Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

dbus-auth.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
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-userdb.h"
00031 
00072 typedef dbus_bool_t (* DBusInitialResponseFunction)  (DBusAuth         *auth,
00073                                                       DBusString       *response);
00074 
00079 typedef dbus_bool_t (* DBusAuthDataFunction)     (DBusAuth         *auth,
00080                                                   const DBusString *data);
00081 
00085 typedef dbus_bool_t (* DBusAuthEncodeFunction)   (DBusAuth         *auth,
00086                                                   const DBusString *data,
00087                                                   DBusString       *encoded);
00088 
00092 typedef dbus_bool_t (* DBusAuthDecodeFunction)   (DBusAuth         *auth,
00093                                                   const DBusString *data,
00094                                                   DBusString       *decoded);
00095 
00099 typedef void        (* DBusAuthShutdownFunction) (DBusAuth       *auth);
00100 
00104 typedef struct
00105 {
00106   const char *mechanism; 
00107   DBusAuthDataFunction server_data_func; 
00108   DBusAuthEncodeFunction server_encode_func; 
00109   DBusAuthDecodeFunction server_decode_func; 
00110   DBusAuthShutdownFunction server_shutdown_func; 
00111   DBusInitialResponseFunction client_initial_response_func; 
00112   DBusAuthDataFunction client_data_func; 
00113   DBusAuthEncodeFunction client_encode_func; 
00114   DBusAuthDecodeFunction client_decode_func; 
00115   DBusAuthShutdownFunction client_shutdown_func; 
00116 } DBusAuthMechanismHandler;
00117 
00121 typedef enum {
00122   DBUS_AUTH_COMMAND_AUTH,
00123   DBUS_AUTH_COMMAND_CANCEL,
00124   DBUS_AUTH_COMMAND_DATA,
00125   DBUS_AUTH_COMMAND_BEGIN,
00126   DBUS_AUTH_COMMAND_REJECTED,
00127   DBUS_AUTH_COMMAND_OK,
00128   DBUS_AUTH_COMMAND_ERROR,
00129   DBUS_AUTH_COMMAND_UNKNOWN
00130 } DBusAuthCommand;
00131 
00137 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth         *auth,
00138                                                DBusAuthCommand   command,
00139                                                const DBusString *args);
00140 
00144 typedef struct
00145 {
00146   const char *name;               
00147   DBusAuthStateFunction handler;  
00148 } DBusAuthStateData;
00149 
00153 struct DBusAuth
00154 {
00155   int refcount;           
00156   const char *side;       
00158   DBusString incoming;    
00159   DBusString outgoing;    
00161   const DBusAuthStateData *state;         
00163   const DBusAuthMechanismHandler *mech;   
00165   DBusString identity;                   
00169   DBusCredentials credentials;      
00173   DBusCredentials authorized_identity; 
00175   DBusCredentials desired_identity;    
00177   DBusString context;               
00178   DBusKeyring *keyring;             
00179   int cookie_id;                    
00180   DBusString challenge;             
00182   char **allowed_mechs;             
00186   unsigned int needed_memory : 1;   
00189   unsigned int already_got_mechanisms : 1;       
00190   unsigned int already_asked_for_initial_response : 1; 
00191   unsigned int buffer_outstanding : 1; 
00192 };
00193 
00197 typedef struct
00198 {
00199   DBusAuth base;    
00201   DBusList *mechs_to_try; 
00203   DBusString guid_from_server; 
00205 } DBusAuthClient;
00206 
00210 typedef struct
00211 {
00212   DBusAuth base;    
00214   int failures;     
00215   int max_failures; 
00217   DBusString guid;  
00219 } DBusAuthServer;
00220 
00221 static void        goto_state                (DBusAuth                       *auth,
00222                                               const DBusAuthStateData        *new_state);
00223 static dbus_bool_t send_auth                 (DBusAuth *auth,
00224                                               const DBusAuthMechanismHandler *mech);
00225 static dbus_bool_t send_data                 (DBusAuth *auth,
00226                                               DBusString *data);
00227 static dbus_bool_t send_rejected             (DBusAuth *auth);
00228 static dbus_bool_t send_error                (DBusAuth *auth,
00229                                               const char *message);
00230 static dbus_bool_t send_ok                   (DBusAuth *auth);
00231 static dbus_bool_t send_begin                (DBusAuth *auth,
00232                                               const DBusString *args_from_ok);
00233 static dbus_bool_t send_cancel               (DBusAuth *auth);
00234 
00239 static dbus_bool_t handle_server_state_waiting_for_auth  (DBusAuth         *auth,
00240                                                           DBusAuthCommand   command,
00241                                                           const DBusString *args);
00242 static dbus_bool_t handle_server_state_waiting_for_data  (DBusAuth         *auth,
00243                                                           DBusAuthCommand   command,
00244                                                           const DBusString *args);
00245 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth         *auth,
00246                                                           DBusAuthCommand   command,
00247                                                           const DBusString *args);
00248   
00249 static const DBusAuthStateData server_state_waiting_for_auth = {
00250   "WaitingForAuth", handle_server_state_waiting_for_auth
00251 };
00252 static const DBusAuthStateData server_state_waiting_for_data = {
00253   "WaitingForData", handle_server_state_waiting_for_data
00254 };
00255 static const DBusAuthStateData server_state_waiting_for_begin = {
00256   "WaitingForBegin", handle_server_state_waiting_for_begin
00257 };
00258   
00263 static dbus_bool_t handle_client_state_waiting_for_data   (DBusAuth         *auth,
00264                                                            DBusAuthCommand   command,
00265                                                            const DBusString *args);
00266 static dbus_bool_t handle_client_state_waiting_for_ok     (DBusAuth         *auth,
00267                                                            DBusAuthCommand   command,
00268                                                            const DBusString *args);
00269 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth         *auth,
00270                                                            DBusAuthCommand   command,
00271                                                            const DBusString *args);
00272 
00273 static const DBusAuthStateData client_state_need_send_auth = {
00274   "NeedSendAuth", NULL
00275 };
00276 static const DBusAuthStateData client_state_waiting_for_data = {
00277   "WaitingForData", handle_client_state_waiting_for_data
00278 };
00279 static const DBusAuthStateData client_state_waiting_for_ok = {
00280   "WaitingForOK", handle_client_state_waiting_for_ok
00281 };
00282 static const DBusAuthStateData client_state_waiting_for_reject = {
00283   "WaitingForReject", handle_client_state_waiting_for_reject
00284 };
00285   
00290 static const DBusAuthStateData common_state_authenticated = {
00291   "Authenticated",  NULL
00292 };
00293 
00294 static const DBusAuthStateData common_state_need_disconnect = {
00295   "NeedDisconnect",  NULL
00296 };
00297 
00298 static const char auth_side_client[] = "client";
00299 static const char auth_side_server[] = "server";
00304 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00305 
00309 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00310 
00314 #define DBUS_AUTH_CLIENT(auth)    ((DBusAuthClient*)(auth))
00315 
00319 #define DBUS_AUTH_SERVER(auth)    ((DBusAuthServer*)(auth))
00320 
00326 #define DBUS_AUTH_NAME(auth)      ((auth)->side)
00327 
00328 static DBusAuth*
00329 _dbus_auth_new (int size)
00330 {
00331   DBusAuth *auth;
00332   
00333   auth = dbus_malloc0 (size);
00334   if (auth == NULL)
00335     return NULL;
00336   
00337   auth->refcount = 1;
00338 
00339   _dbus_credentials_clear (&auth->credentials);
00340   _dbus_credentials_clear (&auth->authorized_identity);
00341   _dbus_credentials_clear (&auth->desired_identity);
00342   
00343   auth->keyring = NULL;
00344   auth->cookie_id = -1;
00345   
00346   /* note that we don't use the max string length feature,
00347    * because you can't use that feature if you're going to
00348    * try to recover from out-of-memory (it creates
00349    * what looks like unrecoverable inability to alloc
00350    * more space in the string). But we do handle
00351    * overlong buffers in _dbus_auth_do_work().
00352    */
00353   
00354   if (!_dbus_string_init (&auth->incoming))
00355     goto enomem_0;
00356 
00357   if (!_dbus_string_init (&auth->outgoing))
00358     goto enomem_1;
00359     
00360   if (!_dbus_string_init (&auth->identity))
00361     goto enomem_2;
00362 
00363   if (!_dbus_string_init (&auth->context))
00364     goto enomem_3;
00365 
00366   if (!_dbus_string_init (&auth->challenge))
00367     goto enomem_4;
00368 
00369   /* default context if none is specified */
00370   if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
00371     goto enomem_5;
00372   
00373   return auth;
00374 
00375  enomem_5:
00376   _dbus_string_free (&auth->challenge);
00377  enomem_4:
00378   _dbus_string_free (&auth->context);
00379  enomem_3:
00380   _dbus_string_free (&auth->identity);
00381  enomem_2:
00382   _dbus_string_free (&auth->outgoing);
00383  enomem_1:
00384   _dbus_string_free (&auth->incoming);
00385  enomem_0:
00386   dbus_free (auth);
00387   return NULL;
00388 }
00389 
00390 static void
00391 shutdown_mech (DBusAuth *auth)
00392 {
00393   /* Cancel any auth */
00394   auth->already_asked_for_initial_response = FALSE;
00395   _dbus_string_set_length (&auth->identity, 0);
00396 
00397   _dbus_credentials_clear (&auth->authorized_identity);
00398   _dbus_credentials_clear (&auth->desired_identity);
00399   
00400   if (auth->mech != NULL)
00401     {
00402       _dbus_verbose ("%s: Shutting down mechanism %s\n",
00403                      DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00404       
00405       if (DBUS_AUTH_IS_CLIENT (auth))
00406         (* auth->mech->client_shutdown_func) (auth);
00407       else
00408         (* auth->mech->server_shutdown_func) (auth);
00409       
00410       auth->mech = NULL;
00411     }
00412 }
00413 
00414 /* Returns TRUE but with an empty string hash if the
00415  * cookie_id isn't known. As with all this code
00416  * TRUE just means we had enough memory.
00417  */
00418 static dbus_bool_t
00419 sha1_compute_hash (DBusAuth         *auth,
00420                    int               cookie_id,
00421                    const DBusString *server_challenge,
00422                    const DBusString *client_challenge,
00423                    DBusString       *hash)
00424 {
00425   DBusString cookie;
00426   DBusString to_hash;
00427   dbus_bool_t retval;
00428   
00429   _dbus_assert (auth->keyring != NULL);
00430 
00431   retval = FALSE;
00432   
00433   if (!_dbus_string_init (&cookie))
00434     return FALSE;
00435 
00436   if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
00437                                   &cookie))
00438     goto out_0;
00439 
00440   if (_dbus_string_get_length (&cookie) == 0)
00441     {
00442       retval = TRUE;
00443       goto out_0;
00444     }
00445 
00446   if (!_dbus_string_init (&to_hash))
00447     goto out_0;
00448   
00449   if (!_dbus_string_copy (server_challenge, 0,
00450                           &to_hash, _dbus_string_get_length (&to_hash)))
00451     goto out_1;
00452 
00453   if (!_dbus_string_append (&to_hash, ":"))
00454     goto out_1;
00455   
00456   if (!_dbus_string_copy (client_challenge, 0,
00457                           &to_hash, _dbus_string_get_length (&to_hash)))
00458     goto out_1;
00459 
00460   if (!_dbus_string_append (&to_hash, ":"))
00461     goto out_1;
00462 
00463   if (!_dbus_string_copy (&cookie, 0,
00464                           &to_hash, _dbus_string_get_length (&to_hash)))
00465     goto out_1;
00466 
00467   if (!_dbus_sha_compute (&to_hash, hash))
00468     goto out_1;
00469   
00470   retval = TRUE;
00471 
00472  out_1:
00473   _dbus_string_zero (&to_hash);
00474   _dbus_string_free (&to_hash);
00475  out_0:
00476   _dbus_string_zero (&cookie);
00477   _dbus_string_free (&cookie);
00478   return retval;
00479 }
00480 
00485 #define N_CHALLENGE_BYTES (128/8)
00486 
00487 static dbus_bool_t
00488 sha1_handle_first_client_response (DBusAuth         *auth,
00489                                    const DBusString *data)
00490 {
00491   /* We haven't sent a challenge yet, we're expecting a desired
00492    * username from the client.
00493    */
00494   DBusString tmp;
00495   DBusString tmp2;
00496   dbus_bool_t retval;
00497   DBusError error;
00498   
00499   retval = FALSE;
00500 
00501   _dbus_string_set_length (&auth->challenge, 0);
00502   
00503   if (_dbus_string_get_length (data) > 0)
00504     {
00505       if (_dbus_string_get_length (&auth->identity) > 0)
00506         {
00507           /* Tried to send two auth identities, wtf */
00508           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00509                          DBUS_AUTH_NAME (auth));
00510           return send_rejected (auth);
00511         }
00512       else
00513         {
00514           /* this is our auth identity */
00515           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00516             return FALSE;
00517         }
00518     }
00519       
00520   if (!_dbus_credentials_from_username (data, &auth->desired_identity))
00521     {
00522       _dbus_verbose ("%s: Did not get a valid username from client\n",
00523                      DBUS_AUTH_NAME (auth));
00524       return send_rejected (auth);
00525     }
00526       
00527   if (!_dbus_string_init (&tmp))
00528     return FALSE;
00529 
00530   if (!_dbus_string_init (&tmp2))
00531     {
00532       _dbus_string_free (&tmp);
00533       return FALSE;
00534     }
00535 
00536   /* we cache the keyring for speed, so here we drop it if it's the
00537    * wrong one. FIXME caching the keyring here is useless since we use
00538    * a different DBusAuth for every connection.
00539    */
00540   if (auth->keyring &&
00541       !_dbus_keyring_is_for_user (auth->keyring,
00542                                   data))
00543     {
00544       _dbus_keyring_unref (auth->keyring);
00545       auth->keyring = NULL;
00546     }
00547   
00548   if (auth->keyring == NULL)
00549     {
00550       DBusError error;
00551 
00552       dbus_error_init (&error);
00553       auth->keyring = _dbus_keyring_new_homedir (data,
00554                                                  &auth->context,
00555                                                  &error);
00556 
00557       if (auth->keyring == NULL)
00558         {
00559           if (dbus_error_has_name (&error,
00560                                    DBUS_ERROR_NO_MEMORY))
00561             {
00562               dbus_error_free (&error);
00563               goto out;
00564             }
00565           else
00566             {
00567               _DBUS_ASSERT_ERROR_IS_SET (&error);
00568               _dbus_verbose ("%s: Error loading keyring: %s\n",
00569                              DBUS_AUTH_NAME (auth), error.message);
00570               if (send_rejected (auth))
00571                 retval = TRUE; /* retval is only about mem */
00572               dbus_error_free (&error);
00573               goto out;
00574             }
00575         }
00576       else
00577         {
00578           _dbus_assert (!dbus_error_is_set (&error));
00579         }
00580     }
00581 
00582   _dbus_assert (auth->keyring != NULL);
00583 
00584   dbus_error_init (&error);
00585   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00586   if (auth->cookie_id < 0)
00587     {
00588       _DBUS_ASSERT_ERROR_IS_SET (&error);
00589       _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00590                      DBUS_AUTH_NAME (auth), error.message);
00591       if (send_rejected (auth))
00592         retval = TRUE;
00593       dbus_error_free (&error);
00594       goto out;
00595     }
00596   else
00597     {
00598       _dbus_assert (!dbus_error_is_set (&error));
00599     }
00600 
00601   if (!_dbus_string_copy (&auth->context, 0,
00602                           &tmp2, _dbus_string_get_length (&tmp2)))
00603     goto out;
00604 
00605   if (!_dbus_string_append (&tmp2, " "))
00606     goto out;
00607 
00608   if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00609     goto out;
00610 
00611   if (!_dbus_string_append (&tmp2, " "))
00612     goto out;  
00613   
00614   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00615     goto out;
00616 
00617   _dbus_string_set_length (&auth->challenge, 0);
00618   if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00619     goto out;
00620   
00621   if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00622                                 _dbus_string_get_length (&tmp2)))
00623     goto out;
00624 
00625   if (!send_data (auth, &tmp2))
00626     goto out;
00627       
00628   goto_state (auth, &server_state_waiting_for_data);
00629   retval = TRUE;
00630   
00631  out:
00632   _dbus_string_zero (&tmp);
00633   _dbus_string_free (&tmp);
00634   _dbus_string_zero (&tmp2);
00635   _dbus_string_free (&tmp2);
00636 
00637   return retval;
00638 }
00639 
00640 static dbus_bool_t
00641 sha1_handle_second_client_response (DBusAuth         *auth,
00642                                     const DBusString *data)
00643 {
00644   /* We are expecting a response which is the hex-encoded client
00645    * challenge, space, then SHA-1 hash of the concatenation of our
00646    * challenge, ":", client challenge, ":", secret key, all
00647    * hex-encoded.
00648    */
00649   int i;
00650   DBusString client_challenge;
00651   DBusString client_hash;
00652   dbus_bool_t retval;
00653   DBusString correct_hash;
00654   
00655   retval = FALSE;
00656   
00657   if (!_dbus_string_find_blank (data, 0, &i))
00658     {
00659       _dbus_verbose ("%s: no space separator in client response\n",
00660                      DBUS_AUTH_NAME (auth));
00661       return send_rejected (auth);
00662     }
00663   
00664   if (!_dbus_string_init (&client_challenge))
00665     goto out_0;
00666 
00667   if (!_dbus_string_init (&client_hash))
00668     goto out_1;  
00669 
00670   if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00671                               0))
00672     goto out_2;
00673 
00674   _dbus_string_skip_blank (data, i, &i);
00675   
00676   if (!_dbus_string_copy_len (data, i,
00677                               _dbus_string_get_length (data) - i,
00678                               &client_hash,
00679                               0))
00680     goto out_2;
00681 
00682   if (_dbus_string_get_length (&client_challenge) == 0 ||
00683       _dbus_string_get_length (&client_hash) == 0)
00684     {
00685       _dbus_verbose ("%s: zero-length client challenge or hash\n",
00686                      DBUS_AUTH_NAME (auth));
00687       if (send_rejected (auth))
00688         retval = TRUE;
00689       goto out_2;
00690     }
00691 
00692   if (!_dbus_string_init (&correct_hash))
00693     goto out_2;
00694 
00695   if (!sha1_compute_hash (auth, auth->cookie_id,
00696                           &auth->challenge, 
00697                           &client_challenge,
00698                           &correct_hash))
00699     goto out_3;
00700 
00701   /* if cookie_id was invalid, then we get an empty hash */
00702   if (_dbus_string_get_length (&correct_hash) == 0)
00703     {
00704       if (send_rejected (auth))
00705         retval = TRUE;
00706       goto out_3;
00707     }
00708   
00709   if (!_dbus_string_equal (&client_hash, &correct_hash))
00710     {
00711       if (send_rejected (auth))
00712         retval = TRUE;
00713       goto out_3;
00714     }
00715       
00716   if (!send_ok (auth))
00717     goto out_3;
00718 
00719   _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n",
00720                  DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
00721   
00722   auth->authorized_identity = auth->desired_identity;
00723   retval = TRUE;
00724   
00725  out_3:
00726   _dbus_string_zero (&correct_hash);
00727   _dbus_string_free (&correct_hash);
00728  out_2:
00729   _dbus_string_zero (&client_hash);
00730   _dbus_string_free (&client_hash);
00731  out_1:
00732   _dbus_string_free (&client_challenge);
00733  out_0:
00734   return retval;
00735 }
00736 
00737 static dbus_bool_t
00738 handle_server_data_cookie_sha1_mech (DBusAuth         *auth,
00739                                      const DBusString *data)
00740 {
00741   if (auth->cookie_id < 0)
00742     return sha1_handle_first_client_response (auth, data);
00743   else
00744     return sha1_handle_second_client_response (auth, data);
00745 }
00746 
00747 static void
00748 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00749 {
00750   auth->cookie_id = -1;  
00751   _dbus_string_set_length (&auth->challenge, 0);
00752 }
00753 
00754 static dbus_bool_t
00755 handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
00756                                                  DBusString *response)
00757 {
00758   const DBusString *username;
00759   dbus_bool_t retval;
00760 
00761   retval = FALSE;
00762 
00763   if (!_dbus_username_from_current_process (&username))
00764     goto out_0;
00765 
00766   if (!_dbus_string_hex_encode (username, 0,
00767                                 response,
00768                                 _dbus_string_get_length (response)))
00769     goto out_0;
00770 
00771   retval = TRUE;
00772   
00773  out_0:
00774   return retval;
00775 }
00776 
00777 static dbus_bool_t
00778 handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
00779                                      const DBusString *data)
00780 {
00781   /* The data we get from the server should be the cookie context
00782    * name, the cookie ID, and the server challenge, separated by
00783    * spaces. We send back our challenge string and the correct hash.
00784    */
00785   dbus_bool_t retval;
00786   DBusString context;
00787   DBusString cookie_id_str;
00788   DBusString server_challenge;
00789   DBusString client_challenge;
00790   DBusString correct_hash;
00791   DBusString tmp;
00792   int i, j;
00793   long val;
00794   
00795   retval = FALSE;                 
00796   
00797   if (!_dbus_string_find_blank (data, 0, &i))
00798     {
00799       if (send_error (auth,
00800                       "Server did not send context/ID/challenge properly"))
00801         retval = TRUE;
00802       goto out_0;
00803     }
00804 
00805   if (!_dbus_string_init (&context))
00806     goto out_0;
00807 
00808   if (!_dbus_string_copy_len (data, 0, i,
00809                               &context, 0))
00810     goto out_1;
00811   
00812   _dbus_string_skip_blank (data, i, &i);
00813   if (!_dbus_string_find_blank (data, i, &j))
00814     {
00815       if (send_error (auth,
00816                       "Server did not send context/ID/challenge properly"))
00817         retval = TRUE;
00818       goto out_1;
00819     }
00820 
00821   if (!_dbus_string_init (&cookie_id_str))
00822     goto out_1;
00823   
00824   if (!_dbus_string_copy_len (data, i, j - i,
00825                               &cookie_id_str, 0))
00826     goto out_2;  
00827 
00828   if (!_dbus_string_init (&server_challenge))
00829     goto out_2;
00830 
00831   i = j;
00832   _dbus_string_skip_blank (data, i, &i);
00833   j = _dbus_string_get_length (data);
00834 
00835   if (!_dbus_string_copy_len (data, i, j - i,
00836                               &server_challenge, 0))
00837     goto out_3;
00838 
00839   if (!_dbus_keyring_validate_context (&context))
00840     {
00841       if (send_error (auth, "Server sent invalid cookie context"))
00842         retval = TRUE;
00843       goto out_3;
00844     }
00845 
00846   if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00847     {
00848       if (send_error (auth, "Could not parse cookie ID as an integer"))
00849         retval = TRUE;
00850       goto out_3;
00851     }
00852 
00853   if (_dbus_string_get_length (&server_challenge) == 0)
00854     {
00855       if (send_error (auth, "Empty server challenge string"))
00856         retval = TRUE;
00857       goto out_3;
00858     }
00859 
00860   if (auth->keyring == NULL)
00861     {
00862       DBusError error;
00863 
00864       dbus_error_init (&error);
00865       auth->keyring = _dbus_keyring_new_homedir (NULL,
00866                                                  &context,
00867                                                  &error);
00868 
00869       if (auth->keyring == NULL)
00870         {
00871           if (dbus_error_has_name (&error,
00872                                    DBUS_ERROR_NO_MEMORY))
00873             {
00874               dbus_error_free (&error);
00875               goto out_3;
00876             }
00877           else
00878             {
00879               _DBUS_ASSERT_ERROR_IS_SET (&error);
00880 
00881               _dbus_verbose ("%s: Error loading keyring: %s\n",
00882                              DBUS_AUTH_NAME (auth), error.message);
00883               
00884               if (send_error (auth, "Could not load cookie file"))
00885                 retval = TRUE; /* retval is only about mem */
00886               
00887               dbus_error_free (&error);
00888               goto out_3;
00889             }
00890         }
00891       else
00892         {
00893           _dbus_assert (!dbus_error_is_set (&error));
00894         }
00895     }
00896   
00897   _dbus_assert (auth->keyring != NULL);
00898   
00899   if (!_dbus_string_init (&tmp))
00900     goto out_3;
00901   
00902   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00903     goto out_4;
00904 
00905   if (!_dbus_string_init (&client_challenge))
00906     goto out_4;
00907 
00908   if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00909     goto out_5;
00910 
00911   if (!_dbus_string_init (&correct_hash))
00912     goto out_5;
00913   
00914   if (!sha1_compute_hash (auth, val,
00915                           &server_challenge,
00916                           &client_challenge,
00917                           &correct_hash))
00918     goto out_6;
00919 
00920   if (_dbus_string_get_length (&correct_hash) == 0)
00921     {
00922       /* couldn't find the cookie ID or something */
00923       if (send_error (auth, "Don't have the requested cookie ID"))
00924         retval = TRUE;
00925       goto out_6;
00926     }
00927   
00928   _dbus_string_set_length (&tmp, 0);
00929   
00930   if (!_dbus_string_copy (&client_challenge, 0, &tmp,
00931                           _dbus_string_get_length (&tmp)))
00932     goto out_6;
00933 
00934   if (!_dbus_string_append (&tmp, " "))
00935     goto out_6;
00936 
00937   if (!_dbus_string_copy (&correct_hash, 0, &tmp,
00938                           _dbus_string_get_length (&tmp)))
00939     goto out_6;
00940 
00941   if (!send_data (auth, &tmp))
00942     goto out_6;
00943 
00944   retval = TRUE;
00945 
00946  out_6:
00947   _dbus_string_zero (&correct_hash);
00948   _dbus_string_free (&correct_hash);
00949  out_5:
00950   _dbus_string_free (&client_challenge);
00951  out_4:
00952   _dbus_string_zero (&tmp);
00953   _dbus_string_free (&tmp);
00954  out_3:
00955   _dbus_string_free (&server_challenge);
00956  out_2:
00957   _dbus_string_free (&cookie_id_str);
00958  out_1:
00959   _dbus_string_free (&context);
00960  out_0:
00961   return retval;
00962 }
00963 
00964 static void
00965 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
00966 {
00967   auth->cookie_id = -1;  
00968   _dbus_string_set_length (&auth->challenge, 0);
00969 }
00970 
00971 static dbus_bool_t
00972 handle_server_data_external_mech (DBusAuth         *auth,
00973                                   const DBusString *data)
00974 {
00975   if (auth->credentials.uid == DBUS_UID_UNSET)
00976     {
00977       _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
00978                      DBUS_AUTH_NAME (auth));
00979       return send_rejected (auth);
00980     }
00981   
00982   if (_dbus_string_get_length (data) > 0)
00983     {
00984       if (_dbus_string_get_length (&auth->identity) > 0)
00985         {
00986           /* Tried to send two auth identities, wtf */
00987           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00988                          DBUS_AUTH_NAME (auth));
00989           return send_rejected (auth);
00990         }
00991       else
00992         {
00993           /* this is our auth identity */
00994           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00995             return FALSE;
00996         }
00997     }
00998 
00999   /* Poke client for an auth identity, if none given */
01000   if (_dbus_string_get_length (&auth->identity) == 0 &&
01001       !auth->already_asked_for_initial_response)
01002     {
01003       if (send_data (auth, NULL))
01004         {
01005           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01006                          DBUS_AUTH_NAME (auth));
01007           auth->already_asked_for_initial_response = TRUE;
01008           return TRUE;
01009         }
01010       else
01011         return FALSE;
01012     }
01013 
01014   _dbus_credentials_clear (&auth->desired_identity);
01015   
01016   /* If auth->identity is still empty here, then client
01017    * responded with an empty string after we poked it for
01018    * an initial response. This means to try to auth the
01019    * identity provided in the credentials.
01020    */
01021   if (_dbus_string_get_length (&auth->identity) == 0)
01022     {
01023       auth->desired_identity.uid = auth->credentials.uid;
01024     }
01025   else
01026     {
01027       if (!_dbus_parse_uid (&auth->identity,
01028                             &auth->desired_identity.uid))
01029         {
01030           _dbus_verbose ("%s: could not get credentials from uid string\n",
01031                          DBUS_AUTH_NAME (auth));
01032           return send_rejected (auth);
01033         }
01034     }
01035 
01036   if (auth->desired_identity.uid == DBUS_UID_UNSET)
01037     {
01038       _dbus_verbose ("%s: desired user %s is no good\n",
01039                      DBUS_AUTH_NAME (auth),
01040                      _dbus_string_get_const_data (&auth->identity));
01041       return send_rejected (auth);
01042     }
01043   
01044   if (_dbus_credentials_match (&auth->desired_identity,
01045                                &auth->credentials))
01046     {
01047       /* client has authenticated */      
01048       if (!send_ok (auth))
01049         return FALSE;
01050 
01051       _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
01052                      " matching socket credentials UID "DBUS_UID_FORMAT"\n",
01053                      DBUS_AUTH_NAME (auth),
01054                      auth->desired_identity.uid,
01055                      auth->credentials.uid);
01056 
01057       auth->authorized_identity.pid = auth->credentials.pid;
01058       auth->authorized_identity.uid = auth->desired_identity.uid;
01059       return TRUE;
01060     }
01061   else
01062     {
01063       _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
01064                      " gid="DBUS_GID_FORMAT
01065                      " do not allow uid="DBUS_UID_FORMAT
01066                      " gid="DBUS_GID_FORMAT"\n",
01067                      DBUS_AUTH_NAME (auth),
01068                      auth->credentials.uid, auth->credentials.gid,
01069                      auth->desired_identity.uid, auth->desired_identity.gid);
01070       return send_rejected (auth);
01071     }
01072 }
01073 
01074 static void
01075 handle_server_shutdown_external_mech (DBusAuth *auth)
01076 {
01077 
01078 }
01079 
01080 static dbus_bool_t
01081 handle_client_initial_response_external_mech (DBusAuth         *auth,
01082                                               DBusString       *response)
01083 {
01084   /* We always append our UID as an initial response, so the server
01085    * doesn't have to send back an empty challenge to check whether we
01086    * want to specify an identity. i.e. this avoids a round trip that
01087    * the spec for the EXTERNAL mechanism otherwise requires.
01088    */
01089   DBusString plaintext;
01090 
01091   if (!_dbus_string_init (&plaintext))
01092     return FALSE;
01093   
01094   if (!_dbus_string_append_uint (&plaintext,
01095                                  _dbus_getuid ()))
01096     goto failed;
01097 
01098   if (!_dbus_string_hex_encode (&plaintext, 0,
01099                                 response,
01100                                 _dbus_string_get_length (response)))
01101     goto failed;
01102 
01103   _dbus_string_free (&plaintext);
01104   
01105   return TRUE;
01106 
01107  failed:
01108   _dbus_string_free (&plaintext);
01109   return FALSE;  
01110 }
01111 
01112 static dbus_bool_t
01113 handle_client_data_external_mech (DBusAuth         *auth,
01114                                   const DBusString *data)
01115 {
01116   
01117   return TRUE;
01118 }
01119 
01120 static void
01121 handle_client_shutdown_external_mech (DBusAuth *auth)
01122 {
01123 
01124 }
01125 
01126 /* Put mechanisms here in order of preference.
01127  * What I eventually want to have is:
01128  *
01129  *  - a mechanism that checks UNIX domain socket credentials
01130  *  - a simple magic cookie mechanism like X11 or ICE
01131  *  - mechanisms that chain to Cyrus SASL, so we can use anything it
01132  *    offers such as Kerberos, X509, whatever.
01133  * 
01134  */
01135 static const DBusAuthMechanismHandler
01136 all_mechanisms[] = {
01137   { "EXTERNAL",
01138     handle_server_data_external_mech,
01139     NULL, NULL,
01140     handle_server_shutdown_external_mech,
01141     handle_client_initial_response_external_mech,
01142     handle_client_data_external_mech,
01143     NULL, NULL,
01144     handle_client_shutdown_external_mech },
01145   { "DBUS_COOKIE_SHA1",
01146     handle_server_data_cookie_sha1_mech,
01147     NULL, NULL,
01148     handle_server_shutdown_cookie_sha1_mech,
01149     handle_client_initial_response_cookie_sha1_mech,
01150     handle_client_data_cookie_sha1_mech,
01151     NULL, NULL,
01152     handle_client_shutdown_cookie_sha1_mech },
01153   { NULL, NULL }
01154 };
01155 
01156 static const DBusAuthMechanismHandler*
01157 find_mech (const DBusString  *name,
01158            char             **allowed_mechs)
01159 {
01160   int i;
01161   
01162   if (allowed_mechs != NULL &&
01163       !_dbus_string_array_contains ((const char**) allowed_mechs,
01164                                     _dbus_string_get_const_data (name)))
01165     return NULL;
01166   
01167   i = 0;
01168   while (all_mechanisms[i].mechanism != NULL)
01169     {      
01170       if (_dbus_string_equal_c_str (name,
01171                                     all_mechanisms[i].mechanism))
01172 
01173         return &all_mechanisms[i];
01174       
01175       ++i;
01176     }
01177   
01178   return NULL;
01179 }
01180 
01181 static dbus_bool_t
01182 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01183 {
01184   DBusString auth_command;
01185 
01186   if (!_dbus_string_init (&auth_command))
01187     return FALSE;
01188       
01189   if (!_dbus_string_append (&auth_command,
01190                             "AUTH "))
01191     {
01192       _dbus_string_free (&auth_command);
01193       return FALSE;
01194     }  
01195   
01196   if (!_dbus_string_append (&auth_command,
01197                             mech->mechanism))
01198     {
01199       _dbus_string_free (&auth_command);
01200       return FALSE;
01201     }
01202 
01203   if (mech->client_initial_response_func != NULL)
01204     {
01205       if (!_dbus_string_append (&auth_command, " "))
01206         {
01207           _dbus_string_free (&auth_command);
01208           return FALSE;
01209         }
01210       
01211       if (!(* mech->client_initial_response_func) (auth, &auth_command))
01212         {
01213           _dbus_string_free (&auth_command);
01214           return FALSE;
01215         }
01216     }
01217   
01218   if (!_dbus_string_append (&auth_command,
01219                             "\r\n"))
01220     {
01221       _dbus_string_free (&auth_command);
01222       return FALSE;
01223     }
01224 
01225   if (!_dbus_string_copy (&auth_command, 0,
01226                           &auth->outgoing,
01227                           _dbus_string_get_length (&auth->outgoing)))
01228     {
01229       _dbus_string_free (&auth_command);
01230       return FALSE;
01231     }
01232 
01233   _dbus_string_free (&auth_command);
01234   shutdown_mech (auth);
01235   auth->mech = mech;      
01236   goto_state (auth, &client_state_waiting_for_data);
01237 
01238   return TRUE;
01239 }
01240 
01241 static dbus_bool_t
01242 send_data (DBusAuth *auth, DBusString *data)
01243 {
01244   int old_len;
01245 
01246   if (data == NULL || _dbus_string_get_length (data) == 0)
01247     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01248   else
01249     {
01250       old_len = _dbus_string_get_length (&auth->outgoing);
01251       if (!_dbus_string_append (&auth->outgoing, "DATA "))
01252         goto out;
01253 
01254       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01255                                     _dbus_string_get_length (&auth->outgoing)))
01256         goto out;
01257 
01258       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01259         goto out;
01260 
01261       return TRUE;
01262 
01263     out:
01264       _dbus_string_set_length (&auth->outgoing, old_len);
01265 
01266       return FALSE;
01267     }
01268 }
01269 
01270 static dbus_bool_t
01271 send_rejected (DBusAuth *auth)
01272 {
01273   DBusString command;
01274   DBusAuthServer *server_auth;
01275   int i;
01276   
01277   if (!_dbus_string_init (&command))
01278     return FALSE;
01279   
01280   if (!_dbus_string_append (&command,
01281                             "REJECTED"))
01282     goto nomem;
01283 
01284   i = 0;
01285   while (all_mechanisms[i].mechanism != NULL)
01286     {
01287       if (!_dbus_string_append (&command,
01288                                 " "))
01289         goto nomem;
01290 
01291       if (!_dbus_string_append (&command,
01292                                 all_mechanisms[i].mechanism))
01293         goto nomem;
01294       
01295       ++i;
01296     }
01297   
01298   if (!_dbus_string_append (&command, "\r\n"))
01299     goto nomem;
01300 
01301   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01302                           _dbus_string_get_length (&auth->outgoing)))
01303     goto nomem;
01304 
01305   shutdown_mech (auth);
01306   
01307   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01308   server_auth = DBUS_AUTH_SERVER (auth);
01309   server_auth->failures += 1;
01310 
01311   if (server_auth->failures >= server_auth->max_failures)
01312     goto_state (auth, &common_state_need_disconnect);
01313   else
01314     goto_state (auth, &server_state_waiting_for_auth);
01315 
01316   _dbus_string_free (&command);
01317   
01318   return TRUE;
01319 
01320  nomem:
01321   _dbus_string_free (&command);
01322   return FALSE;
01323 }
01324 
01325 static dbus_bool_t
01326 send_error (DBusAuth *auth, const char *message)
01327 {
01328   return _dbus_string_append_printf (&auth->outgoing,
01329                                      "ERROR \"%s\"\r\n", message);
01330 }
01331 
01332 static dbus_bool_t
01333 send_ok (DBusAuth *auth)
01334 {
01335   int orig_len;
01336 
01337   orig_len = _dbus_string_get_length (&auth->outgoing);
01338   
01339   if (_dbus_string_append (&auth->outgoing, "OK ") &&
01340       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01341                          0,
01342                          &auth->outgoing,
01343                          _dbus_string_get_length (&auth->outgoing)) &&
01344       _dbus_string_append (&auth->outgoing, "\r\n"))
01345     {
01346       goto_state (auth, &server_state_waiting_for_begin);
01347       return TRUE;
01348     }
01349   else
01350     {
01351       _dbus_string_set_length (&auth->outgoing, orig_len);
01352       return FALSE;
01353     }
01354 }
01355 
01356 static dbus_bool_t
01357 send_begin (DBusAuth         *auth,
01358             const DBusString *args_from_ok)
01359 {
01360   int end_of_hex;
01361   
01362   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
01363   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01364 
01365   /* We decode the hex string to binary, using guid_from_server as scratch... */
01366   
01367   end_of_hex = 0;
01368   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01369                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01370     return FALSE;
01371 
01372   /* now clear out the scratch */
01373   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01374   
01375   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01376       end_of_hex == 0)
01377     {
01378       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01379                      end_of_hex, _dbus_string_get_length (args_from_ok));
01380       goto_state (auth, &common_state_need_disconnect);
01381       return TRUE;
01382     }
01383 
01384   if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01385       _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01386     {
01387       _dbus_verbose ("Got GUID '%s' from the server\n",
01388                      _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01389       
01390       goto_state (auth, &common_state_authenticated);
01391       return TRUE;
01392     }
01393   else
01394     {
01395       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01396       return FALSE;
01397     }
01398 }
01399 
01400 static dbus_bool_t
01401 send_cancel (DBusAuth *auth)
01402 {
01403   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01404     {
01405       goto_state (auth, &client_state_waiting_for_reject);
01406       return TRUE;
01407     }
01408   else
01409     return FALSE;
01410 }
01411 
01412 static dbus_bool_t
01413 process_data (DBusAuth             *auth,
01414               const DBusString     *args,
01415               DBusAuthDataFunction  data_func)
01416 {
01417   int end;
01418   DBusString decoded;
01419 
01420   if (!_dbus_string_init (&decoded))
01421     return FALSE;
01422 
01423   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01424     {
01425       _dbus_string_free (&decoded);
01426       return FALSE;
01427     }
01428 
01429   if (_dbus_string_get_length (args) != end)
01430     {
01431       _dbus_string_free (&decoded);
01432       if (!send_error (auth, "Invalid hex encoding"))
01433         return FALSE;
01434 
01435       return TRUE;
01436     }
01437 
01438 #ifdef DBUS_ENABLE_VERBOSE_MODE
01439   if (_dbus_string_validate_ascii (&decoded, 0,
01440                                    _dbus_string_get_length (&decoded)))
01441     _dbus_verbose ("%s: data: '%s'\n",
01442                    DBUS_AUTH_NAME (auth),
01443                    _dbus_string_get_const_data (&decoded));
01444 #endif
01445       
01446   if (!(* data_func) (auth, &decoded))
01447     {
01448       _dbus_string_free (&decoded);
01449       return FALSE;
01450     }
01451 
01452   _dbus_string_free (&decoded);
01453   return TRUE;
01454 }
01455 
01456 static dbus_bool_t
01457 handle_auth (DBusAuth *auth, const DBusString *args)
01458 {
01459   if (_dbus_string_get_length (args) == 0)
01460     {
01461       /* No args to the auth, send mechanisms */
01462       if (!send_rejected (auth))
01463         return FALSE;
01464 
01465       return TRUE;
01466     }
01467   else
01468     {
01469       int i;
01470       DBusString mech;
01471       DBusString hex_response;
01472       
01473       _dbus_string_find_blank (args, 0, &i);
01474 
01475       if (!_dbus_string_init (&mech))
01476         return FALSE;
01477 
01478       if (!_dbus_string_init (&hex_response))
01479         {
01480           _dbus_string_free (&mech);
01481           return FALSE;
01482         }
01483       
01484       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01485         goto failed;
01486 
01487       _dbus_string_skip_blank (args, i, &i);
01488       if (!_dbus_string_copy (args, i, &hex_response, 0))
01489         goto failed;
01490      
01491       auth->mech = find_mech (&mech, auth->allowed_mechs);
01492       if (auth->mech != NULL)
01493         {
01494           _dbus_verbose ("%s: Trying mechanism %s\n",
01495                          DBUS_AUTH_NAME (auth),
01496                          auth->mech->mechanism);
01497           
01498           if (!process_data (auth, &hex_response,
01499                              auth->mech->server_data_func))
01500             goto failed;
01501         }
01502       else
01503         {
01504           /* Unsupported mechanism */
01505           _dbus_verbose ("%s: Unsupported mechanism %s\n",
01506                          DBUS_AUTH_NAME (auth),
01507                          _dbus_string_get_const_data (&mech));
01508           
01509           if (!send_rejected (auth))
01510             goto failed;
01511         }
01512 
01513       _dbus_string_free (&mech);      
01514       _dbus_string_free (&hex_response);
01515 
01516       return TRUE;
01517       
01518     failed:
01519       auth->mech = NULL;
01520       _dbus_string_free (&mech);
01521       _dbus_string_free (&hex_response);
01522       return FALSE;
01523     }
01524 }
01525 
01526 static dbus_bool_t
01527 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
01528                                        DBusAuthCommand   command,
01529                                        const DBusString *args)
01530 {
01531   switch (command)
01532     {
01533     case DBUS_AUTH_COMMAND_AUTH:
01534       return handle_auth (auth, args);
01535 
01536     case DBUS_AUTH_COMMAND_CANCEL:
01537     case DBUS_AUTH_COMMAND_DATA:
01538       return send_error (auth, "Not currently in an auth conversation");
01539 
01540     case DBUS_AUTH_COMMAND_BEGIN:
01541       goto_state (auth, &common_state_need_disconnect);
01542       return TRUE;
01543 
01544     case DBUS_AUTH_COMMAND_ERROR:
01545       return send_rejected (auth);
01546 
01547     case DBUS_AUTH_COMMAND_REJECTED:
01548     case DBUS_AUTH_COMMAND_OK:
01549     case DBUS_AUTH_COMMAND_UNKNOWN:
01550     default:
01551       return send_error (auth, "Unknown command");
01552     }
01553 }
01554 
01555 static dbus_bool_t
01556 handle_server_state_waiting_for_data  (DBusAuth         *auth,
01557                                        DBusAuthCommand   command,
01558                                        const DBusString *args)
01559 {
01560   switch (command)
01561     {
01562     case DBUS_AUTH_COMMAND_AUTH:
01563       return send_error (auth, "Sent AUTH while another AUTH in progress");
01564 
01565     case DBUS_AUTH_COMMAND_CANCEL:
01566     case DBUS_AUTH_COMMAND_ERROR:
01567       return send_rejected (auth);
01568 
01569     case DBUS_AUTH_COMMAND_DATA:
01570       return process_data (auth, args, auth->mech->server_data_func);
01571 
01572     case DBUS_AUTH_COMMAND_BEGIN:
01573       goto_state (auth, &common_state_need_disconnect);
01574       return TRUE;
01575 
01576     case DBUS_AUTH_COMMAND_REJECTED:
01577     case DBUS_AUTH_COMMAND_OK:
01578     case DBUS_AUTH_COMMAND_UNKNOWN:
01579     default:
01580       return send_error (auth, "Unknown command");
01581     }
01582 }
01583 
01584 static dbus_bool_t
01585 handle_server_state_waiting_for_begin (DBusAuth         *auth,
01586                                        DBusAuthCommand   command,
01587                                        const DBusString *args)
01588 {
01589   switch (command)
01590     {
01591     case DBUS_AUTH_COMMAND_AUTH:
01592       return send_error (auth, "Sent AUTH while expecting BEGIN");
01593 
01594     case DBUS_AUTH_COMMAND_DATA:
01595       return send_error (auth, "Sent DATA while expecting BEGIN");
01596 
01597     case DBUS_AUTH_COMMAND_BEGIN:
01598       goto_state (auth, &common_state_authenticated);
01599       return TRUE;
01600 
01601     case DBUS_AUTH_COMMAND_REJECTED:
01602     case DBUS_AUTH_COMMAND_OK:
01603     case DBUS_AUTH_COMMAND_UNKNOWN:
01604     default:
01605       return send_error (auth, "Unknown command");
01606 
01607     case DBUS_AUTH_COMMAND_CANCEL:
01608     case DBUS_AUTH_COMMAND_ERROR:
01609       return send_rejected (auth);
01610     }
01611 }
01612 
01613 /* return FALSE if no memory, TRUE if all OK */
01614 static dbus_bool_t
01615 get_word (const DBusString *str,
01616           int              *start,
01617           DBusString       *word)
01618 {
01619   int i;
01620 
01621   _dbus_string_skip_blank (str, *start, start);
01622   _dbus_string_find_blank (str, *start, &i);
01623   
01624   if (i > *start)
01625     {
01626       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01627         return FALSE;
01628       
01629       *start = i;
01630     }
01631 
01632   return TRUE;
01633 }
01634 
01635 static dbus_bool_t
01636 record_mechanisms (DBusAuth         *auth,
01637                    const DBusString *args)
01638 {
01639   int next;
01640   int len;
01641 
01642   if (auth->already_got_mechanisms)
01643     return TRUE;
01644   
01645   len = _dbus_string_get_length (args);
01646   
01647   next = 0;
01648   while (next < len)
01649     {
01650       DBusString m;
01651       const DBusAuthMechanismHandler *mech;
01652       
01653       if (!_dbus_string_init (&m))
01654         goto nomem;
01655       
01656       if (!get_word (args, &next, &m))
01657         {
01658           _dbus_string_free (&m);
01659           goto nomem;
01660         }
01661 
01662       mech = find_mech (&m, auth->allowed_mechs);
01663 
01664       if (mech != NULL)
01665         {
01666           /* FIXME right now we try mechanisms in the order
01667            * the server lists them; should we do them in
01668            * some more deterministic order?
01669            *
01670            * Probably in all_mechanisms order, our order of
01671            * preference. Of course when the server is us,
01672            * it lists things in that order anyhow.
01673            */
01674 
01675           _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01676                          DBUS_AUTH_NAME (auth), mech->mechanism);
01677           
01678           if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01679                                   (void*) mech))
01680             {
01681               _dbus_string_free (&m);
01682               goto nomem;
01683             }
01684         }
01685       else
01686         {
01687           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01688                          DBUS_AUTH_NAME (auth),
01689                          _dbus_string_get_const_data (&m));
01690         }
01691 
01692       _dbus_string_free (&m);
01693     }
01694   
01695   auth->already_got_mechanisms = TRUE;
01696   
01697   return TRUE;
01698 
01699  nomem:
01700   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01701   
01702   return FALSE;
01703 }
01704 
01705 static dbus_bool_t
01706 process_rejected (DBusAuth *auth, const DBusString *args)
01707 {
01708   const DBusAuthMechanismHandler *mech;
01709   DBusAuthClient *client;
01710 
01711   client = DBUS_AUTH_CLIENT (auth);
01712 
01713   if (!auth->already_got_mechanisms)
01714     {
01715       if (!record_mechanisms (auth, args))
01716         return FALSE;
01717     }
01718   
01719   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01720     {
01721       mech = client->mechs_to_try->data;
01722 
01723       if (!send_auth (auth, mech))
01724         return FALSE;
01725 
01726       _dbus_list_pop_first (&client->mechs_to_try);
01727 
01728       _dbus_verbose ("%s: Trying mechanism %s\n",
01729                      DBUS_AUTH_NAME (auth),
01730                      mech->mechanism);
01731     }
01732   else
01733     {
01734       /* Give up */
01735       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01736                      DBUS_AUTH_NAME (auth));
01737       goto_state (auth, &common_state_need_disconnect);
01738     }
01739   
01740   return TRUE;
01741 }
01742 
01743 
01744 static dbus_bool_t
01745 handle_client_state_waiting_for_data (DBusAuth         *auth,
01746                                       DBusAuthCommand   command,
01747                                       const DBusString *args)
01748 {
01749   _dbus_assert (auth->mech != NULL);
01750  
01751   switch (command)
01752     {
01753     case DBUS_AUTH_COMMAND_DATA:
01754       return process_data (auth, args, auth->mech->client_data_func);
01755 
01756     case DBUS_AUTH_COMMAND_REJECTED:
01757       return process_rejected (auth, args);
01758 
01759     case DBUS_AUTH_COMMAND_OK:
01760       return send_begin (auth, args);
01761 
01762     case DBUS_AUTH_COMMAND_ERROR:
01763       return send_cancel (auth);
01764 
01765     case DBUS_AUTH_COMMAND_AUTH:
01766     case DBUS_AUTH_COMMAND_CANCEL:
01767     case DBUS_AUTH_COMMAND_BEGIN:
01768     case DBUS_AUTH_COMMAND_UNKNOWN:
01769     default:
01770       return send_error (auth, "Unknown command");
01771     }
01772 }
01773 
01774 static dbus_bool_t
01775 handle_client_state_waiting_for_ok (DBusAuth         *auth,
01776                                     DBusAuthCommand   command,
01777                                     const DBusString *args)
01778 {
01779   switch (command)
01780     {
01781     case DBUS_AUTH_COMMAND_REJECTED:
01782       return process_rejected (auth, args);
01783 
01784     case DBUS_AUTH_COMMAND_OK:
01785       return send_begin (auth, args);
01786 
01787     case DBUS_AUTH_COMMAND_DATA:
01788     case DBUS_AUTH_COMMAND_ERROR:
01789       return send_cancel (auth);
01790 
01791     case DBUS_AUTH_COMMAND_AUTH:
01792     case DBUS_AUTH_COMMAND_CANCEL:
01793     case DBUS_AUTH_COMMAND_BEGIN:
01794     case DBUS_AUTH_COMMAND_UNKNOWN:
01795     default:
01796       return send_error (auth, "Unknown command");
01797     }
01798 }
01799 
01800 static dbus_bool_t
01801 handle_client_state_waiting_for_reject (DBusAuth         *auth,
01802                                         DBusAuthCommand   command,
01803                                         const DBusString *args)
01804 {
01805   switch (command)
01806     {
01807     case DBUS_AUTH_COMMAND_REJECTED:
01808       return process_rejected (auth, args);
01809       
01810     case DBUS_AUTH_COMMAND_AUTH:
01811     case DBUS_AUTH_COMMAND_CANCEL:
01812     case DBUS_AUTH_COMMAND_DATA:
01813     case DBUS_AUTH_COMMAND_BEGIN:
01814     case DBUS_AUTH_COMMAND_OK:
01815     case DBUS_AUTH_COMMAND_ERROR:
01816     case DBUS_AUTH_COMMAND_UNKNOWN:
01817     default:
01818       goto_state (auth, &common_state_need_disconnect);
01819       return TRUE;
01820     }
01821 }
01822 
01826 typedef struct {
01827   const char *name;        
01828   DBusAuthCommand command; 
01829 } DBusAuthCommandName;
01830 
01831 static DBusAuthCommandName auth_command_names[] = {
01832   { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
01833   { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
01834   { "DATA",     DBUS_AUTH_COMMAND_DATA },
01835   { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
01836   { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
01837   { "OK",       DBUS_AUTH_COMMAND_OK },
01838   { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
01839 };
01840 
01841 static DBusAuthCommand
01842 lookup_command_from_name (DBusString *command)
01843 {
01844   int i;
01845 
01846   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
01847     {
01848       if (_dbus_string_equal_c_str (command,
01849                                     auth_command_names[i].name))
01850         return auth_command_names[i].command;
01851     }
01852 
01853   return DBUS_AUTH_COMMAND_UNKNOWN;
01854 }
01855 
01856 static void
01857 goto_state (DBusAuth *auth, const DBusAuthStateData *state)
01858 {
01859   _dbus_verbose ("%s: going from state %s to state %s\n",
01860                  DBUS_AUTH_NAME (auth),
01861                  auth->state->name,
01862                  state->name);
01863 
01864   auth->state = state;
01865 }
01866 
01867 /* returns whether to call it again right away */
01868 static dbus_bool_t
01869 process_command (DBusAuth *auth)
01870 {
01871   DBusAuthCommand command;
01872   DBusString line;
01873   DBusString args;
01874   int eol;
01875   int i, j;
01876   dbus_bool_t retval;
01877 
01878   /* _dbus_verbose ("%s:   trying process_command()\n"); */
01879   
01880   retval = FALSE;
01881   
01882   eol = 0;
01883   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
01884     return FALSE;
01885   
01886   if (!_dbus_string_init (&line))
01887     {
01888       auth->needed_memory = TRUE;
01889       return FALSE;
01890     }
01891 
01892   if (!_dbus_string_init (&args))
01893     {
01894       _dbus_string_free (&line);
01895       auth->needed_memory = TRUE;
01896       return FALSE;
01897     }
01898   
01899   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
01900     goto out;
01901 
01902   if (!_dbus_string_validate_ascii (&line, 0,
01903                                     _dbus_string_get_length (&line)))
01904     {
01905       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
01906                      DBUS_AUTH_NAME (auth));
01907       if (!send_error (auth, "Command contained non-ASCII"))
01908         goto out;
01909       else
01910         goto next_command;
01911     }
01912   
01913   _dbus_verbose ("%s: got command \"%s\"\n",
01914                  DBUS_AUTH_NAME (auth),
01915                  _dbus_string_get_const_data (&line));
01916   
01917   _dbus_string_find_blank (&line, 0, &i);
01918   _dbus_string_skip_blank (&line, i, &j);
01919 
01920   if (j > i)
01921     _dbus_string_delete (&line, i, j - i);
01922   
01923   if (!_dbus_string_move (&line, i, &args, 0))
01924     goto out;
01925 
01926   /* FIXME we should probably validate that only the allowed
01927    * chars are in the command name
01928    */
01929   
01930   command = lookup_command_from_name (&line);
01931   if (!(* auth->state->handler) (auth, command, &args))
01932     goto out;
01933 
01934  next_command:
01935   
01936   /* We've succeeded in processing the whole command so drop it out
01937    * of the incoming buffer and return TRUE to try another command.
01938    */
01939 
01940   _dbus_string_delete (&auth->incoming, 0, eol);
01941   
01942   /* kill the \r\n */
01943   _dbus_string_delete (&auth->incoming, 0, 2);
01944 
01945   retval = TRUE;
01946   
01947  out:
01948   _dbus_string_free (&args);
01949   _dbus_string_free (&line);
01950 
01951   if (!retval)
01952     auth->needed_memory = TRUE;
01953   else
01954     auth->needed_memory = FALSE;
01955   
01956   return retval;
01957 }
01958 
01959 
01974 DBusAuth*
01975 _dbus_auth_server_new (const DBusString *guid)
01976 {
01977   DBusAuth *auth;
01978   DBusAuthServer *server_auth;
01979   DBusString guid_copy;
01980 
01981   if (!_dbus_string_init (&guid_copy))
01982     return NULL;
01983 
01984   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
01985     {
01986       _dbus_string_free (&guid_copy);
01987       return NULL;
01988     }
01989 
01990   auth = _dbus_auth_new (sizeof (DBusAuthServer));
01991   if (auth == NULL)
01992     {
01993       _dbus_string_free (&guid_copy);
01994       return NULL;
01995     }
01996   
01997   auth->side = auth_side_server;
01998   auth->state = &server_state_waiting_for_auth;
01999 
02000   server_auth = DBUS_AUTH_SERVER (auth);
02001 
02002   server_auth->guid = guid_copy;
02003   
02004   /* perhaps this should be per-mechanism with a lower
02005    * max
02006    */
02007   server_auth->failures = 0;
02008   server_auth->max_failures = 6;
02009   
02010   return auth;
02011 }
02012 
02020 DBusAuth*
02021 _dbus_auth_client_new (void)
02022 {
02023   DBusAuth *auth;
02024   DBusString guid_str;
02025 
02026   if (!_dbus_string_init (&guid_str))
02027     return NULL;
02028 
02029   auth = _dbus_auth_new (sizeof (DBusAuthClient));
02030   if (auth == NULL)
02031     {
02032       _dbus_string_free (&guid_str);
02033       return NULL;
02034     }
02035 
02036   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02037 
02038   auth->side = auth_side_client;
02039   auth->state = &client_state_need_send_auth;
02040 
02041   /* Start the auth conversation by sending AUTH for our default
02042    * mechanism */
02043   if (!send_auth (auth, &all_mechanisms[0]))
02044     {
02045       _dbus_auth_unref (auth);
02046       return NULL;
02047     }
02048   
02049   return auth;
02050 }
02051 
02058 DBusAuth *
02059 _dbus_auth_ref (DBusAuth *auth)
02060 {
02061   _dbus_assert (auth != NULL);
02062   
02063   auth->refcount += 1;
02064   
02065   return auth;
02066 }
02067 
02073 void
02074 _dbus_auth_unref (DBusAuth *auth)
02075 {
02076   _dbus_assert (auth != NULL);
02077   _dbus_assert (auth->refcount > 0);
02078 
02079   auth->refcount -= 1;
02080   if (auth->refcount == 0)
02081     {
02082       shutdown_mech (auth);
02083 
02084       if (DBUS_AUTH_IS_CLIENT (auth))
02085         {
02086           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02087           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02088         }
02089       else
02090         {
02091           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02092 
02093           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02094         }
02095 
02096       if (auth->keyring)
02097         _dbus_keyring_unref (auth->keyring);
02098 
02099       _dbus_string_free (&auth->context);
02100       _dbus_string_free (&auth->challenge);
02101       _dbus_string_free (&auth->identity);
02102       _dbus_string_free (&auth->incoming);
02103       _dbus_string_free (&auth->outgoing);
02104 
02105       dbus_free_string_array (auth->allowed_mechs);
02106       
02107       dbus_free (auth);
02108     }
02109 }
02110 
02119 dbus_bool_t
02120 _dbus_auth_set_mechanisms (DBusAuth    *auth,
02121                            const char **mechanisms)
02122 {
02123   char **copy;
02124 
02125   if (mechanisms != NULL)
02126     {
02127       copy = _dbus_dup_string_array (mechanisms);
02128       if (copy == NULL)
02129         return FALSE;
02130     }
02131   else
02132     copy = NULL;
02133   
02134   dbus_free_string_array (auth->allowed_mechs);
02135 
02136   auth->allowed_mechs = copy;
02137 
02138   return TRUE;
02139 }
02140 
02145 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02146 
02154 DBusAuthState
02155 _dbus_auth_do_work (DBusAuth *auth)
02156 {
02157   auth->needed_memory = FALSE;
02158 
02159   /* Max amount we'll buffer up before deciding someone's on crack */
02160 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02161 
02162   do
02163     {
02164       if (DBUS_AUTH_IN_END_STATE (auth))
02165         break;
02166       
02167       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02168           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02169         {
02170           goto_state (auth, &common_state_need_disconnect);
02171           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02172                          DBUS_AUTH_NAME (auth));
02173           break;
02174         }
02175     }
02176   while (process_command (auth));
02177 
02178   if (auth->needed_memory)
02179     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02180   else if (_dbus_string_get_length (&auth->outgoing) > 0)
02181     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02182   else if (auth->state == &common_state_need_disconnect)
02183     return DBUS_AUTH_STATE_NEED_DISCONNECT;
02184   else if (auth->state == &common_state_authenticated)
02185     return DBUS_AUTH_STATE_AUTHENTICATED;
02186   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02187 }
02188 
02198 dbus_bool_t
02199 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
02200                               const DBusString **str)
02201 {
02202   _dbus_assert (auth != NULL);
02203   _dbus_assert (str != NULL);
02204 
02205   *str = NULL;
02206   
02207   if (_dbus_string_get_length (&auth->outgoing) == 0)
02208     return FALSE;
02209 
02210   *str = &auth->outgoing;
02211 
02212   return TRUE;
02213 }
02214 
02223 void
02224 _dbus_auth_bytes_sent (DBusAuth *auth,
02225                        int       bytes_sent)
02226 {
02227   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02228                  DBUS_AUTH_NAME (auth),
02229                  bytes_sent,
02230                  _dbus_string_get_const_data (&auth->outgoing));
02231   
02232   _dbus_string_delete (&auth->outgoing,
02233                        0, bytes_sent);
02234 }
02235 
02243 void
02244 _dbus_auth_get_buffer (DBusAuth     *auth,
02245                        DBusString **buffer)
02246 {
02247   _dbus_assert (auth != NULL);
02248   _dbus_assert (!auth->buffer_outstanding);
02249   
02250   *buffer = &auth->incoming;
02251 
02252   auth->buffer_outstanding = TRUE;
02253 }
02254 
02262 void
02263 _dbus_auth_return_buffer (DBusAuth               *auth,
02264                           DBusString             *buffer,
02265                           int                     bytes_read)
02266 {
02267   _dbus_assert (buffer == &auth->incoming);
02268   _dbus_assert (auth->buffer_outstanding);
02269 
02270   auth->buffer_outstanding = FALSE;
02271 }
02272 
02282 void
02283 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
02284                              const DBusString **str)
02285 {
02286   if (!DBUS_AUTH_IN_END_STATE (auth))
02287     return;
02288 
02289   *str = &auth->incoming;
02290 }
02291 
02292 
02299 void
02300 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02301 {
02302   if (!DBUS_AUTH_IN_END_STATE (auth))
02303     return;
02304 
02305   _dbus_string_set_length (&auth->incoming, 0);
02306 }
02307 
02316 dbus_bool_t
02317 _dbus_auth_needs_encoding (DBusAuth *auth)
02318 {
02319   if (auth->state != &common_state_authenticated)
02320     return FALSE;
02321   
02322   if (auth->mech != NULL)
02323     {
02324       if (DBUS_AUTH_IS_CLIENT (auth))
02325         return auth->mech->client_encode_func != NULL;
02326       else
02327         return auth->mech->server_encode_func != NULL;
02328     }
02329   else
02330     return FALSE;
02331 }
02332 
02343 dbus_bool_t
02344 _dbus_auth_encode_data (DBusAuth         *auth,
02345                         const DBusString *plaintext,
02346                         DBusString       *encoded)
02347 {
02348   _dbus_assert (plaintext != encoded);
02349   
02350   if (auth->state != &common_state_authenticated)
02351     return FALSE;
02352   
02353   if (_dbus_auth_needs_encoding (auth))
02354     {
02355       if (DBUS_AUTH_IS_CLIENT (auth))
02356         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02357       else
02358         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02359     }
02360   else
02361     {
02362       return _dbus_string_copy (plaintext, 0, encoded,
02363                                 _dbus_string_get_length (encoded));
02364     }
02365 }
02366 
02375 dbus_bool_t
02376 _dbus_auth_needs_decoding (DBusAuth *auth)
02377 {
02378   if (auth->state != &common_state_authenticated)
02379     return FALSE;
02380     
02381   if (auth->mech != NULL)
02382     {
02383       if (DBUS_AUTH_IS_CLIENT (auth))
02384         return auth->mech->client_decode_func != NULL;
02385       else
02386         return auth->mech->server_decode_func != NULL;
02387     }
02388   else
02389     return FALSE;
02390 }
02391 
02392 
02406 dbus_bool_t
02407 _dbus_auth_decode_data (DBusAuth         *auth,
02408                         const DBusString *encoded,
02409                         DBusString       *plaintext)
02410 {
02411   _dbus_assert (plaintext != encoded);
02412   
02413   if (auth->state != &common_state_authenticated)
02414     return FALSE;
02415   
02416   if (_dbus_auth_needs_decoding (auth))
02417     {
02418       if (DBUS_AUTH_IS_CLIENT (auth))
02419         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02420       else
02421         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02422     }
02423   else
02424     {
02425       return _dbus_string_copy (encoded, 0, plaintext,
02426                                 _dbus_string_get_length (plaintext));
02427     }
02428 }
02429 
02437 void
02438 _dbus_auth_set_credentials (DBusAuth               *auth,
02439                             const DBusCredentials  *credentials)
02440 {
02441   auth->credentials = *credentials;
02442 }
02443 
02451 void
02452 _dbus_auth_get_identity (DBusAuth               *auth,
02453                          DBusCredentials        *credentials)
02454 {
02455   if (auth->state == &common_state_authenticated)
02456     *credentials = auth->authorized_identity;
02457   else
02458     _dbus_credentials_clear (credentials);
02459 }
02460 
02467 const char*
02468 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02469 {
02470   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02471   
02472   if (auth->state == &common_state_authenticated)
02473     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02474   else
02475     return NULL;
02476 }
02477 
02486 dbus_bool_t
02487 _dbus_auth_set_context (DBusAuth               *auth,
02488                         const DBusString       *context)
02489 {
02490   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02491                                    &auth->context, 0, _dbus_string_get_length (context));
02492 }
02493 
02496 /* tests in dbus-auth-util.c */

Generated on Tue Sep 13 01:28:06 2005 for D-BUS by  doxygen 1.4.4