dbus-auth.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-auth.c Authentication
00003  *
00004  * Copyright (C) 2002, 2003, 2004 Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "dbus-auth.h"
00024 #include "dbus-string.h"
00025 #include "dbus-list.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-keyring.h"
00028 #include "dbus-sha.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-credentials.h"
00031 
00068 typedef dbus_bool_t (* DBusInitialResponseFunction)  (DBusAuth         *auth,
00069                                                       DBusString       *response);
00070 
00075 typedef dbus_bool_t (* DBusAuthDataFunction)     (DBusAuth         *auth,
00076                                                   const DBusString *data);
00077 
00081 typedef dbus_bool_t (* DBusAuthEncodeFunction)   (DBusAuth         *auth,
00082                                                   const DBusString *data,
00083                                                   DBusString       *encoded);
00084 
00088 typedef dbus_bool_t (* DBusAuthDecodeFunction)   (DBusAuth         *auth,
00089                                                   const DBusString *data,
00090                                                   DBusString       *decoded);
00091 
00095 typedef void        (* DBusAuthShutdownFunction) (DBusAuth       *auth);
00096 
00100 typedef struct
00101 {
00102   const char *mechanism; 
00103   DBusAuthDataFunction server_data_func; 
00104   DBusAuthEncodeFunction server_encode_func; 
00105   DBusAuthDecodeFunction server_decode_func; 
00106   DBusAuthShutdownFunction server_shutdown_func; 
00107   DBusInitialResponseFunction client_initial_response_func; 
00108   DBusAuthDataFunction client_data_func; 
00109   DBusAuthEncodeFunction client_encode_func; 
00110   DBusAuthDecodeFunction client_decode_func; 
00111   DBusAuthShutdownFunction client_shutdown_func; 
00112 } DBusAuthMechanismHandler;
00113 
00117 typedef enum {
00118   DBUS_AUTH_COMMAND_AUTH,
00119   DBUS_AUTH_COMMAND_CANCEL,
00120   DBUS_AUTH_COMMAND_DATA,
00121   DBUS_AUTH_COMMAND_BEGIN,
00122   DBUS_AUTH_COMMAND_REJECTED,
00123   DBUS_AUTH_COMMAND_OK,
00124   DBUS_AUTH_COMMAND_ERROR,
00125   DBUS_AUTH_COMMAND_UNKNOWN
00126 } DBusAuthCommand;
00127 
00133 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth         *auth,
00134                                                DBusAuthCommand   command,
00135                                                const DBusString *args);
00136 
00140 typedef struct
00141 {
00142   const char *name;               
00143   DBusAuthStateFunction handler;  
00144 } DBusAuthStateData;
00145 
00149 struct DBusAuth
00150 {
00151   int refcount;           
00152   const char *side;       
00154   DBusString incoming;    
00155   DBusString outgoing;    
00157   const DBusAuthStateData *state;         
00159   const DBusAuthMechanismHandler *mech;   
00161   DBusString identity;                   
00165   DBusCredentials *credentials;          
00168   DBusCredentials *authorized_identity; 
00170   DBusCredentials *desired_identity;    
00172   DBusString context;               
00173   DBusKeyring *keyring;             
00174   int cookie_id;                    
00175   DBusString challenge;             
00177   char **allowed_mechs;             
00181   unsigned int needed_memory : 1;   
00184   unsigned int already_got_mechanisms : 1;       
00185   unsigned int already_asked_for_initial_response : 1; 
00186   unsigned int buffer_outstanding : 1; 
00187 };
00188 
00192 typedef struct
00193 {
00194   DBusAuth base;    
00196   DBusList *mechs_to_try; 
00198   DBusString guid_from_server; 
00200 } DBusAuthClient;
00201 
00205 typedef struct
00206 {
00207   DBusAuth base;    
00209   int failures;     
00210   int max_failures; 
00212   DBusString guid;  
00214 } DBusAuthServer;
00215 
00216 static void        goto_state                (DBusAuth                       *auth,
00217                                               const DBusAuthStateData        *new_state);
00218 static dbus_bool_t send_auth                 (DBusAuth *auth,
00219                                               const DBusAuthMechanismHandler *mech);
00220 static dbus_bool_t send_data                 (DBusAuth *auth,
00221                                               DBusString *data);
00222 static dbus_bool_t send_rejected             (DBusAuth *auth);
00223 static dbus_bool_t send_error                (DBusAuth *auth,
00224                                               const char *message);
00225 static dbus_bool_t send_ok                   (DBusAuth *auth);
00226 static dbus_bool_t send_begin                (DBusAuth *auth,
00227                                               const DBusString *args_from_ok);
00228 static dbus_bool_t send_cancel               (DBusAuth *auth);
00229 
00234 static dbus_bool_t handle_server_state_waiting_for_auth  (DBusAuth         *auth,
00235                                                           DBusAuthCommand   command,
00236                                                           const DBusString *args);
00237 static dbus_bool_t handle_server_state_waiting_for_data  (DBusAuth         *auth,
00238                                                           DBusAuthCommand   command,
00239                                                           const DBusString *args);
00240 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth         *auth,
00241                                                           DBusAuthCommand   command,
00242                                                           const DBusString *args);
00243   
00244 static const DBusAuthStateData server_state_waiting_for_auth = {
00245   "WaitingForAuth", handle_server_state_waiting_for_auth
00246 };
00247 static const DBusAuthStateData server_state_waiting_for_data = {
00248   "WaitingForData", handle_server_state_waiting_for_data
00249 };
00250 static const DBusAuthStateData server_state_waiting_for_begin = {
00251   "WaitingForBegin", handle_server_state_waiting_for_begin
00252 };
00253   
00258 static dbus_bool_t handle_client_state_waiting_for_data   (DBusAuth         *auth,
00259                                                            DBusAuthCommand   command,
00260                                                            const DBusString *args);
00261 static dbus_bool_t handle_client_state_waiting_for_ok     (DBusAuth         *auth,
00262                                                            DBusAuthCommand   command,
00263                                                            const DBusString *args);
00264 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth         *auth,
00265                                                            DBusAuthCommand   command,
00266                                                            const DBusString *args);
00267 
00268 static const DBusAuthStateData client_state_need_send_auth = {
00269   "NeedSendAuth", NULL
00270 };
00271 static const DBusAuthStateData client_state_waiting_for_data = {
00272   "WaitingForData", handle_client_state_waiting_for_data
00273 };
00274 static const DBusAuthStateData client_state_waiting_for_ok = {
00275   "WaitingForOK", handle_client_state_waiting_for_ok
00276 };
00277 static const DBusAuthStateData client_state_waiting_for_reject = {
00278   "WaitingForReject", handle_client_state_waiting_for_reject
00279 };
00280   
00285 static const DBusAuthStateData common_state_authenticated = {
00286   "Authenticated",  NULL
00287 };
00288 
00289 static const DBusAuthStateData common_state_need_disconnect = {
00290   "NeedDisconnect",  NULL
00291 };
00292 
00293 static const char auth_side_client[] = "client";
00294 static const char auth_side_server[] = "server";
00299 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00300 
00304 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00305 
00309 #define DBUS_AUTH_CLIENT(auth)    ((DBusAuthClient*)(auth))
00310 
00314 #define DBUS_AUTH_SERVER(auth)    ((DBusAuthServer*)(auth))
00315 
00321 #define DBUS_AUTH_NAME(auth)      ((auth)->side)
00322 
00323 static DBusAuth*
00324 _dbus_auth_new (int size)
00325 {
00326   DBusAuth *auth;
00327   
00328   auth = dbus_malloc0 (size);
00329   if (auth == NULL)
00330     return NULL;
00331   
00332   auth->refcount = 1;
00333   
00334   auth->keyring = NULL;
00335   auth->cookie_id = -1;
00336   
00337   /* note that we don't use the max string length feature,
00338    * because you can't use that feature if you're going to
00339    * try to recover from out-of-memory (it creates
00340    * what looks like unrecoverable inability to alloc
00341    * more space in the string). But we do handle
00342    * overlong buffers in _dbus_auth_do_work().
00343    */
00344   
00345   if (!_dbus_string_init (&auth->incoming))
00346     goto enomem_0;
00347 
00348   if (!_dbus_string_init (&auth->outgoing))
00349     goto enomem_1;
00350     
00351   if (!_dbus_string_init (&auth->identity))
00352     goto enomem_2;
00353 
00354   if (!_dbus_string_init (&auth->context))
00355     goto enomem_3;
00356 
00357   if (!_dbus_string_init (&auth->challenge))
00358     goto enomem_4;
00359 
00360   /* default context if none is specified */
00361   if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
00362     goto enomem_5;
00363 
00364   auth->credentials = _dbus_credentials_new ();
00365   if (auth->credentials == NULL)
00366     goto enomem_6;
00367   
00368   auth->authorized_identity = _dbus_credentials_new ();
00369   if (auth->authorized_identity == NULL)
00370     goto enomem_7;
00371 
00372   auth->desired_identity = _dbus_credentials_new ();
00373   if (auth->desired_identity == NULL)
00374     goto enomem_8;
00375   
00376   return auth;
00377 
00378 #if 0
00379  enomem_9:
00380   _dbus_credentials_unref (auth->desired_identity);
00381 #endif
00382  enomem_8:
00383   _dbus_credentials_unref (auth->authorized_identity);
00384  enomem_7:
00385   _dbus_credentials_unref (auth->credentials);
00386  enomem_6:
00387  /* last alloc was an append to context, which is freed already below */ ;
00388  enomem_5:
00389   _dbus_string_free (&auth->challenge);
00390  enomem_4:
00391   _dbus_string_free (&auth->context);
00392  enomem_3:
00393   _dbus_string_free (&auth->identity);
00394  enomem_2:
00395   _dbus_string_free (&auth->outgoing);
00396  enomem_1:
00397   _dbus_string_free (&auth->incoming);
00398  enomem_0:
00399   dbus_free (auth);
00400   return NULL;
00401 }
00402 
00403 static void
00404 shutdown_mech (DBusAuth *auth)
00405 {
00406   /* Cancel any auth */
00407   auth->already_asked_for_initial_response = FALSE;
00408   _dbus_string_set_length (&auth->identity, 0);
00409 
00410   _dbus_credentials_clear (auth->authorized_identity);
00411   _dbus_credentials_clear (auth->desired_identity);
00412   
00413   if (auth->mech != NULL)
00414     {
00415       _dbus_verbose ("%s: Shutting down mechanism %s\n",
00416                      DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00417       
00418       if (DBUS_AUTH_IS_CLIENT (auth))
00419         (* auth->mech->client_shutdown_func) (auth);
00420       else
00421         (* auth->mech->server_shutdown_func) (auth);
00422       
00423       auth->mech = NULL;
00424     }
00425 }
00426 
00427 /*
00428  * DBUS_COOKIE_SHA1 mechanism
00429  */
00430 
00431 /* Returns TRUE but with an empty string hash if the
00432  * cookie_id isn't known. As with all this code
00433  * TRUE just means we had enough memory.
00434  */
00435 static dbus_bool_t
00436 sha1_compute_hash (DBusAuth         *auth,
00437                    int               cookie_id,
00438                    const DBusString *server_challenge,
00439                    const DBusString *client_challenge,
00440                    DBusString       *hash)
00441 {
00442   DBusString cookie;
00443   DBusString to_hash;
00444   dbus_bool_t retval;
00445   
00446   _dbus_assert (auth->keyring != NULL);
00447 
00448   retval = FALSE;
00449   
00450   if (!_dbus_string_init (&cookie))
00451     return FALSE;
00452 
00453   if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
00454                                   &cookie))
00455     goto out_0;
00456 
00457   if (_dbus_string_get_length (&cookie) == 0)
00458     {
00459       retval = TRUE;
00460       goto out_0;
00461     }
00462 
00463   if (!_dbus_string_init (&to_hash))
00464     goto out_0;
00465   
00466   if (!_dbus_string_copy (server_challenge, 0,
00467                           &to_hash, _dbus_string_get_length (&to_hash)))
00468     goto out_1;
00469 
00470   if (!_dbus_string_append (&to_hash, ":"))
00471     goto out_1;
00472   
00473   if (!_dbus_string_copy (client_challenge, 0,
00474                           &to_hash, _dbus_string_get_length (&to_hash)))
00475     goto out_1;
00476 
00477   if (!_dbus_string_append (&to_hash, ":"))
00478     goto out_1;
00479 
00480   if (!_dbus_string_copy (&cookie, 0,
00481                           &to_hash, _dbus_string_get_length (&to_hash)))
00482     goto out_1;
00483 
00484   if (!_dbus_sha_compute (&to_hash, hash))
00485     goto out_1;
00486   
00487   retval = TRUE;
00488 
00489  out_1:
00490   _dbus_string_zero (&to_hash);
00491   _dbus_string_free (&to_hash);
00492  out_0:
00493   _dbus_string_zero (&cookie);
00494   _dbus_string_free (&cookie);
00495   return retval;
00496 }
00497 
00502 #define N_CHALLENGE_BYTES (128/8)
00503 
00504 static dbus_bool_t
00505 sha1_handle_first_client_response (DBusAuth         *auth,
00506                                    const DBusString *data)
00507 {
00508   /* We haven't sent a challenge yet, we're expecting a desired
00509    * username from the client.
00510    */
00511   DBusString tmp;
00512   DBusString tmp2;
00513   dbus_bool_t retval;
00514   DBusError error;
00515   
00516   retval = FALSE;
00517 
00518   _dbus_string_set_length (&auth->challenge, 0);
00519   
00520   if (_dbus_string_get_length (data) > 0)
00521     {
00522       if (_dbus_string_get_length (&auth->identity) > 0)
00523         {
00524           /* Tried to send two auth identities, wtf */
00525           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00526                          DBUS_AUTH_NAME (auth));
00527           return send_rejected (auth);
00528         }
00529       else
00530         {
00531           /* this is our auth identity */
00532           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00533             return FALSE;
00534         }
00535     }
00536       
00537   if (!_dbus_credentials_add_from_user (auth->desired_identity, data))
00538     {
00539       _dbus_verbose ("%s: Did not get a valid username from client\n",
00540                      DBUS_AUTH_NAME (auth));
00541       return send_rejected (auth);
00542     }
00543       
00544   if (!_dbus_string_init (&tmp))
00545     return FALSE;
00546 
00547   if (!_dbus_string_init (&tmp2))
00548     {
00549       _dbus_string_free (&tmp);
00550       return FALSE;
00551     }
00552 
00553   /* we cache the keyring for speed, so here we drop it if it's the
00554    * wrong one. FIXME caching the keyring here is useless since we use
00555    * a different DBusAuth for every connection.
00556    */
00557   if (auth->keyring &&
00558       !_dbus_keyring_is_for_credentials (auth->keyring,
00559                                          auth->desired_identity))
00560     {
00561       _dbus_keyring_unref (auth->keyring);
00562       auth->keyring = NULL;
00563     }
00564   
00565   if (auth->keyring == NULL)
00566     {
00567       dbus_error_init (&error);
00568       auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity,
00569                                                          &auth->context,
00570                                                          &error);
00571 
00572       if (auth->keyring == NULL)
00573         {
00574           if (dbus_error_has_name (&error,
00575                                    DBUS_ERROR_NO_MEMORY))
00576             {
00577               dbus_error_free (&error);
00578               goto out;
00579             }
00580           else
00581             {
00582               _DBUS_ASSERT_ERROR_IS_SET (&error);
00583               _dbus_verbose ("%s: Error loading keyring: %s\n",
00584                              DBUS_AUTH_NAME (auth), error.message);
00585               if (send_rejected (auth))
00586                 retval = TRUE; /* retval is only about mem */
00587               dbus_error_free (&error);
00588               goto out;
00589             }
00590         }
00591       else
00592         {
00593           _dbus_assert (!dbus_error_is_set (&error));
00594         }
00595     }
00596 
00597   _dbus_assert (auth->keyring != NULL);
00598 
00599   dbus_error_init (&error);
00600   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00601   if (auth->cookie_id < 0)
00602     {
00603       _DBUS_ASSERT_ERROR_IS_SET (&error);
00604       _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00605                      DBUS_AUTH_NAME (auth), error.message);
00606       if (send_rejected (auth))
00607         retval = TRUE;
00608       dbus_error_free (&error);
00609       goto out;
00610     }
00611   else
00612     {
00613       _dbus_assert (!dbus_error_is_set (&error));
00614     }
00615 
00616   if (!_dbus_string_copy (&auth->context, 0,
00617                           &tmp2, _dbus_string_get_length (&tmp2)))
00618     goto out;
00619 
00620   if (!_dbus_string_append (&tmp2, " "))
00621     goto out;
00622 
00623   if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00624     goto out;
00625 
00626   if (!_dbus_string_append (&tmp2, " "))
00627     goto out;  
00628   
00629   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00630     goto out;
00631 
00632   _dbus_string_set_length (&auth->challenge, 0);
00633   if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00634     goto out;
00635   
00636   if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00637                                 _dbus_string_get_length (&tmp2)))
00638     goto out;
00639 
00640   if (!send_data (auth, &tmp2))
00641     goto out;
00642       
00643   goto_state (auth, &server_state_waiting_for_data);
00644   retval = TRUE;
00645   
00646  out:
00647   _dbus_string_zero (&tmp);
00648   _dbus_string_free (&tmp);
00649   _dbus_string_zero (&tmp2);
00650   _dbus_string_free (&tmp2);
00651 
00652   return retval;
00653 }
00654 
00655 static dbus_bool_t
00656 sha1_handle_second_client_response (DBusAuth         *auth,
00657                                     const DBusString *data)
00658 {
00659   /* We are expecting a response which is the hex-encoded client
00660    * challenge, space, then SHA-1 hash of the concatenation of our
00661    * challenge, ":", client challenge, ":", secret key, all
00662    * hex-encoded.
00663    */
00664   int i;
00665   DBusString client_challenge;
00666   DBusString client_hash;
00667   dbus_bool_t retval;
00668   DBusString correct_hash;
00669   
00670   retval = FALSE;
00671   
00672   if (!_dbus_string_find_blank (data, 0, &i))
00673     {
00674       _dbus_verbose ("%s: no space separator in client response\n",
00675                      DBUS_AUTH_NAME (auth));
00676       return send_rejected (auth);
00677     }
00678   
00679   if (!_dbus_string_init (&client_challenge))
00680     goto out_0;
00681 
00682   if (!_dbus_string_init (&client_hash))
00683     goto out_1;  
00684 
00685   if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00686                               0))
00687     goto out_2;
00688 
00689   _dbus_string_skip_blank (data, i, &i);
00690   
00691   if (!_dbus_string_copy_len (data, i,
00692                               _dbus_string_get_length (data) - i,
00693                               &client_hash,
00694                               0))
00695     goto out_2;
00696 
00697   if (_dbus_string_get_length (&client_challenge) == 0 ||
00698       _dbus_string_get_length (&client_hash) == 0)
00699     {
00700       _dbus_verbose ("%s: zero-length client challenge or hash\n",
00701                      DBUS_AUTH_NAME (auth));
00702       if (send_rejected (auth))
00703         retval = TRUE;
00704       goto out_2;
00705     }
00706 
00707   if (!_dbus_string_init (&correct_hash))
00708     goto out_2;
00709 
00710   if (!sha1_compute_hash (auth, auth->cookie_id,
00711                           &auth->challenge, 
00712                           &client_challenge,
00713                           &correct_hash))
00714     goto out_3;
00715 
00716   /* if cookie_id was invalid, then we get an empty hash */
00717   if (_dbus_string_get_length (&correct_hash) == 0)
00718     {
00719       if (send_rejected (auth))
00720         retval = TRUE;
00721       goto out_3;
00722     }
00723   
00724   if (!_dbus_string_equal (&client_hash, &correct_hash))
00725     {
00726       if (send_rejected (auth))
00727         retval = TRUE;
00728       goto out_3;
00729     }
00730 
00731   if (!_dbus_credentials_add_credentials (auth->authorized_identity,
00732                                           auth->desired_identity))
00733     goto out_3;
00734 
00735   /* Copy process ID from the socket credentials if it's there
00736    */
00737   if (!_dbus_credentials_add_credential (auth->authorized_identity,
00738                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
00739                                          auth->credentials))
00740     goto out_3;
00741   
00742   if (!send_ok (auth))
00743     goto out_3;
00744 
00745   _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n",
00746                  DBUS_AUTH_NAME (auth));
00747   
00748   retval = TRUE;
00749   
00750  out_3:
00751   _dbus_string_zero (&correct_hash);
00752   _dbus_string_free (&correct_hash);
00753  out_2:
00754   _dbus_string_zero (&client_hash);
00755   _dbus_string_free (&client_hash);
00756  out_1:
00757   _dbus_string_free (&client_challenge);
00758  out_0:
00759   return retval;
00760 }
00761 
00762 static dbus_bool_t
00763 handle_server_data_cookie_sha1_mech (DBusAuth         *auth,
00764                                      const DBusString *data)
00765 {
00766   if (auth->cookie_id < 0)
00767     return sha1_handle_first_client_response (auth, data);
00768   else
00769     return sha1_handle_second_client_response (auth, data);
00770 }
00771 
00772 static void
00773 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00774 {
00775   auth->cookie_id = -1;  
00776   _dbus_string_set_length (&auth->challenge, 0);
00777 }
00778 
00779 static dbus_bool_t
00780 handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
00781                                                  DBusString *response)
00782 {
00783   DBusString username;
00784   dbus_bool_t retval;
00785 
00786   retval = FALSE;
00787 
00788   if (!_dbus_string_init (&username))
00789     return FALSE;
00790   
00791   if (!_dbus_append_user_from_current_process (&username))
00792     goto out_0;
00793 
00794   if (!_dbus_string_hex_encode (&username, 0,
00795                                 response,
00796                                 _dbus_string_get_length (response)))
00797     goto out_0;
00798 
00799   retval = TRUE;
00800   
00801  out_0:
00802   _dbus_string_free (&username);
00803   
00804   return retval;
00805 }
00806 
00807 static dbus_bool_t
00808 handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
00809                                      const DBusString *data)
00810 {
00811   /* The data we get from the server should be the cookie context
00812    * name, the cookie ID, and the server challenge, separated by
00813    * spaces. We send back our challenge string and the correct hash.
00814    */
00815   dbus_bool_t retval;
00816   DBusString context;
00817   DBusString cookie_id_str;
00818   DBusString server_challenge;
00819   DBusString client_challenge;
00820   DBusString correct_hash;
00821   DBusString tmp;
00822   int i, j;
00823   long val;
00824   
00825   retval = FALSE;                 
00826   
00827   if (!_dbus_string_find_blank (data, 0, &i))
00828     {
00829       if (send_error (auth,
00830                       "Server did not send context/ID/challenge properly"))
00831         retval = TRUE;
00832       goto out_0;
00833     }
00834 
00835   if (!_dbus_string_init (&context))
00836     goto out_0;
00837 
00838   if (!_dbus_string_copy_len (data, 0, i,
00839                               &context, 0))
00840     goto out_1;
00841   
00842   _dbus_string_skip_blank (data, i, &i);
00843   if (!_dbus_string_find_blank (data, i, &j))
00844     {
00845       if (send_error (auth,
00846                       "Server did not send context/ID/challenge properly"))
00847         retval = TRUE;
00848       goto out_1;
00849     }
00850 
00851   if (!_dbus_string_init (&cookie_id_str))
00852     goto out_1;
00853   
00854   if (!_dbus_string_copy_len (data, i, j - i,
00855                               &cookie_id_str, 0))
00856     goto out_2;  
00857 
00858   if (!_dbus_string_init (&server_challenge))
00859     goto out_2;
00860 
00861   i = j;
00862   _dbus_string_skip_blank (data, i, &i);
00863   j = _dbus_string_get_length (data);
00864 
00865   if (!_dbus_string_copy_len (data, i, j - i,
00866                               &server_challenge, 0))
00867     goto out_3;
00868 
00869   if (!_dbus_keyring_validate_context (&context))
00870     {
00871       if (send_error (auth, "Server sent invalid cookie context"))
00872         retval = TRUE;
00873       goto out_3;
00874     }
00875 
00876   if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00877     {
00878       if (send_error (auth, "Could not parse cookie ID as an integer"))
00879         retval = TRUE;
00880       goto out_3;
00881     }
00882 
00883   if (_dbus_string_get_length (&server_challenge) == 0)
00884     {
00885       if (send_error (auth, "Empty server challenge string"))
00886         retval = TRUE;
00887       goto out_3;
00888     }
00889 
00890   if (auth->keyring == NULL)
00891     {
00892       DBusError error;
00893 
00894       dbus_error_init (&error);
00895       auth->keyring = _dbus_keyring_new_for_credentials (NULL,
00896                                                          &context,
00897                                                          &error);
00898 
00899       if (auth->keyring == NULL)
00900         {
00901           if (dbus_error_has_name (&error,
00902                                    DBUS_ERROR_NO_MEMORY))
00903             {
00904               dbus_error_free (&error);
00905               goto out_3;
00906             }
00907           else
00908             {
00909               _DBUS_ASSERT_ERROR_IS_SET (&error);
00910 
00911               _dbus_verbose ("%s: Error loading keyring: %s\n",
00912                              DBUS_AUTH_NAME (auth), error.message);
00913               
00914               if (send_error (auth, "Could not load cookie file"))
00915                 retval = TRUE; /* retval is only about mem */
00916               
00917               dbus_error_free (&error);
00918               goto out_3;
00919             }
00920         }
00921       else
00922         {
00923           _dbus_assert (!dbus_error_is_set (&error));
00924         }
00925     }
00926   
00927   _dbus_assert (auth->keyring != NULL);
00928   
00929   if (!_dbus_string_init (&tmp))
00930     goto out_3;
00931   
00932   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00933     goto out_4;
00934 
00935   if (!_dbus_string_init (&client_challenge))
00936     goto out_4;
00937 
00938   if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00939     goto out_5;
00940 
00941   if (!_dbus_string_init (&correct_hash))
00942     goto out_5;
00943   
00944   if (!sha1_compute_hash (auth, val,
00945                           &server_challenge,
00946                           &client_challenge,
00947                           &correct_hash))
00948     goto out_6;
00949 
00950   if (_dbus_string_get_length (&correct_hash) == 0)
00951     {
00952       /* couldn't find the cookie ID or something */
00953       if (send_error (auth, "Don't have the requested cookie ID"))
00954         retval = TRUE;
00955       goto out_6;
00956     }
00957   
00958   _dbus_string_set_length (&tmp, 0);
00959   
00960   if (!_dbus_string_copy (&client_challenge, 0, &tmp,
00961                           _dbus_string_get_length (&tmp)))
00962     goto out_6;
00963 
00964   if (!_dbus_string_append (&tmp, " "))
00965     goto out_6;
00966 
00967   if (!_dbus_string_copy (&correct_hash, 0, &tmp,
00968                           _dbus_string_get_length (&tmp)))
00969     goto out_6;
00970 
00971   if (!send_data (auth, &tmp))
00972     goto out_6;
00973 
00974   retval = TRUE;
00975 
00976  out_6:
00977   _dbus_string_zero (&correct_hash);
00978   _dbus_string_free (&correct_hash);
00979  out_5:
00980   _dbus_string_free (&client_challenge);
00981  out_4:
00982   _dbus_string_zero (&tmp);
00983   _dbus_string_free (&tmp);
00984  out_3:
00985   _dbus_string_free (&server_challenge);
00986  out_2:
00987   _dbus_string_free (&cookie_id_str);
00988  out_1:
00989   _dbus_string_free (&context);
00990  out_0:
00991   return retval;
00992 }
00993 
00994 static void
00995 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
00996 {
00997   auth->cookie_id = -1;  
00998   _dbus_string_set_length (&auth->challenge, 0);
00999 }
01000 
01001 /*
01002  * EXTERNAL mechanism
01003  */
01004 
01005 static dbus_bool_t
01006 handle_server_data_external_mech (DBusAuth         *auth,
01007                                   const DBusString *data)
01008 {
01009   if (_dbus_credentials_are_anonymous (auth->credentials))
01010     {
01011       _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
01012                      DBUS_AUTH_NAME (auth));
01013       return send_rejected (auth);
01014     }
01015   
01016   if (_dbus_string_get_length (data) > 0)
01017     {
01018       if (_dbus_string_get_length (&auth->identity) > 0)
01019         {
01020           /* Tried to send two auth identities, wtf */
01021           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
01022                          DBUS_AUTH_NAME (auth));
01023           return send_rejected (auth);
01024         }
01025       else
01026         {
01027           /* this is our auth identity */
01028           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
01029             return FALSE;
01030         }
01031     }
01032 
01033   /* Poke client for an auth identity, if none given */
01034   if (_dbus_string_get_length (&auth->identity) == 0 &&
01035       !auth->already_asked_for_initial_response)
01036     {
01037       if (send_data (auth, NULL))
01038         {
01039           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01040                          DBUS_AUTH_NAME (auth));
01041           auth->already_asked_for_initial_response = TRUE;
01042           goto_state (auth, &server_state_waiting_for_data);
01043           return TRUE;
01044         }
01045       else
01046         return FALSE;
01047     }
01048 
01049   _dbus_credentials_clear (auth->desired_identity);
01050   
01051   /* If auth->identity is still empty here, then client
01052    * responded with an empty string after we poked it for
01053    * an initial response. This means to try to auth the
01054    * identity provided in the credentials.
01055    */
01056   if (_dbus_string_get_length (&auth->identity) == 0)
01057     {
01058       if (!_dbus_credentials_add_credentials (auth->desired_identity,
01059                                               auth->credentials))
01060         {
01061           return FALSE; /* OOM */
01062         }
01063     }
01064   else
01065     {
01066       if (!_dbus_credentials_add_from_user (auth->desired_identity,
01067                                             &auth->identity))
01068         {
01069           _dbus_verbose ("%s: could not get credentials from uid string\n",
01070                          DBUS_AUTH_NAME (auth));
01071           return send_rejected (auth);
01072         }
01073     }
01074 
01075   if (_dbus_credentials_are_anonymous (auth->desired_identity))
01076     {
01077       _dbus_verbose ("%s: desired user %s is no good\n",
01078                      DBUS_AUTH_NAME (auth),
01079                      _dbus_string_get_const_data (&auth->identity));
01080       return send_rejected (auth);
01081     }
01082   
01083   if (_dbus_credentials_are_superset (auth->credentials,
01084                                       auth->desired_identity))
01085     {
01086       /* client has authenticated */
01087       if (!_dbus_credentials_add_credentials (auth->authorized_identity,
01088                                               auth->desired_identity))
01089         return FALSE;
01090 
01091       /* also copy process ID from the socket credentials
01092        */
01093       if (!_dbus_credentials_add_credential (auth->authorized_identity,
01094                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01095                                              auth->credentials))
01096         return FALSE;
01097       
01098       if (!send_ok (auth))
01099         return FALSE;
01100 
01101       _dbus_verbose ("%s: authenticated client based on socket credentials\n",
01102                      DBUS_AUTH_NAME (auth));
01103 
01104       return TRUE;
01105     }
01106   else
01107     {
01108       _dbus_verbose ("%s: desired identity not found in socket credentials\n",
01109                      DBUS_AUTH_NAME (auth));
01110       return send_rejected (auth);
01111     }
01112 }
01113 
01114 static void
01115 handle_server_shutdown_external_mech (DBusAuth *auth)
01116 {
01117 
01118 }
01119 
01120 static dbus_bool_t
01121 handle_client_initial_response_external_mech (DBusAuth         *auth,
01122                                               DBusString       *response)
01123 {
01124   /* We always append our UID as an initial response, so the server
01125    * doesn't have to send back an empty challenge to check whether we
01126    * want to specify an identity. i.e. this avoids a round trip that
01127    * the spec for the EXTERNAL mechanism otherwise requires.
01128    */
01129   DBusString plaintext;
01130 
01131   if (!_dbus_string_init (&plaintext))
01132     return FALSE;
01133 
01134   if (!_dbus_append_user_from_current_process (&plaintext))
01135     goto failed;
01136 
01137   if (!_dbus_string_hex_encode (&plaintext, 0,
01138                                 response,
01139                                 _dbus_string_get_length (response)))
01140     goto failed;
01141 
01142   _dbus_string_free (&plaintext);
01143   
01144   return TRUE;
01145 
01146  failed:
01147   _dbus_string_free (&plaintext);
01148   return FALSE;  
01149 }
01150 
01151 static dbus_bool_t
01152 handle_client_data_external_mech (DBusAuth         *auth,
01153                                   const DBusString *data)
01154 {
01155   
01156   return TRUE;
01157 }
01158 
01159 static void
01160 handle_client_shutdown_external_mech (DBusAuth *auth)
01161 {
01162 
01163 }
01164 
01165 /*
01166  * ANONYMOUS mechanism
01167  */
01168 
01169 static dbus_bool_t
01170 handle_server_data_anonymous_mech (DBusAuth         *auth,
01171                                    const DBusString *data)
01172 {  
01173   if (_dbus_string_get_length (data) > 0)
01174     {
01175       /* Client is allowed to send "trace" data, the only defined
01176        * meaning is that if it contains '@' it is an email address,
01177        * and otherwise it is anything else, and it's supposed to be
01178        * UTF-8
01179        */
01180       if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
01181         {
01182           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
01183                          DBUS_AUTH_NAME (auth));
01184 
01185           {
01186             DBusString plaintext;
01187             DBusString encoded;
01188             _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
01189             _dbus_string_init (&encoded);
01190             _dbus_string_hex_encode (&plaintext, 0,
01191                                      &encoded,
01192                                      0);
01193               _dbus_verbose ("%s: try '%s'\n",
01194                              DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
01195           }
01196           return send_rejected (auth);
01197         }
01198       
01199       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
01200                      DBUS_AUTH_NAME (auth),
01201                      _dbus_string_get_const_data (data));
01202     }
01203 
01204   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
01205   _dbus_credentials_clear (auth->desired_identity);
01206 
01207   /* Copy process ID from the socket credentials
01208    */
01209   if (!_dbus_credentials_add_credential (auth->authorized_identity,
01210                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01211                                          auth->credentials))
01212     return FALSE;
01213   
01214   /* Anonymous is always allowed */
01215   if (!send_ok (auth))
01216     return FALSE;
01217 
01218   _dbus_verbose ("%s: authenticated client as anonymous\n",
01219                  DBUS_AUTH_NAME (auth));
01220 
01221   return TRUE;
01222 }
01223 
01224 static void
01225 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
01226 {
01227   
01228 }
01229 
01230 static dbus_bool_t
01231 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
01232                                                DBusString       *response)
01233 {
01234   /* Our initial response is a "trace" string which must be valid UTF-8
01235    * and must be an email address if it contains '@'.
01236    * We just send the dbus implementation info, like a user-agent or
01237    * something, because... why not. There's nothing guaranteed here
01238    * though, we could change it later.
01239    */
01240   DBusString plaintext;
01241 
01242   if (!_dbus_string_init (&plaintext))
01243     return FALSE;
01244 
01245   if (!_dbus_string_append (&plaintext,
01246                             "libdbus " VERSION))
01247     goto failed;
01248 
01249   if (!_dbus_string_hex_encode (&plaintext, 0,
01250                                 response,
01251                                 _dbus_string_get_length (response)))
01252     goto failed;
01253 
01254   _dbus_string_free (&plaintext);
01255   
01256   return TRUE;
01257 
01258  failed:
01259   _dbus_string_free (&plaintext);
01260   return FALSE;  
01261 }
01262 
01263 static dbus_bool_t
01264 handle_client_data_anonymous_mech (DBusAuth         *auth,
01265                                   const DBusString *data)
01266 {
01267   
01268   return TRUE;
01269 }
01270 
01271 static void
01272 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
01273 {
01274   
01275 }
01276 
01277 /* Put mechanisms here in order of preference.
01278  * Right now we have:
01279  *
01280  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
01281  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
01282  * - ANONYMOUS checks nothing but doesn't auth the person as a user
01283  *
01284  * We might ideally add a mechanism to chain to Cyrus SASL so we can
01285  * use its mechanisms as well.
01286  * 
01287  */
01288 static const DBusAuthMechanismHandler
01289 all_mechanisms[] = {
01290   { "EXTERNAL",
01291     handle_server_data_external_mech,
01292     NULL, NULL,
01293     handle_server_shutdown_external_mech,
01294     handle_client_initial_response_external_mech,
01295     handle_client_data_external_mech,
01296     NULL, NULL,
01297     handle_client_shutdown_external_mech },
01298   { "DBUS_COOKIE_SHA1",
01299     handle_server_data_cookie_sha1_mech,
01300     NULL, NULL,
01301     handle_server_shutdown_cookie_sha1_mech,
01302     handle_client_initial_response_cookie_sha1_mech,
01303     handle_client_data_cookie_sha1_mech,
01304     NULL, NULL,
01305     handle_client_shutdown_cookie_sha1_mech },
01306   { "ANONYMOUS",
01307     handle_server_data_anonymous_mech,
01308     NULL, NULL,
01309     handle_server_shutdown_anonymous_mech,
01310     handle_client_initial_response_anonymous_mech,
01311     handle_client_data_anonymous_mech,
01312     NULL, NULL,
01313     handle_client_shutdown_anonymous_mech },  
01314   { NULL, NULL }
01315 };
01316 
01317 static const DBusAuthMechanismHandler*
01318 find_mech (const DBusString  *name,
01319            char             **allowed_mechs)
01320 {
01321   int i;
01322   
01323   if (allowed_mechs != NULL &&
01324       !_dbus_string_array_contains ((const char**) allowed_mechs,
01325                                     _dbus_string_get_const_data (name)))
01326     return NULL;
01327   
01328   i = 0;
01329   while (all_mechanisms[i].mechanism != NULL)
01330     {      
01331       if (_dbus_string_equal_c_str (name,
01332                                     all_mechanisms[i].mechanism))
01333 
01334         return &all_mechanisms[i];
01335       
01336       ++i;
01337     }
01338   
01339   return NULL;
01340 }
01341 
01342 static dbus_bool_t
01343 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01344 {
01345   DBusString auth_command;
01346 
01347   if (!_dbus_string_init (&auth_command))
01348     return FALSE;
01349       
01350   if (!_dbus_string_append (&auth_command,
01351                             "AUTH "))
01352     {
01353       _dbus_string_free (&auth_command);
01354       return FALSE;
01355     }  
01356   
01357   if (!_dbus_string_append (&auth_command,
01358                             mech->mechanism))
01359     {
01360       _dbus_string_free (&auth_command);
01361       return FALSE;
01362     }
01363 
01364   if (mech->client_initial_response_func != NULL)
01365     {
01366       if (!_dbus_string_append (&auth_command, " "))
01367         {
01368           _dbus_string_free (&auth_command);
01369           return FALSE;
01370         }
01371       
01372       if (!(* mech->client_initial_response_func) (auth, &auth_command))
01373         {
01374           _dbus_string_free (&auth_command);
01375           return FALSE;
01376         }
01377     }
01378   
01379   if (!_dbus_string_append (&auth_command,
01380                             "\r\n"))
01381     {
01382       _dbus_string_free (&auth_command);
01383       return FALSE;
01384     }
01385 
01386   if (!_dbus_string_copy (&auth_command, 0,
01387                           &auth->outgoing,
01388                           _dbus_string_get_length (&auth->outgoing)))
01389     {
01390       _dbus_string_free (&auth_command);
01391       return FALSE;
01392     }
01393 
01394   _dbus_string_free (&auth_command);
01395   shutdown_mech (auth);
01396   auth->mech = mech;      
01397   goto_state (auth, &client_state_waiting_for_data);
01398 
01399   return TRUE;
01400 }
01401 
01402 static dbus_bool_t
01403 send_data (DBusAuth *auth, DBusString *data)
01404 {
01405   int old_len;
01406 
01407   if (data == NULL || _dbus_string_get_length (data) == 0)
01408     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01409   else
01410     {
01411       old_len = _dbus_string_get_length (&auth->outgoing);
01412       if (!_dbus_string_append (&auth->outgoing, "DATA "))
01413         goto out;
01414 
01415       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01416                                     _dbus_string_get_length (&auth->outgoing)))
01417         goto out;
01418 
01419       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01420         goto out;
01421 
01422       return TRUE;
01423 
01424     out:
01425       _dbus_string_set_length (&auth->outgoing, old_len);
01426 
01427       return FALSE;
01428     }
01429 }
01430 
01431 static dbus_bool_t
01432 send_rejected (DBusAuth *auth)
01433 {
01434   DBusString command;
01435   DBusAuthServer *server_auth;
01436   int i;
01437   
01438   if (!_dbus_string_init (&command))
01439     return FALSE;
01440   
01441   if (!_dbus_string_append (&command,
01442                             "REJECTED"))
01443     goto nomem;
01444 
01445   i = 0;
01446   while (all_mechanisms[i].mechanism != NULL)
01447     {
01448       if (!_dbus_string_append (&command,
01449                                 " "))
01450         goto nomem;
01451 
01452       if (!_dbus_string_append (&command,
01453                                 all_mechanisms[i].mechanism))
01454         goto nomem;
01455       
01456       ++i;
01457     }
01458   
01459   if (!_dbus_string_append (&command, "\r\n"))
01460     goto nomem;
01461 
01462   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01463                           _dbus_string_get_length (&auth->outgoing)))
01464     goto nomem;
01465 
01466   shutdown_mech (auth);
01467   
01468   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01469   server_auth = DBUS_AUTH_SERVER (auth);
01470   server_auth->failures += 1;
01471 
01472   if (server_auth->failures >= server_auth->max_failures)
01473     goto_state (auth, &common_state_need_disconnect);
01474   else
01475     goto_state (auth, &server_state_waiting_for_auth);
01476 
01477   _dbus_string_free (&command);
01478   
01479   return TRUE;
01480 
01481  nomem:
01482   _dbus_string_free (&command);
01483   return FALSE;
01484 }
01485 
01486 static dbus_bool_t
01487 send_error (DBusAuth *auth, const char *message)
01488 {
01489   return _dbus_string_append_printf (&auth->outgoing,
01490                                      "ERROR \"%s\"\r\n", message);
01491 }
01492 
01493 static dbus_bool_t
01494 send_ok (DBusAuth *auth)
01495 {
01496   int orig_len;
01497 
01498   orig_len = _dbus_string_get_length (&auth->outgoing);
01499   
01500   if (_dbus_string_append (&auth->outgoing, "OK ") &&
01501       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01502                          0,
01503                          &auth->outgoing,
01504                          _dbus_string_get_length (&auth->outgoing)) &&
01505       _dbus_string_append (&auth->outgoing, "\r\n"))
01506     {
01507       goto_state (auth, &server_state_waiting_for_begin);
01508       return TRUE;
01509     }
01510   else
01511     {
01512       _dbus_string_set_length (&auth->outgoing, orig_len);
01513       return FALSE;
01514     }
01515 }
01516 
01517 static dbus_bool_t
01518 send_begin (DBusAuth         *auth,
01519             const DBusString *args_from_ok)
01520 {
01521   int end_of_hex;
01522   
01523   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
01524   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01525 
01526   /* We decode the hex string to binary, using guid_from_server as scratch... */
01527   
01528   end_of_hex = 0;
01529   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01530                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01531     return FALSE;
01532 
01533   /* now clear out the scratch */
01534   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01535   
01536   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01537       end_of_hex == 0)
01538     {
01539       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01540                      end_of_hex, _dbus_string_get_length (args_from_ok));
01541       goto_state (auth, &common_state_need_disconnect);
01542       return TRUE;
01543     }
01544 
01545   if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01546       _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01547     {
01548       _dbus_verbose ("Got GUID '%s' from the server\n",
01549                      _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01550       
01551       goto_state (auth, &common_state_authenticated);
01552       return TRUE;
01553     }
01554   else
01555     {
01556       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01557       return FALSE;
01558     }
01559 }
01560 
01561 static dbus_bool_t
01562 send_cancel (DBusAuth *auth)
01563 {
01564   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01565     {
01566       goto_state (auth, &client_state_waiting_for_reject);
01567       return TRUE;
01568     }
01569   else
01570     return FALSE;
01571 }
01572 
01573 static dbus_bool_t
01574 process_data (DBusAuth             *auth,
01575               const DBusString     *args,
01576               DBusAuthDataFunction  data_func)
01577 {
01578   int end;
01579   DBusString decoded;
01580 
01581   if (!_dbus_string_init (&decoded))
01582     return FALSE;
01583 
01584   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01585     {
01586       _dbus_string_free (&decoded);
01587       return FALSE;
01588     }
01589 
01590   if (_dbus_string_get_length (args) != end)
01591     {
01592       _dbus_string_free (&decoded);
01593       if (!send_error (auth, "Invalid hex encoding"))
01594         return FALSE;
01595 
01596       return TRUE;
01597     }
01598 
01599 #ifdef DBUS_ENABLE_VERBOSE_MODE
01600   if (_dbus_string_validate_ascii (&decoded, 0,
01601                                    _dbus_string_get_length (&decoded)))
01602     _dbus_verbose ("%s: data: '%s'\n",
01603                    DBUS_AUTH_NAME (auth),
01604                    _dbus_string_get_const_data (&decoded));
01605 #endif
01606       
01607   if (!(* data_func) (auth, &decoded))
01608     {
01609       _dbus_string_free (&decoded);
01610       return FALSE;
01611     }
01612 
01613   _dbus_string_free (&decoded);
01614   return TRUE;
01615 }
01616 
01617 static dbus_bool_t
01618 handle_auth (DBusAuth *auth, const DBusString *args)
01619 {
01620   if (_dbus_string_get_length (args) == 0)
01621     {
01622       /* No args to the auth, send mechanisms */
01623       if (!send_rejected (auth))
01624         return FALSE;
01625 
01626       return TRUE;
01627     }
01628   else
01629     {
01630       int i;
01631       DBusString mech;
01632       DBusString hex_response;
01633       
01634       _dbus_string_find_blank (args, 0, &i);
01635 
01636       if (!_dbus_string_init (&mech))
01637         return FALSE;
01638 
01639       if (!_dbus_string_init (&hex_response))
01640         {
01641           _dbus_string_free (&mech);
01642           return FALSE;
01643         }
01644       
01645       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01646         goto failed;
01647 
01648       _dbus_string_skip_blank (args, i, &i);
01649       if (!_dbus_string_copy (args, i, &hex_response, 0))
01650         goto failed;
01651      
01652       auth->mech = find_mech (&mech, auth->allowed_mechs);
01653       if (auth->mech != NULL)
01654         {
01655           _dbus_verbose ("%s: Trying mechanism %s\n",
01656                          DBUS_AUTH_NAME (auth),
01657                          auth->mech->mechanism);
01658           
01659           if (!process_data (auth, &hex_response,
01660                              auth->mech->server_data_func))
01661             goto failed;
01662         }
01663       else
01664         {
01665           /* Unsupported mechanism */
01666           _dbus_verbose ("%s: Unsupported mechanism %s\n",
01667                          DBUS_AUTH_NAME (auth),
01668                          _dbus_string_get_const_data (&mech));
01669           
01670           if (!send_rejected (auth))
01671             goto failed;
01672         }
01673 
01674       _dbus_string_free (&mech);      
01675       _dbus_string_free (&hex_response);
01676 
01677       return TRUE;
01678       
01679     failed:
01680       auth->mech = NULL;
01681       _dbus_string_free (&mech);
01682       _dbus_string_free (&hex_response);
01683       return FALSE;
01684     }
01685 }
01686 
01687 static dbus_bool_t
01688 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
01689                                        DBusAuthCommand   command,
01690                                        const DBusString *args)
01691 {
01692   switch (command)
01693     {
01694     case DBUS_AUTH_COMMAND_AUTH:
01695       return handle_auth (auth, args);
01696 
01697     case DBUS_AUTH_COMMAND_CANCEL:
01698     case DBUS_AUTH_COMMAND_DATA:
01699       return send_error (auth, "Not currently in an auth conversation");
01700 
01701     case DBUS_AUTH_COMMAND_BEGIN:
01702       goto_state (auth, &common_state_need_disconnect);
01703       return TRUE;
01704 
01705     case DBUS_AUTH_COMMAND_ERROR:
01706       return send_rejected (auth);
01707 
01708     case DBUS_AUTH_COMMAND_REJECTED:
01709     case DBUS_AUTH_COMMAND_OK:
01710     case DBUS_AUTH_COMMAND_UNKNOWN:
01711     default:
01712       return send_error (auth, "Unknown command");
01713     }
01714 }
01715 
01716 static dbus_bool_t
01717 handle_server_state_waiting_for_data  (DBusAuth         *auth,
01718                                        DBusAuthCommand   command,
01719                                        const DBusString *args)
01720 {
01721   switch (command)
01722     {
01723     case DBUS_AUTH_COMMAND_AUTH:
01724       return send_error (auth, "Sent AUTH while another AUTH in progress");
01725 
01726     case DBUS_AUTH_COMMAND_CANCEL:
01727     case DBUS_AUTH_COMMAND_ERROR:
01728       return send_rejected (auth);
01729 
01730     case DBUS_AUTH_COMMAND_DATA:
01731       return process_data (auth, args, auth->mech->server_data_func);
01732 
01733     case DBUS_AUTH_COMMAND_BEGIN:
01734       goto_state (auth, &common_state_need_disconnect);
01735       return TRUE;
01736 
01737     case DBUS_AUTH_COMMAND_REJECTED:
01738     case DBUS_AUTH_COMMAND_OK:
01739     case DBUS_AUTH_COMMAND_UNKNOWN:
01740     default:
01741       return send_error (auth, "Unknown command");
01742     }
01743 }
01744 
01745 static dbus_bool_t
01746 handle_server_state_waiting_for_begin (DBusAuth         *auth,
01747                                        DBusAuthCommand   command,
01748                                        const DBusString *args)
01749 {
01750   switch (command)
01751     {
01752     case DBUS_AUTH_COMMAND_AUTH:
01753       return send_error (auth, "Sent AUTH while expecting BEGIN");
01754 
01755     case DBUS_AUTH_COMMAND_DATA:
01756       return send_error (auth, "Sent DATA while expecting BEGIN");
01757 
01758     case DBUS_AUTH_COMMAND_BEGIN:
01759       goto_state (auth, &common_state_authenticated);
01760       return TRUE;
01761 
01762     case DBUS_AUTH_COMMAND_REJECTED:
01763     case DBUS_AUTH_COMMAND_OK:
01764     case DBUS_AUTH_COMMAND_UNKNOWN:
01765     default:
01766       return send_error (auth, "Unknown command");
01767 
01768     case DBUS_AUTH_COMMAND_CANCEL:
01769     case DBUS_AUTH_COMMAND_ERROR:
01770       return send_rejected (auth);
01771     }
01772 }
01773 
01774 /* return FALSE if no memory, TRUE if all OK */
01775 static dbus_bool_t
01776 get_word (const DBusString *str,
01777           int              *start,
01778           DBusString       *word)
01779 {
01780   int i;
01781 
01782   _dbus_string_skip_blank (str, *start, start);
01783   _dbus_string_find_blank (str, *start, &i);
01784   
01785   if (i > *start)
01786     {
01787       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01788         return FALSE;
01789       
01790       *start = i;
01791     }
01792 
01793   return TRUE;
01794 }
01795 
01796 static dbus_bool_t
01797 record_mechanisms (DBusAuth         *auth,
01798                    const DBusString *args)
01799 {
01800   int next;
01801   int len;
01802 
01803   if (auth->already_got_mechanisms)
01804     return TRUE;
01805   
01806   len = _dbus_string_get_length (args);
01807   
01808   next = 0;
01809   while (next < len)
01810     {
01811       DBusString m;
01812       const DBusAuthMechanismHandler *mech;
01813       
01814       if (!_dbus_string_init (&m))
01815         goto nomem;
01816       
01817       if (!get_word (args, &next, &m))
01818         {
01819           _dbus_string_free (&m);
01820           goto nomem;
01821         }
01822 
01823       mech = find_mech (&m, auth->allowed_mechs);
01824 
01825       if (mech != NULL)
01826         {
01827           /* FIXME right now we try mechanisms in the order
01828            * the server lists them; should we do them in
01829            * some more deterministic order?
01830            *
01831            * Probably in all_mechanisms order, our order of
01832            * preference. Of course when the server is us,
01833            * it lists things in that order anyhow.
01834            */
01835 
01836           if (mech != &all_mechanisms[0])
01837             {
01838               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01839                              DBUS_AUTH_NAME (auth), mech->mechanism);
01840           
01841               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01842                                       (void*) mech))
01843                 {
01844                   _dbus_string_free (&m);
01845                   goto nomem;
01846                 }
01847             }
01848           else
01849             {
01850               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
01851                              DBUS_AUTH_NAME (auth), mech->mechanism);
01852             }
01853         }
01854       else
01855         {
01856           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01857                          DBUS_AUTH_NAME (auth),
01858                          _dbus_string_get_const_data (&m));
01859         }
01860 
01861       _dbus_string_free (&m);
01862     }
01863   
01864   auth->already_got_mechanisms = TRUE;
01865   
01866   return TRUE;
01867 
01868  nomem:
01869   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01870   
01871   return FALSE;
01872 }
01873 
01874 static dbus_bool_t
01875 process_rejected (DBusAuth *auth, const DBusString *args)
01876 {
01877   const DBusAuthMechanismHandler *mech;
01878   DBusAuthClient *client;
01879 
01880   client = DBUS_AUTH_CLIENT (auth);
01881 
01882   if (!auth->already_got_mechanisms)
01883     {
01884       if (!record_mechanisms (auth, args))
01885         return FALSE;
01886     }
01887   
01888   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01889     {
01890       mech = client->mechs_to_try->data;
01891 
01892       if (!send_auth (auth, mech))
01893         return FALSE;
01894 
01895       _dbus_list_pop_first (&client->mechs_to_try);
01896 
01897       _dbus_verbose ("%s: Trying mechanism %s\n",
01898                      DBUS_AUTH_NAME (auth),
01899                      mech->mechanism);
01900     }
01901   else
01902     {
01903       /* Give up */
01904       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01905                      DBUS_AUTH_NAME (auth));
01906       goto_state (auth, &common_state_need_disconnect);
01907     }
01908   
01909   return TRUE;
01910 }
01911 
01912 
01913 static dbus_bool_t
01914 handle_client_state_waiting_for_data (DBusAuth         *auth,
01915                                       DBusAuthCommand   command,
01916                                       const DBusString *args)
01917 {
01918   _dbus_assert (auth->mech != NULL);
01919  
01920   switch (command)
01921     {
01922     case DBUS_AUTH_COMMAND_DATA:
01923       return process_data (auth, args, auth->mech->client_data_func);
01924 
01925     case DBUS_AUTH_COMMAND_REJECTED:
01926       return process_rejected (auth, args);
01927 
01928     case DBUS_AUTH_COMMAND_OK:
01929       return send_begin (auth, args);
01930 
01931     case DBUS_AUTH_COMMAND_ERROR:
01932       return send_cancel (auth);
01933 
01934     case DBUS_AUTH_COMMAND_AUTH:
01935     case DBUS_AUTH_COMMAND_CANCEL:
01936     case DBUS_AUTH_COMMAND_BEGIN:
01937     case DBUS_AUTH_COMMAND_UNKNOWN:
01938     default:
01939       return send_error (auth, "Unknown command");
01940     }
01941 }
01942 
01943 static dbus_bool_t
01944 handle_client_state_waiting_for_ok (DBusAuth         *auth,
01945                                     DBusAuthCommand   command,
01946                                     const DBusString *args)
01947 {
01948   switch (command)
01949     {
01950     case DBUS_AUTH_COMMAND_REJECTED:
01951       return process_rejected (auth, args);
01952 
01953     case DBUS_AUTH_COMMAND_OK:
01954       return send_begin (auth, args);
01955 
01956     case DBUS_AUTH_COMMAND_DATA:
01957     case DBUS_AUTH_COMMAND_ERROR:
01958       return send_cancel (auth);
01959 
01960     case DBUS_AUTH_COMMAND_AUTH:
01961     case DBUS_AUTH_COMMAND_CANCEL:
01962     case DBUS_AUTH_COMMAND_BEGIN:
01963     case DBUS_AUTH_COMMAND_UNKNOWN:
01964     default:
01965       return send_error (auth, "Unknown command");
01966     }
01967 }
01968 
01969 static dbus_bool_t
01970 handle_client_state_waiting_for_reject (DBusAuth         *auth,
01971                                         DBusAuthCommand   command,
01972                                         const DBusString *args)
01973 {
01974   switch (command)
01975     {
01976     case DBUS_AUTH_COMMAND_REJECTED:
01977       return process_rejected (auth, args);
01978       
01979     case DBUS_AUTH_COMMAND_AUTH:
01980     case DBUS_AUTH_COMMAND_CANCEL:
01981     case DBUS_AUTH_COMMAND_DATA:
01982     case DBUS_AUTH_COMMAND_BEGIN:
01983     case DBUS_AUTH_COMMAND_OK:
01984     case DBUS_AUTH_COMMAND_ERROR:
01985     case DBUS_AUTH_COMMAND_UNKNOWN:
01986     default:
01987       goto_state (auth, &common_state_need_disconnect);
01988       return TRUE;
01989     }
01990 }
01991 
01995 typedef struct {
01996   const char *name;        
01997   DBusAuthCommand command; 
01998 } DBusAuthCommandName;
01999 
02000 static const DBusAuthCommandName auth_command_names[] = {
02001   { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
02002   { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
02003   { "DATA",     DBUS_AUTH_COMMAND_DATA },
02004   { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
02005   { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
02006   { "OK",       DBUS_AUTH_COMMAND_OK },
02007   { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
02008 };
02009 
02010 static DBusAuthCommand
02011 lookup_command_from_name (DBusString *command)
02012 {
02013   int i;
02014 
02015   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
02016     {
02017       if (_dbus_string_equal_c_str (command,
02018                                     auth_command_names[i].name))
02019         return auth_command_names[i].command;
02020     }
02021 
02022   return DBUS_AUTH_COMMAND_UNKNOWN;
02023 }
02024 
02025 static void
02026 goto_state (DBusAuth *auth,
02027             const DBusAuthStateData *state)
02028 {
02029   _dbus_verbose ("%s: going from state %s to state %s\n",
02030                  DBUS_AUTH_NAME (auth),
02031                  auth->state->name,
02032                  state->name);
02033 
02034   auth->state = state;
02035 }
02036 
02037 /* returns whether to call it again right away */
02038 static dbus_bool_t
02039 process_command (DBusAuth *auth)
02040 {
02041   DBusAuthCommand command;
02042   DBusString line;
02043   DBusString args;
02044   int eol;
02045   int i, j;
02046   dbus_bool_t retval;
02047 
02048   /* _dbus_verbose ("%s:   trying process_command()\n"); */
02049   
02050   retval = FALSE;
02051   
02052   eol = 0;
02053   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
02054     return FALSE;
02055   
02056   if (!_dbus_string_init (&line))
02057     {
02058       auth->needed_memory = TRUE;
02059       return FALSE;
02060     }
02061 
02062   if (!_dbus_string_init (&args))
02063     {
02064       _dbus_string_free (&line);
02065       auth->needed_memory = TRUE;
02066       return FALSE;
02067     }
02068   
02069   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
02070     goto out;
02071 
02072   if (!_dbus_string_validate_ascii (&line, 0,
02073                                     _dbus_string_get_length (&line)))
02074     {
02075       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
02076                      DBUS_AUTH_NAME (auth));
02077       if (!send_error (auth, "Command contained non-ASCII"))
02078         goto out;
02079       else
02080         goto next_command;
02081     }
02082   
02083   _dbus_verbose ("%s: got command \"%s\"\n",
02084                  DBUS_AUTH_NAME (auth),
02085                  _dbus_string_get_const_data (&line));
02086   
02087   _dbus_string_find_blank (&line, 0, &i);
02088   _dbus_string_skip_blank (&line, i, &j);
02089 
02090   if (j > i)
02091     _dbus_string_delete (&line, i, j - i);
02092   
02093   if (!_dbus_string_move (&line, i, &args, 0))
02094     goto out;
02095 
02096   /* FIXME 1.0 we should probably validate that only the allowed
02097    * chars are in the command name
02098    */
02099   
02100   command = lookup_command_from_name (&line);
02101   if (!(* auth->state->handler) (auth, command, &args))
02102     goto out;
02103 
02104  next_command:
02105   
02106   /* We've succeeded in processing the whole command so drop it out
02107    * of the incoming buffer and return TRUE to try another command.
02108    */
02109 
02110   _dbus_string_delete (&auth->incoming, 0, eol);
02111   
02112   /* kill the \r\n */
02113   _dbus_string_delete (&auth->incoming, 0, 2);
02114 
02115   retval = TRUE;
02116   
02117  out:
02118   _dbus_string_free (&args);
02119   _dbus_string_free (&line);
02120 
02121   if (!retval)
02122     auth->needed_memory = TRUE;
02123   else
02124     auth->needed_memory = FALSE;
02125   
02126   return retval;
02127 }
02128 
02129 
02144 DBusAuth*
02145 _dbus_auth_server_new (const DBusString *guid)
02146 {
02147   DBusAuth *auth;
02148   DBusAuthServer *server_auth;
02149   DBusString guid_copy;
02150 
02151   if (!_dbus_string_init (&guid_copy))
02152     return NULL;
02153 
02154   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
02155     {
02156       _dbus_string_free (&guid_copy);
02157       return NULL;
02158     }
02159 
02160   auth = _dbus_auth_new (sizeof (DBusAuthServer));
02161   if (auth == NULL)
02162     {
02163       _dbus_string_free (&guid_copy);
02164       return NULL;
02165     }
02166   
02167   auth->side = auth_side_server;
02168   auth->state = &server_state_waiting_for_auth;
02169 
02170   server_auth = DBUS_AUTH_SERVER (auth);
02171 
02172   server_auth->guid = guid_copy;
02173   
02174   /* perhaps this should be per-mechanism with a lower
02175    * max
02176    */
02177   server_auth->failures = 0;
02178   server_auth->max_failures = 6;
02179   
02180   return auth;
02181 }
02182 
02190 DBusAuth*
02191 _dbus_auth_client_new (void)
02192 {
02193   DBusAuth *auth;
02194   DBusString guid_str;
02195 
02196   if (!_dbus_string_init (&guid_str))
02197     return NULL;
02198 
02199   auth = _dbus_auth_new (sizeof (DBusAuthClient));
02200   if (auth == NULL)
02201     {
02202       _dbus_string_free (&guid_str);
02203       return NULL;
02204     }
02205 
02206   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02207 
02208   auth->side = auth_side_client;
02209   auth->state = &client_state_need_send_auth;
02210 
02211   /* Start the auth conversation by sending AUTH for our default
02212    * mechanism */
02213   if (!send_auth (auth, &all_mechanisms[0]))
02214     {
02215       _dbus_auth_unref (auth);
02216       return NULL;
02217     }
02218   
02219   return auth;
02220 }
02221 
02228 DBusAuth *
02229 _dbus_auth_ref (DBusAuth *auth)
02230 {
02231   _dbus_assert (auth != NULL);
02232   
02233   auth->refcount += 1;
02234   
02235   return auth;
02236 }
02237 
02243 void
02244 _dbus_auth_unref (DBusAuth *auth)
02245 {
02246   _dbus_assert (auth != NULL);
02247   _dbus_assert (auth->refcount > 0);
02248 
02249   auth->refcount -= 1;
02250   if (auth->refcount == 0)
02251     {
02252       shutdown_mech (auth);
02253 
02254       if (DBUS_AUTH_IS_CLIENT (auth))
02255         {
02256           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02257           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02258         }
02259       else
02260         {
02261           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02262 
02263           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02264         }
02265 
02266       if (auth->keyring)
02267         _dbus_keyring_unref (auth->keyring);
02268 
02269       _dbus_string_free (&auth->context);
02270       _dbus_string_free (&auth->challenge);
02271       _dbus_string_free (&auth->identity);
02272       _dbus_string_free (&auth->incoming);
02273       _dbus_string_free (&auth->outgoing);
02274 
02275       dbus_free_string_array (auth->allowed_mechs);
02276 
02277       _dbus_credentials_unref (auth->credentials);
02278       _dbus_credentials_unref (auth->authorized_identity);
02279       _dbus_credentials_unref (auth->desired_identity);
02280       
02281       dbus_free (auth);
02282     }
02283 }
02284 
02293 dbus_bool_t
02294 _dbus_auth_set_mechanisms (DBusAuth    *auth,
02295                            const char **mechanisms)
02296 {
02297   char **copy;
02298 
02299   if (mechanisms != NULL)
02300     {
02301       copy = _dbus_dup_string_array (mechanisms);
02302       if (copy == NULL)
02303         return FALSE;
02304     }
02305   else
02306     copy = NULL;
02307   
02308   dbus_free_string_array (auth->allowed_mechs);
02309 
02310   auth->allowed_mechs = copy;
02311 
02312   return TRUE;
02313 }
02314 
02319 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02320 
02328 DBusAuthState
02329 _dbus_auth_do_work (DBusAuth *auth)
02330 {
02331   auth->needed_memory = FALSE;
02332 
02333   /* Max amount we'll buffer up before deciding someone's on crack */
02334 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02335 
02336   do
02337     {
02338       if (DBUS_AUTH_IN_END_STATE (auth))
02339         break;
02340       
02341       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02342           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02343         {
02344           goto_state (auth, &common_state_need_disconnect);
02345           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02346                          DBUS_AUTH_NAME (auth));
02347           break;
02348         }
02349     }
02350   while (process_command (auth));
02351 
02352   if (auth->needed_memory)
02353     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02354   else if (_dbus_string_get_length (&auth->outgoing) > 0)
02355     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02356   else if (auth->state == &common_state_need_disconnect)
02357     return DBUS_AUTH_STATE_NEED_DISCONNECT;
02358   else if (auth->state == &common_state_authenticated)
02359     return DBUS_AUTH_STATE_AUTHENTICATED;
02360   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02361 }
02362 
02372 dbus_bool_t
02373 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
02374                               const DBusString **str)
02375 {
02376   _dbus_assert (auth != NULL);
02377   _dbus_assert (str != NULL);
02378 
02379   *str = NULL;
02380   
02381   if (_dbus_string_get_length (&auth->outgoing) == 0)
02382     return FALSE;
02383 
02384   *str = &auth->outgoing;
02385 
02386   return TRUE;
02387 }
02388 
02397 void
02398 _dbus_auth_bytes_sent (DBusAuth *auth,
02399                        int       bytes_sent)
02400 {
02401   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02402                  DBUS_AUTH_NAME (auth),
02403                  bytes_sent,
02404                  _dbus_string_get_const_data (&auth->outgoing));
02405   
02406   _dbus_string_delete (&auth->outgoing,
02407                        0, bytes_sent);
02408 }
02409 
02417 void
02418 _dbus_auth_get_buffer (DBusAuth     *auth,
02419                        DBusString **buffer)
02420 {
02421   _dbus_assert (auth != NULL);
02422   _dbus_assert (!auth->buffer_outstanding);
02423   
02424   *buffer = &auth->incoming;
02425 
02426   auth->buffer_outstanding = TRUE;
02427 }
02428 
02436 void
02437 _dbus_auth_return_buffer (DBusAuth               *auth,
02438                           DBusString             *buffer,
02439                           int                     bytes_read)
02440 {
02441   _dbus_assert (buffer == &auth->incoming);
02442   _dbus_assert (auth->buffer_outstanding);
02443 
02444   auth->buffer_outstanding = FALSE;
02445 }
02446 
02456 void
02457 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
02458                              const DBusString **str)
02459 {
02460   if (!DBUS_AUTH_IN_END_STATE (auth))
02461     return;
02462 
02463   *str = &auth->incoming;
02464 }
02465 
02466 
02473 void
02474 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02475 {
02476   if (!DBUS_AUTH_IN_END_STATE (auth))
02477     return;
02478 
02479   _dbus_string_set_length (&auth->incoming, 0);
02480 }
02481 
02490 dbus_bool_t
02491 _dbus_auth_needs_encoding (DBusAuth *auth)
02492 {
02493   if (auth->state != &common_state_authenticated)
02494     return FALSE;
02495   
02496   if (auth->mech != NULL)
02497     {
02498       if (DBUS_AUTH_IS_CLIENT (auth))
02499         return auth->mech->client_encode_func != NULL;
02500       else
02501         return auth->mech->server_encode_func != NULL;
02502     }
02503   else
02504     return FALSE;
02505 }
02506 
02517 dbus_bool_t
02518 _dbus_auth_encode_data (DBusAuth         *auth,
02519                         const DBusString *plaintext,
02520                         DBusString       *encoded)
02521 {
02522   _dbus_assert (plaintext != encoded);
02523   
02524   if (auth->state != &common_state_authenticated)
02525     return FALSE;
02526   
02527   if (_dbus_auth_needs_encoding (auth))
02528     {
02529       if (DBUS_AUTH_IS_CLIENT (auth))
02530         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02531       else
02532         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02533     }
02534   else
02535     {
02536       return _dbus_string_copy (plaintext, 0, encoded,
02537                                 _dbus_string_get_length (encoded));
02538     }
02539 }
02540 
02549 dbus_bool_t
02550 _dbus_auth_needs_decoding (DBusAuth *auth)
02551 {
02552   if (auth->state != &common_state_authenticated)
02553     return FALSE;
02554     
02555   if (auth->mech != NULL)
02556     {
02557       if (DBUS_AUTH_IS_CLIENT (auth))
02558         return auth->mech->client_decode_func != NULL;
02559       else
02560         return auth->mech->server_decode_func != NULL;
02561     }
02562   else
02563     return FALSE;
02564 }
02565 
02566 
02580 dbus_bool_t
02581 _dbus_auth_decode_data (DBusAuth         *auth,
02582                         const DBusString *encoded,
02583                         DBusString       *plaintext)
02584 {
02585   _dbus_assert (plaintext != encoded);
02586   
02587   if (auth->state != &common_state_authenticated)
02588     return FALSE;
02589   
02590   if (_dbus_auth_needs_decoding (auth))
02591     {
02592       if (DBUS_AUTH_IS_CLIENT (auth))
02593         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02594       else
02595         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02596     }
02597   else
02598     {
02599       return _dbus_string_copy (encoded, 0, plaintext,
02600                                 _dbus_string_get_length (plaintext));
02601     }
02602 }
02603 
02612 dbus_bool_t
02613 _dbus_auth_set_credentials (DBusAuth               *auth,
02614                             DBusCredentials        *credentials)
02615 {
02616   _dbus_credentials_clear (auth->credentials);
02617   return _dbus_credentials_add_credentials (auth->credentials,
02618                                             credentials);
02619 }
02620 
02630 DBusCredentials*
02631 _dbus_auth_get_identity (DBusAuth               *auth)
02632 {
02633   if (auth->state == &common_state_authenticated)
02634     {
02635       return auth->authorized_identity;
02636     }
02637   else
02638     {
02639       /* FIXME instead of this, keep an empty credential around that
02640        * doesn't require allocation or something
02641        */
02642       /* return empty credentials */
02643       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
02644       return auth->authorized_identity;
02645     }
02646 }
02647 
02654 const char*
02655 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02656 {
02657   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02658   
02659   if (auth->state == &common_state_authenticated)
02660     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02661   else
02662     return NULL;
02663 }
02664 
02673 dbus_bool_t
02674 _dbus_auth_set_context (DBusAuth               *auth,
02675                         const DBusString       *context)
02676 {
02677   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02678                                    &auth->context, 0, _dbus_string_get_length (context));
02679 }
02680 
02683 /* tests in dbus-auth-util.c */

Generated on Sun May 18 18:20:53 2008 for D-Bus by  doxygen 1.5.2