D-Bus  1.4.18
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   DBusCredentials *myself = NULL;
00530   
00531   retval = FALSE;
00532 
00533   _dbus_string_set_length (&auth->challenge, 0);
00534   
00535   if (_dbus_string_get_length (data) > 0)
00536     {
00537       if (_dbus_string_get_length (&auth->identity) > 0)
00538         {
00539           /* Tried to send two auth identities, wtf */
00540           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00541                          DBUS_AUTH_NAME (auth));
00542           return send_rejected (auth);
00543         }
00544       else
00545         {
00546           /* this is our auth identity */
00547           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00548             return FALSE;
00549         }
00550     }
00551       
00552   if (!_dbus_credentials_add_from_user (auth->desired_identity, data))
00553     {
00554       _dbus_verbose ("%s: Did not get a valid username from client\n",
00555                      DBUS_AUTH_NAME (auth));
00556       return send_rejected (auth);
00557     }
00558       
00559   if (!_dbus_string_init (&tmp))
00560     return FALSE;
00561 
00562   if (!_dbus_string_init (&tmp2))
00563     {
00564       _dbus_string_free (&tmp);
00565       return FALSE;
00566     }
00567 
00568   myself = _dbus_credentials_new_from_current_process ();
00569 
00570   if (myself == NULL)
00571     goto out;
00572 
00573   if (!_dbus_credentials_same_user (myself, auth->desired_identity))
00574     {
00575       /*
00576        * DBUS_COOKIE_SHA1 is not suitable for authenticating that the
00577        * client is anyone other than the user owning the process
00578        * containing the DBusServer: we probably aren't allowed to write
00579        * to other users' home directories. Even if we can (for example
00580        * uid 0 on traditional Unix or CAP_DAC_OVERRIDE on Linux), we
00581        * must not, because the other user controls their home directory,
00582        * and could carry out symlink attacks to make us read from or
00583        * write to unintended locations. It's difficult to avoid symlink
00584        * attacks in a portable way, so we just don't try. This isn't a
00585        * regression, because DBUS_COOKIE_SHA1 never worked for other
00586        * users anyway.
00587        */
00588       _dbus_verbose ("%s: client tried to authenticate as \"%s\", "
00589                      "but that doesn't match this process",
00590                      DBUS_AUTH_NAME (auth),
00591                      _dbus_string_get_const_data (data));
00592       retval = send_rejected (auth);
00593       goto out;
00594     }
00595 
00596   /* we cache the keyring for speed, so here we drop it if it's the
00597    * wrong one. FIXME caching the keyring here is useless since we use
00598    * a different DBusAuth for every connection.
00599    */
00600   if (auth->keyring &&
00601       !_dbus_keyring_is_for_credentials (auth->keyring,
00602                                          auth->desired_identity))
00603     {
00604       _dbus_keyring_unref (auth->keyring);
00605       auth->keyring = NULL;
00606     }
00607   
00608   if (auth->keyring == NULL)
00609     {
00610       dbus_error_init (&error);
00611       auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity,
00612                                                          &auth->context,
00613                                                          &error);
00614 
00615       if (auth->keyring == NULL)
00616         {
00617           if (dbus_error_has_name (&error,
00618                                    DBUS_ERROR_NO_MEMORY))
00619             {
00620               dbus_error_free (&error);
00621               goto out;
00622             }
00623           else
00624             {
00625               _DBUS_ASSERT_ERROR_IS_SET (&error);
00626               _dbus_verbose ("%s: Error loading keyring: %s\n",
00627                              DBUS_AUTH_NAME (auth), error.message);
00628               if (send_rejected (auth))
00629                 retval = TRUE; /* retval is only about mem */
00630               dbus_error_free (&error);
00631               goto out;
00632             }
00633         }
00634       else
00635         {
00636           _dbus_assert (!dbus_error_is_set (&error));
00637         }
00638     }
00639 
00640   _dbus_assert (auth->keyring != NULL);
00641 
00642   dbus_error_init (&error);
00643   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00644   if (auth->cookie_id < 0)
00645     {
00646       _DBUS_ASSERT_ERROR_IS_SET (&error);
00647       _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00648                      DBUS_AUTH_NAME (auth), error.message);
00649       if (send_rejected (auth))
00650         retval = TRUE;
00651       dbus_error_free (&error);
00652       goto out;
00653     }
00654   else
00655     {
00656       _dbus_assert (!dbus_error_is_set (&error));
00657     }
00658 
00659   if (!_dbus_string_copy (&auth->context, 0,
00660                           &tmp2, _dbus_string_get_length (&tmp2)))
00661     goto out;
00662 
00663   if (!_dbus_string_append (&tmp2, " "))
00664     goto out;
00665 
00666   if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00667     goto out;
00668 
00669   if (!_dbus_string_append (&tmp2, " "))
00670     goto out;  
00671   
00672   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00673     goto out;
00674 
00675   _dbus_string_set_length (&auth->challenge, 0);
00676   if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00677     goto out;
00678   
00679   if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00680                                 _dbus_string_get_length (&tmp2)))
00681     goto out;
00682 
00683   if (!send_data (auth, &tmp2))
00684     goto out;
00685       
00686   goto_state (auth, &server_state_waiting_for_data);
00687   retval = TRUE;
00688   
00689  out:
00690   _dbus_string_zero (&tmp);
00691   _dbus_string_free (&tmp);
00692   _dbus_string_zero (&tmp2);
00693   _dbus_string_free (&tmp2);
00694 
00695   if (myself != NULL)
00696     _dbus_credentials_unref (myself);
00697 
00698   return retval;
00699 }
00700 
00701 static dbus_bool_t
00702 sha1_handle_second_client_response (DBusAuth         *auth,
00703                                     const DBusString *data)
00704 {
00705   /* We are expecting a response which is the hex-encoded client
00706    * challenge, space, then SHA-1 hash of the concatenation of our
00707    * challenge, ":", client challenge, ":", secret key, all
00708    * hex-encoded.
00709    */
00710   int i;
00711   DBusString client_challenge;
00712   DBusString client_hash;
00713   dbus_bool_t retval;
00714   DBusString correct_hash;
00715   
00716   retval = FALSE;
00717   
00718   if (!_dbus_string_find_blank (data, 0, &i))
00719     {
00720       _dbus_verbose ("%s: no space separator in client response\n",
00721                      DBUS_AUTH_NAME (auth));
00722       return send_rejected (auth);
00723     }
00724   
00725   if (!_dbus_string_init (&client_challenge))
00726     goto out_0;
00727 
00728   if (!_dbus_string_init (&client_hash))
00729     goto out_1;  
00730 
00731   if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00732                               0))
00733     goto out_2;
00734 
00735   _dbus_string_skip_blank (data, i, &i);
00736   
00737   if (!_dbus_string_copy_len (data, i,
00738                               _dbus_string_get_length (data) - i,
00739                               &client_hash,
00740                               0))
00741     goto out_2;
00742 
00743   if (_dbus_string_get_length (&client_challenge) == 0 ||
00744       _dbus_string_get_length (&client_hash) == 0)
00745     {
00746       _dbus_verbose ("%s: zero-length client challenge or hash\n",
00747                      DBUS_AUTH_NAME (auth));
00748       if (send_rejected (auth))
00749         retval = TRUE;
00750       goto out_2;
00751     }
00752 
00753   if (!_dbus_string_init (&correct_hash))
00754     goto out_2;
00755 
00756   if (!sha1_compute_hash (auth, auth->cookie_id,
00757                           &auth->challenge, 
00758                           &client_challenge,
00759                           &correct_hash))
00760     goto out_3;
00761 
00762   /* if cookie_id was invalid, then we get an empty hash */
00763   if (_dbus_string_get_length (&correct_hash) == 0)
00764     {
00765       if (send_rejected (auth))
00766         retval = TRUE;
00767       goto out_3;
00768     }
00769   
00770   if (!_dbus_string_equal (&client_hash, &correct_hash))
00771     {
00772       if (send_rejected (auth))
00773         retval = TRUE;
00774       goto out_3;
00775     }
00776 
00777   if (!_dbus_credentials_add_credentials (auth->authorized_identity,
00778                                           auth->desired_identity))
00779     goto out_3;
00780 
00781   /* Copy process ID from the socket credentials if it's there
00782    */
00783   if (!_dbus_credentials_add_credential (auth->authorized_identity,
00784                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
00785                                          auth->credentials))
00786     goto out_3;
00787   
00788   if (!send_ok (auth))
00789     goto out_3;
00790 
00791   _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n",
00792                  DBUS_AUTH_NAME (auth));
00793   
00794   retval = TRUE;
00795   
00796  out_3:
00797   _dbus_string_zero (&correct_hash);
00798   _dbus_string_free (&correct_hash);
00799  out_2:
00800   _dbus_string_zero (&client_hash);
00801   _dbus_string_free (&client_hash);
00802  out_1:
00803   _dbus_string_free (&client_challenge);
00804  out_0:
00805   return retval;
00806 }
00807 
00808 static dbus_bool_t
00809 handle_server_data_cookie_sha1_mech (DBusAuth         *auth,
00810                                      const DBusString *data)
00811 {
00812   if (auth->cookie_id < 0)
00813     return sha1_handle_first_client_response (auth, data);
00814   else
00815     return sha1_handle_second_client_response (auth, data);
00816 }
00817 
00818 static void
00819 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00820 {
00821   auth->cookie_id = -1;  
00822   _dbus_string_set_length (&auth->challenge, 0);
00823 }
00824 
00825 static dbus_bool_t
00826 handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
00827                                                  DBusString *response)
00828 {
00829   DBusString username;
00830   dbus_bool_t retval;
00831 
00832   retval = FALSE;
00833 
00834   if (!_dbus_string_init (&username))
00835     return FALSE;
00836   
00837   if (!_dbus_append_user_from_current_process (&username))
00838     goto out_0;
00839 
00840   if (!_dbus_string_hex_encode (&username, 0,
00841                                 response,
00842                                 _dbus_string_get_length (response)))
00843     goto out_0;
00844 
00845   retval = TRUE;
00846   
00847  out_0:
00848   _dbus_string_free (&username);
00849   
00850   return retval;
00851 }
00852 
00853 static dbus_bool_t
00854 handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
00855                                      const DBusString *data)
00856 {
00857   /* The data we get from the server should be the cookie context
00858    * name, the cookie ID, and the server challenge, separated by
00859    * spaces. We send back our challenge string and the correct hash.
00860    */
00861   dbus_bool_t retval;
00862   DBusString context;
00863   DBusString cookie_id_str;
00864   DBusString server_challenge;
00865   DBusString client_challenge;
00866   DBusString correct_hash;
00867   DBusString tmp;
00868   int i, j;
00869   long val;
00870   
00871   retval = FALSE;                 
00872   
00873   if (!_dbus_string_find_blank (data, 0, &i))
00874     {
00875       if (send_error (auth,
00876                       "Server did not send context/ID/challenge properly"))
00877         retval = TRUE;
00878       goto out_0;
00879     }
00880 
00881   if (!_dbus_string_init (&context))
00882     goto out_0;
00883 
00884   if (!_dbus_string_copy_len (data, 0, i,
00885                               &context, 0))
00886     goto out_1;
00887   
00888   _dbus_string_skip_blank (data, i, &i);
00889   if (!_dbus_string_find_blank (data, i, &j))
00890     {
00891       if (send_error (auth,
00892                       "Server did not send context/ID/challenge properly"))
00893         retval = TRUE;
00894       goto out_1;
00895     }
00896 
00897   if (!_dbus_string_init (&cookie_id_str))
00898     goto out_1;
00899   
00900   if (!_dbus_string_copy_len (data, i, j - i,
00901                               &cookie_id_str, 0))
00902     goto out_2;  
00903 
00904   if (!_dbus_string_init (&server_challenge))
00905     goto out_2;
00906 
00907   i = j;
00908   _dbus_string_skip_blank (data, i, &i);
00909   j = _dbus_string_get_length (data);
00910 
00911   if (!_dbus_string_copy_len (data, i, j - i,
00912                               &server_challenge, 0))
00913     goto out_3;
00914 
00915   if (!_dbus_keyring_validate_context (&context))
00916     {
00917       if (send_error (auth, "Server sent invalid cookie context"))
00918         retval = TRUE;
00919       goto out_3;
00920     }
00921 
00922   if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00923     {
00924       if (send_error (auth, "Could not parse cookie ID as an integer"))
00925         retval = TRUE;
00926       goto out_3;
00927     }
00928 
00929   if (_dbus_string_get_length (&server_challenge) == 0)
00930     {
00931       if (send_error (auth, "Empty server challenge string"))
00932         retval = TRUE;
00933       goto out_3;
00934     }
00935 
00936   if (auth->keyring == NULL)
00937     {
00938       DBusError error;
00939 
00940       dbus_error_init (&error);
00941       auth->keyring = _dbus_keyring_new_for_credentials (NULL,
00942                                                          &context,
00943                                                          &error);
00944 
00945       if (auth->keyring == NULL)
00946         {
00947           if (dbus_error_has_name (&error,
00948                                    DBUS_ERROR_NO_MEMORY))
00949             {
00950               dbus_error_free (&error);
00951               goto out_3;
00952             }
00953           else
00954             {
00955               _DBUS_ASSERT_ERROR_IS_SET (&error);
00956 
00957               _dbus_verbose ("%s: Error loading keyring: %s\n",
00958                              DBUS_AUTH_NAME (auth), error.message);
00959               
00960               if (send_error (auth, "Could not load cookie file"))
00961                 retval = TRUE; /* retval is only about mem */
00962               
00963               dbus_error_free (&error);
00964               goto out_3;
00965             }
00966         }
00967       else
00968         {
00969           _dbus_assert (!dbus_error_is_set (&error));
00970         }
00971     }
00972   
00973   _dbus_assert (auth->keyring != NULL);
00974   
00975   if (!_dbus_string_init (&tmp))
00976     goto out_3;
00977   
00978   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00979     goto out_4;
00980 
00981   if (!_dbus_string_init (&client_challenge))
00982     goto out_4;
00983 
00984   if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00985     goto out_5;
00986 
00987   if (!_dbus_string_init (&correct_hash))
00988     goto out_5;
00989   
00990   if (!sha1_compute_hash (auth, val,
00991                           &server_challenge,
00992                           &client_challenge,
00993                           &correct_hash))
00994     goto out_6;
00995 
00996   if (_dbus_string_get_length (&correct_hash) == 0)
00997     {
00998       /* couldn't find the cookie ID or something */
00999       if (send_error (auth, "Don't have the requested cookie ID"))
01000         retval = TRUE;
01001       goto out_6;
01002     }
01003   
01004   _dbus_string_set_length (&tmp, 0);
01005   
01006   if (!_dbus_string_copy (&client_challenge, 0, &tmp,
01007                           _dbus_string_get_length (&tmp)))
01008     goto out_6;
01009 
01010   if (!_dbus_string_append (&tmp, " "))
01011     goto out_6;
01012 
01013   if (!_dbus_string_copy (&correct_hash, 0, &tmp,
01014                           _dbus_string_get_length (&tmp)))
01015     goto out_6;
01016 
01017   if (!send_data (auth, &tmp))
01018     goto out_6;
01019 
01020   retval = TRUE;
01021 
01022  out_6:
01023   _dbus_string_zero (&correct_hash);
01024   _dbus_string_free (&correct_hash);
01025  out_5:
01026   _dbus_string_free (&client_challenge);
01027  out_4:
01028   _dbus_string_zero (&tmp);
01029   _dbus_string_free (&tmp);
01030  out_3:
01031   _dbus_string_free (&server_challenge);
01032  out_2:
01033   _dbus_string_free (&cookie_id_str);
01034  out_1:
01035   _dbus_string_free (&context);
01036  out_0:
01037   return retval;
01038 }
01039 
01040 static void
01041 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
01042 {
01043   auth->cookie_id = -1;  
01044   _dbus_string_set_length (&auth->challenge, 0);
01045 }
01046 
01047 /*
01048  * EXTERNAL mechanism
01049  */
01050 
01051 static dbus_bool_t
01052 handle_server_data_external_mech (DBusAuth         *auth,
01053                                   const DBusString *data)
01054 {
01055   if (_dbus_credentials_are_anonymous (auth->credentials))
01056     {
01057       _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
01058                      DBUS_AUTH_NAME (auth));
01059       return send_rejected (auth);
01060     }
01061   
01062   if (_dbus_string_get_length (data) > 0)
01063     {
01064       if (_dbus_string_get_length (&auth->identity) > 0)
01065         {
01066           /* Tried to send two auth identities, wtf */
01067           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
01068                          DBUS_AUTH_NAME (auth));
01069           return send_rejected (auth);
01070         }
01071       else
01072         {
01073           /* this is our auth identity */
01074           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
01075             return FALSE;
01076         }
01077     }
01078 
01079   /* Poke client for an auth identity, if none given */
01080   if (_dbus_string_get_length (&auth->identity) == 0 &&
01081       !auth->already_asked_for_initial_response)
01082     {
01083       if (send_data (auth, NULL))
01084         {
01085           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01086                          DBUS_AUTH_NAME (auth));
01087           auth->already_asked_for_initial_response = TRUE;
01088           goto_state (auth, &server_state_waiting_for_data);
01089           return TRUE;
01090         }
01091       else
01092         return FALSE;
01093     }
01094 
01095   _dbus_credentials_clear (auth->desired_identity);
01096   
01097   /* If auth->identity is still empty here, then client
01098    * responded with an empty string after we poked it for
01099    * an initial response. This means to try to auth the
01100    * identity provided in the credentials.
01101    */
01102   if (_dbus_string_get_length (&auth->identity) == 0)
01103     {
01104       if (!_dbus_credentials_add_credentials (auth->desired_identity,
01105                                               auth->credentials))
01106         {
01107           return FALSE; /* OOM */
01108         }
01109     }
01110   else
01111     {
01112       if (!_dbus_credentials_add_from_user (auth->desired_identity,
01113                                             &auth->identity))
01114         {
01115           _dbus_verbose ("%s: could not get credentials from uid string\n",
01116                          DBUS_AUTH_NAME (auth));
01117           return send_rejected (auth);
01118         }
01119     }
01120 
01121   if (_dbus_credentials_are_anonymous (auth->desired_identity))
01122     {
01123       _dbus_verbose ("%s: desired user %s is no good\n",
01124                      DBUS_AUTH_NAME (auth),
01125                      _dbus_string_get_const_data (&auth->identity));
01126       return send_rejected (auth);
01127     }
01128   
01129   if (_dbus_credentials_are_superset (auth->credentials,
01130                                       auth->desired_identity))
01131     {
01132       /* client has authenticated */
01133       if (!_dbus_credentials_add_credentials (auth->authorized_identity,
01134                                               auth->desired_identity))
01135         return FALSE;
01136 
01137       /* also copy process ID from the socket credentials
01138        */
01139       if (!_dbus_credentials_add_credential (auth->authorized_identity,
01140                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01141                                              auth->credentials))
01142         return FALSE;
01143 
01144       /* also copy audit data from the socket credentials
01145        */
01146       if (!_dbus_credentials_add_credential (auth->authorized_identity,
01147                                              DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
01148                                              auth->credentials))
01149         return FALSE;
01150       
01151       if (!send_ok (auth))
01152         return FALSE;
01153 
01154       _dbus_verbose ("%s: authenticated client based on socket credentials\n",
01155                      DBUS_AUTH_NAME (auth));
01156 
01157       return TRUE;
01158     }
01159   else
01160     {
01161       _dbus_verbose ("%s: desired identity not found in socket credentials\n",
01162                      DBUS_AUTH_NAME (auth));
01163       return send_rejected (auth);
01164     }
01165 }
01166 
01167 static void
01168 handle_server_shutdown_external_mech (DBusAuth *auth)
01169 {
01170 
01171 }
01172 
01173 static dbus_bool_t
01174 handle_client_initial_response_external_mech (DBusAuth         *auth,
01175                                               DBusString       *response)
01176 {
01177   /* We always append our UID as an initial response, so the server
01178    * doesn't have to send back an empty challenge to check whether we
01179    * want to specify an identity. i.e. this avoids a round trip that
01180    * the spec for the EXTERNAL mechanism otherwise requires.
01181    */
01182   DBusString plaintext;
01183 
01184   if (!_dbus_string_init (&plaintext))
01185     return FALSE;
01186 
01187   if (!_dbus_append_user_from_current_process (&plaintext))
01188     goto failed;
01189 
01190   if (!_dbus_string_hex_encode (&plaintext, 0,
01191                                 response,
01192                                 _dbus_string_get_length (response)))
01193     goto failed;
01194 
01195   _dbus_string_free (&plaintext);
01196   
01197   return TRUE;
01198 
01199  failed:
01200   _dbus_string_free (&plaintext);
01201   return FALSE;  
01202 }
01203 
01204 static dbus_bool_t
01205 handle_client_data_external_mech (DBusAuth         *auth,
01206                                   const DBusString *data)
01207 {
01208   
01209   return TRUE;
01210 }
01211 
01212 static void
01213 handle_client_shutdown_external_mech (DBusAuth *auth)
01214 {
01215 
01216 }
01217 
01218 /*
01219  * ANONYMOUS mechanism
01220  */
01221 
01222 static dbus_bool_t
01223 handle_server_data_anonymous_mech (DBusAuth         *auth,
01224                                    const DBusString *data)
01225 {  
01226   if (_dbus_string_get_length (data) > 0)
01227     {
01228       /* Client is allowed to send "trace" data, the only defined
01229        * meaning is that if it contains '@' it is an email address,
01230        * and otherwise it is anything else, and it's supposed to be
01231        * UTF-8
01232        */
01233       if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
01234         {
01235           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
01236                          DBUS_AUTH_NAME (auth));
01237           return send_rejected (auth);
01238         }
01239       
01240       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
01241                      DBUS_AUTH_NAME (auth),
01242                      _dbus_string_get_const_data (data));
01243     }
01244 
01245   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
01246   _dbus_credentials_clear (auth->desired_identity);
01247 
01248   /* Copy process ID from the socket credentials
01249    */
01250   if (!_dbus_credentials_add_credential (auth->authorized_identity,
01251                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01252                                          auth->credentials))
01253     return FALSE;
01254   
01255   /* Anonymous is always allowed */
01256   if (!send_ok (auth))
01257     return FALSE;
01258 
01259   _dbus_verbose ("%s: authenticated client as anonymous\n",
01260                  DBUS_AUTH_NAME (auth));
01261 
01262   return TRUE;
01263 }
01264 
01265 static void
01266 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
01267 {
01268   
01269 }
01270 
01271 static dbus_bool_t
01272 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
01273                                                DBusString       *response)
01274 {
01275   /* Our initial response is a "trace" string which must be valid UTF-8
01276    * and must be an email address if it contains '@'.
01277    * We just send the dbus implementation info, like a user-agent or
01278    * something, because... why not. There's nothing guaranteed here
01279    * though, we could change it later.
01280    */
01281   DBusString plaintext;
01282 
01283   if (!_dbus_string_init (&plaintext))
01284     return FALSE;
01285 
01286   if (!_dbus_string_append (&plaintext,
01287                             "libdbus " DBUS_VERSION_STRING))
01288     goto failed;
01289 
01290   if (!_dbus_string_hex_encode (&plaintext, 0,
01291                                 response,
01292                                 _dbus_string_get_length (response)))
01293     goto failed;
01294 
01295   _dbus_string_free (&plaintext);
01296   
01297   return TRUE;
01298 
01299  failed:
01300   _dbus_string_free (&plaintext);
01301   return FALSE;  
01302 }
01303 
01304 static dbus_bool_t
01305 handle_client_data_anonymous_mech (DBusAuth         *auth,
01306                                   const DBusString *data)
01307 {
01308   
01309   return TRUE;
01310 }
01311 
01312 static void
01313 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
01314 {
01315   
01316 }
01317 
01318 /* Put mechanisms here in order of preference.
01319  * Right now we have:
01320  *
01321  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
01322  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
01323  * - ANONYMOUS checks nothing but doesn't auth the person as a user
01324  *
01325  * We might ideally add a mechanism to chain to Cyrus SASL so we can
01326  * use its mechanisms as well.
01327  * 
01328  */
01329 static const DBusAuthMechanismHandler
01330 all_mechanisms[] = {
01331   { "EXTERNAL",
01332     handle_server_data_external_mech,
01333     NULL, NULL,
01334     handle_server_shutdown_external_mech,
01335     handle_client_initial_response_external_mech,
01336     handle_client_data_external_mech,
01337     NULL, NULL,
01338     handle_client_shutdown_external_mech },
01339   { "DBUS_COOKIE_SHA1",
01340     handle_server_data_cookie_sha1_mech,
01341     NULL, NULL,
01342     handle_server_shutdown_cookie_sha1_mech,
01343     handle_client_initial_response_cookie_sha1_mech,
01344     handle_client_data_cookie_sha1_mech,
01345     NULL, NULL,
01346     handle_client_shutdown_cookie_sha1_mech },
01347   { "ANONYMOUS",
01348     handle_server_data_anonymous_mech,
01349     NULL, NULL,
01350     handle_server_shutdown_anonymous_mech,
01351     handle_client_initial_response_anonymous_mech,
01352     handle_client_data_anonymous_mech,
01353     NULL, NULL,
01354     handle_client_shutdown_anonymous_mech },  
01355   { NULL, NULL }
01356 };
01357 
01358 static const DBusAuthMechanismHandler*
01359 find_mech (const DBusString  *name,
01360            char             **allowed_mechs)
01361 {
01362   int i;
01363   
01364   if (allowed_mechs != NULL &&
01365       !_dbus_string_array_contains ((const char**) allowed_mechs,
01366                                     _dbus_string_get_const_data (name)))
01367     return NULL;
01368   
01369   i = 0;
01370   while (all_mechanisms[i].mechanism != NULL)
01371     {      
01372       if (_dbus_string_equal_c_str (name,
01373                                     all_mechanisms[i].mechanism))
01374 
01375         return &all_mechanisms[i];
01376       
01377       ++i;
01378     }
01379   
01380   return NULL;
01381 }
01382 
01383 static dbus_bool_t
01384 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01385 {
01386   DBusString auth_command;
01387 
01388   if (!_dbus_string_init (&auth_command))
01389     return FALSE;
01390       
01391   if (!_dbus_string_append (&auth_command,
01392                             "AUTH "))
01393     {
01394       _dbus_string_free (&auth_command);
01395       return FALSE;
01396     }  
01397   
01398   if (!_dbus_string_append (&auth_command,
01399                             mech->mechanism))
01400     {
01401       _dbus_string_free (&auth_command);
01402       return FALSE;
01403     }
01404 
01405   if (mech->client_initial_response_func != NULL)
01406     {
01407       if (!_dbus_string_append (&auth_command, " "))
01408         {
01409           _dbus_string_free (&auth_command);
01410           return FALSE;
01411         }
01412       
01413       if (!(* mech->client_initial_response_func) (auth, &auth_command))
01414         {
01415           _dbus_string_free (&auth_command);
01416           return FALSE;
01417         }
01418     }
01419   
01420   if (!_dbus_string_append (&auth_command,
01421                             "\r\n"))
01422     {
01423       _dbus_string_free (&auth_command);
01424       return FALSE;
01425     }
01426 
01427   if (!_dbus_string_copy (&auth_command, 0,
01428                           &auth->outgoing,
01429                           _dbus_string_get_length (&auth->outgoing)))
01430     {
01431       _dbus_string_free (&auth_command);
01432       return FALSE;
01433     }
01434 
01435   _dbus_string_free (&auth_command);
01436   shutdown_mech (auth);
01437   auth->mech = mech;      
01438   goto_state (auth, &client_state_waiting_for_data);
01439 
01440   return TRUE;
01441 }
01442 
01443 static dbus_bool_t
01444 send_data (DBusAuth *auth, DBusString *data)
01445 {
01446   int old_len;
01447 
01448   if (data == NULL || _dbus_string_get_length (data) == 0)
01449     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01450   else
01451     {
01452       old_len = _dbus_string_get_length (&auth->outgoing);
01453       if (!_dbus_string_append (&auth->outgoing, "DATA "))
01454         goto out;
01455 
01456       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01457                                     _dbus_string_get_length (&auth->outgoing)))
01458         goto out;
01459 
01460       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01461         goto out;
01462 
01463       return TRUE;
01464 
01465     out:
01466       _dbus_string_set_length (&auth->outgoing, old_len);
01467 
01468       return FALSE;
01469     }
01470 }
01471 
01472 static dbus_bool_t
01473 send_rejected (DBusAuth *auth)
01474 {
01475   DBusString command;
01476   DBusAuthServer *server_auth;
01477   int i;
01478   
01479   if (!_dbus_string_init (&command))
01480     return FALSE;
01481   
01482   if (!_dbus_string_append (&command,
01483                             "REJECTED"))
01484     goto nomem;
01485 
01486   i = 0;
01487   while (all_mechanisms[i].mechanism != NULL)
01488     {
01489       if (!_dbus_string_append (&command,
01490                                 " "))
01491         goto nomem;
01492 
01493       if (!_dbus_string_append (&command,
01494                                 all_mechanisms[i].mechanism))
01495         goto nomem;
01496       
01497       ++i;
01498     }
01499   
01500   if (!_dbus_string_append (&command, "\r\n"))
01501     goto nomem;
01502 
01503   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01504                           _dbus_string_get_length (&auth->outgoing)))
01505     goto nomem;
01506 
01507   shutdown_mech (auth);
01508   
01509   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01510   server_auth = DBUS_AUTH_SERVER (auth);
01511   server_auth->failures += 1;
01512 
01513   if (server_auth->failures >= server_auth->max_failures)
01514     goto_state (auth, &common_state_need_disconnect);
01515   else
01516     goto_state (auth, &server_state_waiting_for_auth);
01517 
01518   _dbus_string_free (&command);
01519   
01520   return TRUE;
01521 
01522  nomem:
01523   _dbus_string_free (&command);
01524   return FALSE;
01525 }
01526 
01527 static dbus_bool_t
01528 send_error (DBusAuth *auth, const char *message)
01529 {
01530   return _dbus_string_append_printf (&auth->outgoing,
01531                                      "ERROR \"%s\"\r\n", message);
01532 }
01533 
01534 static dbus_bool_t
01535 send_ok (DBusAuth *auth)
01536 {
01537   int orig_len;
01538 
01539   orig_len = _dbus_string_get_length (&auth->outgoing);
01540   
01541   if (_dbus_string_append (&auth->outgoing, "OK ") &&
01542       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01543                          0,
01544                          &auth->outgoing,
01545                          _dbus_string_get_length (&auth->outgoing)) &&
01546       _dbus_string_append (&auth->outgoing, "\r\n"))
01547     {
01548       goto_state (auth, &server_state_waiting_for_begin);
01549       return TRUE;
01550     }
01551   else
01552     {
01553       _dbus_string_set_length (&auth->outgoing, orig_len);
01554       return FALSE;
01555     }
01556 }
01557 
01558 static dbus_bool_t
01559 send_begin (DBusAuth         *auth)
01560 {
01561 
01562   if (!_dbus_string_append (&auth->outgoing,
01563                             "BEGIN\r\n"))
01564     return FALSE;
01565 
01566   goto_state (auth, &common_state_authenticated);
01567   return TRUE;
01568 }
01569 
01570 static dbus_bool_t
01571 process_ok(DBusAuth *auth,
01572           const DBusString *args_from_ok) {
01573 
01574   int end_of_hex;
01575   
01576   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
01577   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01578 
01579   /* We decode the hex string to binary, using guid_from_server as scratch... */
01580   
01581   end_of_hex = 0;
01582   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01583                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01584     return FALSE;
01585 
01586   /* now clear out the scratch */
01587   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01588   
01589   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01590       end_of_hex == 0)
01591     {
01592       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01593                      end_of_hex, _dbus_string_get_length (args_from_ok));
01594       goto_state (auth, &common_state_need_disconnect);
01595       return TRUE;
01596     }
01597 
01598   if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
01599       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01600       return FALSE;
01601   }
01602 
01603   _dbus_verbose ("Got GUID '%s' from the server\n",
01604                  _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01605 
01606   if (auth->unix_fd_possible)
01607     return send_negotiate_unix_fd(auth);
01608 
01609   _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
01610   return send_begin (auth);
01611 }
01612 
01613 static dbus_bool_t
01614 send_cancel (DBusAuth *auth)
01615 {
01616   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01617     {
01618       goto_state (auth, &client_state_waiting_for_reject);
01619       return TRUE;
01620     }
01621   else
01622     return FALSE;
01623 }
01624 
01625 static dbus_bool_t
01626 process_data (DBusAuth             *auth,
01627               const DBusString     *args,
01628               DBusAuthDataFunction  data_func)
01629 {
01630   int end;
01631   DBusString decoded;
01632 
01633   if (!_dbus_string_init (&decoded))
01634     return FALSE;
01635 
01636   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01637     {
01638       _dbus_string_free (&decoded);
01639       return FALSE;
01640     }
01641 
01642   if (_dbus_string_get_length (args) != end)
01643     {
01644       _dbus_string_free (&decoded);
01645       if (!send_error (auth, "Invalid hex encoding"))
01646         return FALSE;
01647 
01648       return TRUE;
01649     }
01650 
01651 #ifdef DBUS_ENABLE_VERBOSE_MODE
01652   if (_dbus_string_validate_ascii (&decoded, 0,
01653                                    _dbus_string_get_length (&decoded)))
01654     _dbus_verbose ("%s: data: '%s'\n",
01655                    DBUS_AUTH_NAME (auth),
01656                    _dbus_string_get_const_data (&decoded));
01657 #endif
01658       
01659   if (!(* data_func) (auth, &decoded))
01660     {
01661       _dbus_string_free (&decoded);
01662       return FALSE;
01663     }
01664 
01665   _dbus_string_free (&decoded);
01666   return TRUE;
01667 }
01668 
01669 static dbus_bool_t
01670 send_negotiate_unix_fd (DBusAuth *auth)
01671 {
01672   if (!_dbus_string_append (&auth->outgoing,
01673                             "NEGOTIATE_UNIX_FD\r\n"))
01674     return FALSE;
01675 
01676   goto_state (auth, &client_state_waiting_for_agree_unix_fd);
01677   return TRUE;
01678 }
01679 
01680 static dbus_bool_t
01681 send_agree_unix_fd (DBusAuth *auth)
01682 {
01683   _dbus_assert(auth->unix_fd_possible);
01684 
01685   auth->unix_fd_negotiated = TRUE;
01686   _dbus_verbose("Agreed to UNIX FD passing\n");
01687 
01688   if (!_dbus_string_append (&auth->outgoing,
01689                             "AGREE_UNIX_FD\r\n"))
01690     return FALSE;
01691 
01692   goto_state (auth, &server_state_waiting_for_begin);
01693   return TRUE;
01694 }
01695 
01696 static dbus_bool_t
01697 handle_auth (DBusAuth *auth, const DBusString *args)
01698 {
01699   if (_dbus_string_get_length (args) == 0)
01700     {
01701       /* No args to the auth, send mechanisms */
01702       if (!send_rejected (auth))
01703         return FALSE;
01704 
01705       return TRUE;
01706     }
01707   else
01708     {
01709       int i;
01710       DBusString mech;
01711       DBusString hex_response;
01712       
01713       _dbus_string_find_blank (args, 0, &i);
01714 
01715       if (!_dbus_string_init (&mech))
01716         return FALSE;
01717 
01718       if (!_dbus_string_init (&hex_response))
01719         {
01720           _dbus_string_free (&mech);
01721           return FALSE;
01722         }
01723       
01724       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01725         goto failed;
01726 
01727       _dbus_string_skip_blank (args, i, &i);
01728       if (!_dbus_string_copy (args, i, &hex_response, 0))
01729         goto failed;
01730      
01731       auth->mech = find_mech (&mech, auth->allowed_mechs);
01732       if (auth->mech != NULL)
01733         {
01734           _dbus_verbose ("%s: Trying mechanism %s\n",
01735                          DBUS_AUTH_NAME (auth),
01736                          auth->mech->mechanism);
01737           
01738           if (!process_data (auth, &hex_response,
01739                              auth->mech->server_data_func))
01740             goto failed;
01741         }
01742       else
01743         {
01744           /* Unsupported mechanism */
01745           _dbus_verbose ("%s: Unsupported mechanism %s\n",
01746                          DBUS_AUTH_NAME (auth),
01747                          _dbus_string_get_const_data (&mech));
01748           
01749           if (!send_rejected (auth))
01750             goto failed;
01751         }
01752 
01753       _dbus_string_free (&mech);      
01754       _dbus_string_free (&hex_response);
01755 
01756       return TRUE;
01757       
01758     failed:
01759       auth->mech = NULL;
01760       _dbus_string_free (&mech);
01761       _dbus_string_free (&hex_response);
01762       return FALSE;
01763     }
01764 }
01765 
01766 static dbus_bool_t
01767 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
01768                                        DBusAuthCommand   command,
01769                                        const DBusString *args)
01770 {
01771   switch (command)
01772     {
01773     case DBUS_AUTH_COMMAND_AUTH:
01774       return handle_auth (auth, args);
01775 
01776     case DBUS_AUTH_COMMAND_CANCEL:
01777     case DBUS_AUTH_COMMAND_DATA:
01778       return send_error (auth, "Not currently in an auth conversation");
01779 
01780     case DBUS_AUTH_COMMAND_BEGIN:
01781       goto_state (auth, &common_state_need_disconnect);
01782       return TRUE;
01783 
01784     case DBUS_AUTH_COMMAND_ERROR:
01785       return send_rejected (auth);
01786 
01787     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01788       return send_error (auth, "Need to authenticate first");
01789 
01790     case DBUS_AUTH_COMMAND_REJECTED:
01791     case DBUS_AUTH_COMMAND_OK:
01792     case DBUS_AUTH_COMMAND_UNKNOWN:
01793     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
01794     default:
01795       return send_error (auth, "Unknown command");
01796     }
01797 }
01798 
01799 static dbus_bool_t
01800 handle_server_state_waiting_for_data  (DBusAuth         *auth,
01801                                        DBusAuthCommand   command,
01802                                        const DBusString *args)
01803 {
01804   switch (command)
01805     {
01806     case DBUS_AUTH_COMMAND_AUTH:
01807       return send_error (auth, "Sent AUTH while another AUTH in progress");
01808 
01809     case DBUS_AUTH_COMMAND_CANCEL:
01810     case DBUS_AUTH_COMMAND_ERROR:
01811       return send_rejected (auth);
01812 
01813     case DBUS_AUTH_COMMAND_DATA:
01814       return process_data (auth, args, auth->mech->server_data_func);
01815 
01816     case DBUS_AUTH_COMMAND_BEGIN:
01817       goto_state (auth, &common_state_need_disconnect);
01818       return TRUE;
01819 
01820     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01821       return send_error (auth, "Need to authenticate first");
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 }
01831 
01832 static dbus_bool_t
01833 handle_server_state_waiting_for_begin (DBusAuth         *auth,
01834                                        DBusAuthCommand   command,
01835                                        const DBusString *args)
01836 {
01837   switch (command)
01838     {
01839     case DBUS_AUTH_COMMAND_AUTH:
01840       return send_error (auth, "Sent AUTH while expecting BEGIN");
01841 
01842     case DBUS_AUTH_COMMAND_DATA:
01843       return send_error (auth, "Sent DATA while expecting BEGIN");
01844 
01845     case DBUS_AUTH_COMMAND_BEGIN:
01846       goto_state (auth, &common_state_authenticated);
01847       return TRUE;
01848 
01849     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01850       if (auth->unix_fd_possible)
01851         return send_agree_unix_fd(auth);
01852       else
01853         return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
01854 
01855     case DBUS_AUTH_COMMAND_REJECTED:
01856     case DBUS_AUTH_COMMAND_OK:
01857     case DBUS_AUTH_COMMAND_UNKNOWN:
01858     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
01859     default:
01860       return send_error (auth, "Unknown command");
01861 
01862     case DBUS_AUTH_COMMAND_CANCEL:
01863     case DBUS_AUTH_COMMAND_ERROR:
01864       return send_rejected (auth);
01865     }
01866 }
01867 
01868 /* return FALSE if no memory, TRUE if all OK */
01869 static dbus_bool_t
01870 get_word (const DBusString *str,
01871           int              *start,
01872           DBusString       *word)
01873 {
01874   int i;
01875 
01876   _dbus_string_skip_blank (str, *start, start);
01877   _dbus_string_find_blank (str, *start, &i);
01878   
01879   if (i > *start)
01880     {
01881       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01882         return FALSE;
01883       
01884       *start = i;
01885     }
01886 
01887   return TRUE;
01888 }
01889 
01890 static dbus_bool_t
01891 record_mechanisms (DBusAuth         *auth,
01892                    const DBusString *args)
01893 {
01894   int next;
01895   int len;
01896 
01897   if (auth->already_got_mechanisms)
01898     return TRUE;
01899   
01900   len = _dbus_string_get_length (args);
01901   
01902   next = 0;
01903   while (next < len)
01904     {
01905       DBusString m;
01906       const DBusAuthMechanismHandler *mech;
01907       
01908       if (!_dbus_string_init (&m))
01909         goto nomem;
01910       
01911       if (!get_word (args, &next, &m))
01912         {
01913           _dbus_string_free (&m);
01914           goto nomem;
01915         }
01916 
01917       mech = find_mech (&m, auth->allowed_mechs);
01918 
01919       if (mech != NULL)
01920         {
01921           /* FIXME right now we try mechanisms in the order
01922            * the server lists them; should we do them in
01923            * some more deterministic order?
01924            *
01925            * Probably in all_mechanisms order, our order of
01926            * preference. Of course when the server is us,
01927            * it lists things in that order anyhow.
01928            */
01929 
01930           if (mech != &all_mechanisms[0])
01931             {
01932               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01933                              DBUS_AUTH_NAME (auth), mech->mechanism);
01934           
01935               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01936                                       (void*) mech))
01937                 {
01938                   _dbus_string_free (&m);
01939                   goto nomem;
01940                 }
01941             }
01942           else
01943             {
01944               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
01945                              DBUS_AUTH_NAME (auth), mech->mechanism);
01946             }
01947         }
01948       else
01949         {
01950           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01951                          DBUS_AUTH_NAME (auth),
01952                          _dbus_string_get_const_data (&m));
01953         }
01954 
01955       _dbus_string_free (&m);
01956     }
01957   
01958   auth->already_got_mechanisms = TRUE;
01959   
01960   return TRUE;
01961 
01962  nomem:
01963   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01964   
01965   return FALSE;
01966 }
01967 
01968 static dbus_bool_t
01969 process_rejected (DBusAuth *auth, const DBusString *args)
01970 {
01971   const DBusAuthMechanismHandler *mech;
01972   DBusAuthClient *client;
01973 
01974   client = DBUS_AUTH_CLIENT (auth);
01975 
01976   if (!auth->already_got_mechanisms)
01977     {
01978       if (!record_mechanisms (auth, args))
01979         return FALSE;
01980     }
01981   
01982   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01983     {
01984       mech = client->mechs_to_try->data;
01985 
01986       if (!send_auth (auth, mech))
01987         return FALSE;
01988 
01989       _dbus_list_pop_first (&client->mechs_to_try);
01990 
01991       _dbus_verbose ("%s: Trying mechanism %s\n",
01992                      DBUS_AUTH_NAME (auth),
01993                      mech->mechanism);
01994     }
01995   else
01996     {
01997       /* Give up */
01998       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01999                      DBUS_AUTH_NAME (auth));
02000       goto_state (auth, &common_state_need_disconnect);
02001     }
02002   
02003   return TRUE;
02004 }
02005 
02006 
02007 static dbus_bool_t
02008 handle_client_state_waiting_for_data (DBusAuth         *auth,
02009                                       DBusAuthCommand   command,
02010                                       const DBusString *args)
02011 {
02012   _dbus_assert (auth->mech != NULL);
02013  
02014   switch (command)
02015     {
02016     case DBUS_AUTH_COMMAND_DATA:
02017       return process_data (auth, args, auth->mech->client_data_func);
02018 
02019     case DBUS_AUTH_COMMAND_REJECTED:
02020       return process_rejected (auth, args);
02021 
02022     case DBUS_AUTH_COMMAND_OK:
02023       return process_ok(auth, args);
02024 
02025     case DBUS_AUTH_COMMAND_ERROR:
02026       return send_cancel (auth);
02027 
02028     case DBUS_AUTH_COMMAND_AUTH:
02029     case DBUS_AUTH_COMMAND_CANCEL:
02030     case DBUS_AUTH_COMMAND_BEGIN:
02031     case DBUS_AUTH_COMMAND_UNKNOWN:
02032     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02033     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02034     default:
02035       return send_error (auth, "Unknown command");
02036     }
02037 }
02038 
02039 static dbus_bool_t
02040 handle_client_state_waiting_for_ok (DBusAuth         *auth,
02041                                     DBusAuthCommand   command,
02042                                     const DBusString *args)
02043 {
02044   switch (command)
02045     {
02046     case DBUS_AUTH_COMMAND_REJECTED:
02047       return process_rejected (auth, args);
02048 
02049     case DBUS_AUTH_COMMAND_OK:
02050       return process_ok(auth, args);
02051 
02052     case DBUS_AUTH_COMMAND_DATA:
02053     case DBUS_AUTH_COMMAND_ERROR:
02054       return send_cancel (auth);
02055 
02056     case DBUS_AUTH_COMMAND_AUTH:
02057     case DBUS_AUTH_COMMAND_CANCEL:
02058     case DBUS_AUTH_COMMAND_BEGIN:
02059     case DBUS_AUTH_COMMAND_UNKNOWN:
02060     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02061     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02062     default:
02063       return send_error (auth, "Unknown command");
02064     }
02065 }
02066 
02067 static dbus_bool_t
02068 handle_client_state_waiting_for_reject (DBusAuth         *auth,
02069                                         DBusAuthCommand   command,
02070                                         const DBusString *args)
02071 {
02072   switch (command)
02073     {
02074     case DBUS_AUTH_COMMAND_REJECTED:
02075       return process_rejected (auth, args);
02076       
02077     case DBUS_AUTH_COMMAND_AUTH:
02078     case DBUS_AUTH_COMMAND_CANCEL:
02079     case DBUS_AUTH_COMMAND_DATA:
02080     case DBUS_AUTH_COMMAND_BEGIN:
02081     case DBUS_AUTH_COMMAND_OK:
02082     case DBUS_AUTH_COMMAND_ERROR:
02083     case DBUS_AUTH_COMMAND_UNKNOWN:
02084     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02085     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02086     default:
02087       goto_state (auth, &common_state_need_disconnect);
02088       return TRUE;
02089     }
02090 }
02091 
02092 static dbus_bool_t
02093 handle_client_state_waiting_for_agree_unix_fd(DBusAuth         *auth,
02094                                               DBusAuthCommand   command,
02095                                               const DBusString *args)
02096 {
02097   switch (command)
02098     {
02099     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02100       _dbus_assert(auth->unix_fd_possible);
02101       auth->unix_fd_negotiated = TRUE;
02102       _dbus_verbose("Successfully negotiated UNIX FD passing\n");
02103       return send_begin (auth);
02104 
02105     case DBUS_AUTH_COMMAND_ERROR:
02106       _dbus_assert(auth->unix_fd_possible);
02107       auth->unix_fd_negotiated = FALSE;
02108       _dbus_verbose("Failed to negotiate UNIX FD passing\n");
02109       return send_begin (auth);
02110 
02111     case DBUS_AUTH_COMMAND_OK:
02112     case DBUS_AUTH_COMMAND_DATA:
02113     case DBUS_AUTH_COMMAND_REJECTED:
02114     case DBUS_AUTH_COMMAND_AUTH:
02115     case DBUS_AUTH_COMMAND_CANCEL:
02116     case DBUS_AUTH_COMMAND_BEGIN:
02117     case DBUS_AUTH_COMMAND_UNKNOWN:
02118     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02119     default:
02120       return send_error (auth, "Unknown command");
02121     }
02122 }
02123 
02127 typedef struct {
02128   const char *name;        
02129   DBusAuthCommand command; 
02130 } DBusAuthCommandName;
02131 
02132 static const DBusAuthCommandName auth_command_names[] = {
02133   { "AUTH",              DBUS_AUTH_COMMAND_AUTH },
02134   { "CANCEL",            DBUS_AUTH_COMMAND_CANCEL },
02135   { "DATA",              DBUS_AUTH_COMMAND_DATA },
02136   { "BEGIN",             DBUS_AUTH_COMMAND_BEGIN },
02137   { "REJECTED",          DBUS_AUTH_COMMAND_REJECTED },
02138   { "OK",                DBUS_AUTH_COMMAND_OK },
02139   { "ERROR",             DBUS_AUTH_COMMAND_ERROR },
02140   { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
02141   { "AGREE_UNIX_FD",     DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
02142 };
02143 
02144 static DBusAuthCommand
02145 lookup_command_from_name (DBusString *command)
02146 {
02147   int i;
02148 
02149   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
02150     {
02151       if (_dbus_string_equal_c_str (command,
02152                                     auth_command_names[i].name))
02153         return auth_command_names[i].command;
02154     }
02155 
02156   return DBUS_AUTH_COMMAND_UNKNOWN;
02157 }
02158 
02159 static void
02160 goto_state (DBusAuth *auth,
02161             const DBusAuthStateData *state)
02162 {
02163   _dbus_verbose ("%s: going from state %s to state %s\n",
02164                  DBUS_AUTH_NAME (auth),
02165                  auth->state->name,
02166                  state->name);
02167 
02168   auth->state = state;
02169 }
02170 
02171 /* returns whether to call it again right away */
02172 static dbus_bool_t
02173 process_command (DBusAuth *auth)
02174 {
02175   DBusAuthCommand command;
02176   DBusString line;
02177   DBusString args;
02178   int eol;
02179   int i, j;
02180   dbus_bool_t retval;
02181 
02182   /* _dbus_verbose ("%s:   trying process_command()\n"); */
02183   
02184   retval = FALSE;
02185   
02186   eol = 0;
02187   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
02188     return FALSE;
02189   
02190   if (!_dbus_string_init (&line))
02191     {
02192       auth->needed_memory = TRUE;
02193       return FALSE;
02194     }
02195 
02196   if (!_dbus_string_init (&args))
02197     {
02198       _dbus_string_free (&line);
02199       auth->needed_memory = TRUE;
02200       return FALSE;
02201     }
02202   
02203   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
02204     goto out;
02205 
02206   if (!_dbus_string_validate_ascii (&line, 0,
02207                                     _dbus_string_get_length (&line)))
02208     {
02209       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
02210                      DBUS_AUTH_NAME (auth));
02211       if (!send_error (auth, "Command contained non-ASCII"))
02212         goto out;
02213       else
02214         goto next_command;
02215     }
02216   
02217   _dbus_verbose ("%s: got command \"%s\"\n",
02218                  DBUS_AUTH_NAME (auth),
02219                  _dbus_string_get_const_data (&line));
02220   
02221   _dbus_string_find_blank (&line, 0, &i);
02222   _dbus_string_skip_blank (&line, i, &j);
02223 
02224   if (j > i)
02225     _dbus_string_delete (&line, i, j - i);
02226   
02227   if (!_dbus_string_move (&line, i, &args, 0))
02228     goto out;
02229 
02230   /* FIXME 1.0 we should probably validate that only the allowed
02231    * chars are in the command name
02232    */
02233   
02234   command = lookup_command_from_name (&line);
02235   if (!(* auth->state->handler) (auth, command, &args))
02236     goto out;
02237 
02238  next_command:
02239   
02240   /* We've succeeded in processing the whole command so drop it out
02241    * of the incoming buffer and return TRUE to try another command.
02242    */
02243 
02244   _dbus_string_delete (&auth->incoming, 0, eol);
02245   
02246   /* kill the \r\n */
02247   _dbus_string_delete (&auth->incoming, 0, 2);
02248 
02249   retval = TRUE;
02250   
02251  out:
02252   _dbus_string_free (&args);
02253   _dbus_string_free (&line);
02254 
02255   if (!retval)
02256     auth->needed_memory = TRUE;
02257   else
02258     auth->needed_memory = FALSE;
02259   
02260   return retval;
02261 }
02262 
02263 
02278 DBusAuth*
02279 _dbus_auth_server_new (const DBusString *guid)
02280 {
02281   DBusAuth *auth;
02282   DBusAuthServer *server_auth;
02283   DBusString guid_copy;
02284 
02285   if (!_dbus_string_init (&guid_copy))
02286     return NULL;
02287 
02288   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
02289     {
02290       _dbus_string_free (&guid_copy);
02291       return NULL;
02292     }
02293 
02294   auth = _dbus_auth_new (sizeof (DBusAuthServer));
02295   if (auth == NULL)
02296     {
02297       _dbus_string_free (&guid_copy);
02298       return NULL;
02299     }
02300   
02301   auth->side = auth_side_server;
02302   auth->state = &server_state_waiting_for_auth;
02303 
02304   server_auth = DBUS_AUTH_SERVER (auth);
02305 
02306   server_auth->guid = guid_copy;
02307   
02308   /* perhaps this should be per-mechanism with a lower
02309    * max
02310    */
02311   server_auth->failures = 0;
02312   server_auth->max_failures = 6;
02313   
02314   return auth;
02315 }
02316 
02324 DBusAuth*
02325 _dbus_auth_client_new (void)
02326 {
02327   DBusAuth *auth;
02328   DBusString guid_str;
02329 
02330   if (!_dbus_string_init (&guid_str))
02331     return NULL;
02332 
02333   auth = _dbus_auth_new (sizeof (DBusAuthClient));
02334   if (auth == NULL)
02335     {
02336       _dbus_string_free (&guid_str);
02337       return NULL;
02338     }
02339 
02340   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02341 
02342   auth->side = auth_side_client;
02343   auth->state = &client_state_need_send_auth;
02344 
02345   /* Start the auth conversation by sending AUTH for our default
02346    * mechanism */
02347   if (!send_auth (auth, &all_mechanisms[0]))
02348     {
02349       _dbus_auth_unref (auth);
02350       return NULL;
02351     }
02352   
02353   return auth;
02354 }
02355 
02362 DBusAuth *
02363 _dbus_auth_ref (DBusAuth *auth)
02364 {
02365   _dbus_assert (auth != NULL);
02366   
02367   auth->refcount += 1;
02368   
02369   return auth;
02370 }
02371 
02377 void
02378 _dbus_auth_unref (DBusAuth *auth)
02379 {
02380   _dbus_assert (auth != NULL);
02381   _dbus_assert (auth->refcount > 0);
02382 
02383   auth->refcount -= 1;
02384   if (auth->refcount == 0)
02385     {
02386       shutdown_mech (auth);
02387 
02388       if (DBUS_AUTH_IS_CLIENT (auth))
02389         {
02390           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02391           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02392         }
02393       else
02394         {
02395           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02396 
02397           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02398         }
02399 
02400       if (auth->keyring)
02401         _dbus_keyring_unref (auth->keyring);
02402 
02403       _dbus_string_free (&auth->context);
02404       _dbus_string_free (&auth->challenge);
02405       _dbus_string_free (&auth->identity);
02406       _dbus_string_free (&auth->incoming);
02407       _dbus_string_free (&auth->outgoing);
02408 
02409       dbus_free_string_array (auth->allowed_mechs);
02410 
02411       _dbus_credentials_unref (auth->credentials);
02412       _dbus_credentials_unref (auth->authorized_identity);
02413       _dbus_credentials_unref (auth->desired_identity);
02414       
02415       dbus_free (auth);
02416     }
02417 }
02418 
02427 dbus_bool_t
02428 _dbus_auth_set_mechanisms (DBusAuth    *auth,
02429                            const char **mechanisms)
02430 {
02431   char **copy;
02432 
02433   if (mechanisms != NULL)
02434     {
02435       copy = _dbus_dup_string_array (mechanisms);
02436       if (copy == NULL)
02437         return FALSE;
02438     }
02439   else
02440     copy = NULL;
02441   
02442   dbus_free_string_array (auth->allowed_mechs);
02443 
02444   auth->allowed_mechs = copy;
02445 
02446   return TRUE;
02447 }
02448 
02453 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02454 
02462 DBusAuthState
02463 _dbus_auth_do_work (DBusAuth *auth)
02464 {
02465   auth->needed_memory = FALSE;
02466 
02467   /* Max amount we'll buffer up before deciding someone's on crack */
02468 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02469 
02470   do
02471     {
02472       if (DBUS_AUTH_IN_END_STATE (auth))
02473         break;
02474       
02475       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02476           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02477         {
02478           goto_state (auth, &common_state_need_disconnect);
02479           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02480                          DBUS_AUTH_NAME (auth));
02481           break;
02482         }
02483     }
02484   while (process_command (auth));
02485 
02486   if (auth->needed_memory)
02487     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02488   else if (_dbus_string_get_length (&auth->outgoing) > 0)
02489     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02490   else if (auth->state == &common_state_need_disconnect)
02491     return DBUS_AUTH_STATE_NEED_DISCONNECT;
02492   else if (auth->state == &common_state_authenticated)
02493     return DBUS_AUTH_STATE_AUTHENTICATED;
02494   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02495 }
02496 
02506 dbus_bool_t
02507 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
02508                               const DBusString **str)
02509 {
02510   _dbus_assert (auth != NULL);
02511   _dbus_assert (str != NULL);
02512 
02513   *str = NULL;
02514   
02515   if (_dbus_string_get_length (&auth->outgoing) == 0)
02516     return FALSE;
02517 
02518   *str = &auth->outgoing;
02519 
02520   return TRUE;
02521 }
02522 
02531 void
02532 _dbus_auth_bytes_sent (DBusAuth *auth,
02533                        int       bytes_sent)
02534 {
02535   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02536                  DBUS_AUTH_NAME (auth),
02537                  bytes_sent,
02538                  _dbus_string_get_const_data (&auth->outgoing));
02539   
02540   _dbus_string_delete (&auth->outgoing,
02541                        0, bytes_sent);
02542 }
02543 
02551 void
02552 _dbus_auth_get_buffer (DBusAuth     *auth,
02553                        DBusString **buffer)
02554 {
02555   _dbus_assert (auth != NULL);
02556   _dbus_assert (!auth->buffer_outstanding);
02557   
02558   *buffer = &auth->incoming;
02559 
02560   auth->buffer_outstanding = TRUE;
02561 }
02562 
02570 void
02571 _dbus_auth_return_buffer (DBusAuth               *auth,
02572                           DBusString             *buffer,
02573                           int                     bytes_read)
02574 {
02575   _dbus_assert (buffer == &auth->incoming);
02576   _dbus_assert (auth->buffer_outstanding);
02577 
02578   auth->buffer_outstanding = FALSE;
02579 }
02580 
02590 void
02591 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
02592                              const DBusString **str)
02593 {
02594   if (!DBUS_AUTH_IN_END_STATE (auth))
02595     return;
02596 
02597   *str = &auth->incoming;
02598 }
02599 
02600 
02607 void
02608 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02609 {
02610   if (!DBUS_AUTH_IN_END_STATE (auth))
02611     return;
02612 
02613   _dbus_string_set_length (&auth->incoming, 0);
02614 }
02615 
02624 dbus_bool_t
02625 _dbus_auth_needs_encoding (DBusAuth *auth)
02626 {
02627   if (auth->state != &common_state_authenticated)
02628     return FALSE;
02629   
02630   if (auth->mech != NULL)
02631     {
02632       if (DBUS_AUTH_IS_CLIENT (auth))
02633         return auth->mech->client_encode_func != NULL;
02634       else
02635         return auth->mech->server_encode_func != NULL;
02636     }
02637   else
02638     return FALSE;
02639 }
02640 
02651 dbus_bool_t
02652 _dbus_auth_encode_data (DBusAuth         *auth,
02653                         const DBusString *plaintext,
02654                         DBusString       *encoded)
02655 {
02656   _dbus_assert (plaintext != encoded);
02657   
02658   if (auth->state != &common_state_authenticated)
02659     return FALSE;
02660   
02661   if (_dbus_auth_needs_encoding (auth))
02662     {
02663       if (DBUS_AUTH_IS_CLIENT (auth))
02664         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02665       else
02666         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02667     }
02668   else
02669     {
02670       return _dbus_string_copy (plaintext, 0, encoded,
02671                                 _dbus_string_get_length (encoded));
02672     }
02673 }
02674 
02683 dbus_bool_t
02684 _dbus_auth_needs_decoding (DBusAuth *auth)
02685 {
02686   if (auth->state != &common_state_authenticated)
02687     return FALSE;
02688     
02689   if (auth->mech != NULL)
02690     {
02691       if (DBUS_AUTH_IS_CLIENT (auth))
02692         return auth->mech->client_decode_func != NULL;
02693       else
02694         return auth->mech->server_decode_func != NULL;
02695     }
02696   else
02697     return FALSE;
02698 }
02699 
02700 
02714 dbus_bool_t
02715 _dbus_auth_decode_data (DBusAuth         *auth,
02716                         const DBusString *encoded,
02717                         DBusString       *plaintext)
02718 {
02719   _dbus_assert (plaintext != encoded);
02720   
02721   if (auth->state != &common_state_authenticated)
02722     return FALSE;
02723   
02724   if (_dbus_auth_needs_decoding (auth))
02725     {
02726       if (DBUS_AUTH_IS_CLIENT (auth))
02727         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02728       else
02729         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02730     }
02731   else
02732     {
02733       return _dbus_string_copy (encoded, 0, plaintext,
02734                                 _dbus_string_get_length (plaintext));
02735     }
02736 }
02737 
02746 dbus_bool_t
02747 _dbus_auth_set_credentials (DBusAuth               *auth,
02748                             DBusCredentials        *credentials)
02749 {
02750   _dbus_credentials_clear (auth->credentials);
02751   return _dbus_credentials_add_credentials (auth->credentials,
02752                                             credentials);
02753 }
02754 
02764 DBusCredentials*
02765 _dbus_auth_get_identity (DBusAuth               *auth)
02766 {
02767   if (auth->state == &common_state_authenticated)
02768     {
02769       return auth->authorized_identity;
02770     }
02771   else
02772     {
02773       /* FIXME instead of this, keep an empty credential around that
02774        * doesn't require allocation or something
02775        */
02776       /* return empty credentials */
02777       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
02778       return auth->authorized_identity;
02779     }
02780 }
02781 
02788 const char*
02789 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02790 {
02791   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02792   
02793   if (auth->state == &common_state_authenticated)
02794     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02795   else
02796     return NULL;
02797 }
02798 
02807 dbus_bool_t
02808 _dbus_auth_set_context (DBusAuth               *auth,
02809                         const DBusString       *context)
02810 {
02811   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02812                                    &auth->context, 0, _dbus_string_get_length (context));
02813 }
02814 
02822 void
02823 _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
02824 {
02825   auth->unix_fd_possible = b;
02826 }
02827 
02834 dbus_bool_t
02835 _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
02836 {
02837   return auth->unix_fd_negotiated;
02838 }
02839 
02842 /* tests in dbus-auth-util.c */