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