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

Generated on Tue Aug 30 16:35:49 2005 for D-BUS by  doxygen 1.4.3