• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

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 
01206           {
01207             DBusString plaintext;
01208             DBusString encoded;
01209             _dbus_string_init_const (&plaintext, "D-Bus " DBUS_VERSION_STRING);
01210             _dbus_string_init (&encoded);
01211             _dbus_string_hex_encode (&plaintext, 0,
01212                                      &encoded,
01213                                      0);
01214               _dbus_verbose ("%s: try '%s'\n",
01215                              DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
01216           }
01217           return send_rejected (auth);
01218         }
01219       
01220       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
01221                      DBUS_AUTH_NAME (auth),
01222                      _dbus_string_get_const_data (data));
01223     }
01224 
01225   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
01226   _dbus_credentials_clear (auth->desired_identity);
01227 
01228   /* Copy process ID from the socket credentials
01229    */
01230   if (!_dbus_credentials_add_credential (auth->authorized_identity,
01231                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01232                                          auth->credentials))
01233     return FALSE;
01234   
01235   /* Anonymous is always allowed */
01236   if (!send_ok (auth))
01237     return FALSE;
01238 
01239   _dbus_verbose ("%s: authenticated client as anonymous\n",
01240                  DBUS_AUTH_NAME (auth));
01241 
01242   return TRUE;
01243 }
01244 
01245 static void
01246 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
01247 {
01248   
01249 }
01250 
01251 static dbus_bool_t
01252 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
01253                                                DBusString       *response)
01254 {
01255   /* Our initial response is a "trace" string which must be valid UTF-8
01256    * and must be an email address if it contains '@'.
01257    * We just send the dbus implementation info, like a user-agent or
01258    * something, because... why not. There's nothing guaranteed here
01259    * though, we could change it later.
01260    */
01261   DBusString plaintext;
01262 
01263   if (!_dbus_string_init (&plaintext))
01264     return FALSE;
01265 
01266   if (!_dbus_string_append (&plaintext,
01267                             "libdbus " DBUS_VERSION_STRING))
01268     goto failed;
01269 
01270   if (!_dbus_string_hex_encode (&plaintext, 0,
01271                                 response,
01272                                 _dbus_string_get_length (response)))
01273     goto failed;
01274 
01275   _dbus_string_free (&plaintext);
01276   
01277   return TRUE;
01278 
01279  failed:
01280   _dbus_string_free (&plaintext);
01281   return FALSE;  
01282 }
01283 
01284 static dbus_bool_t
01285 handle_client_data_anonymous_mech (DBusAuth         *auth,
01286                                   const DBusString *data)
01287 {
01288   
01289   return TRUE;
01290 }
01291 
01292 static void
01293 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
01294 {
01295   
01296 }
01297 
01298 /* Put mechanisms here in order of preference.
01299  * Right now we have:
01300  *
01301  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
01302  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
01303  * - ANONYMOUS checks nothing but doesn't auth the person as a user
01304  *
01305  * We might ideally add a mechanism to chain to Cyrus SASL so we can
01306  * use its mechanisms as well.
01307  * 
01308  */
01309 static const DBusAuthMechanismHandler
01310 all_mechanisms[] = {
01311   { "EXTERNAL",
01312     handle_server_data_external_mech,
01313     NULL, NULL,
01314     handle_server_shutdown_external_mech,
01315     handle_client_initial_response_external_mech,
01316     handle_client_data_external_mech,
01317     NULL, NULL,
01318     handle_client_shutdown_external_mech },
01319   { "DBUS_COOKIE_SHA1",
01320     handle_server_data_cookie_sha1_mech,
01321     NULL, NULL,
01322     handle_server_shutdown_cookie_sha1_mech,
01323     handle_client_initial_response_cookie_sha1_mech,
01324     handle_client_data_cookie_sha1_mech,
01325     NULL, NULL,
01326     handle_client_shutdown_cookie_sha1_mech },
01327   { "ANONYMOUS",
01328     handle_server_data_anonymous_mech,
01329     NULL, NULL,
01330     handle_server_shutdown_anonymous_mech,
01331     handle_client_initial_response_anonymous_mech,
01332     handle_client_data_anonymous_mech,
01333     NULL, NULL,
01334     handle_client_shutdown_anonymous_mech },  
01335   { NULL, NULL }
01336 };
01337 
01338 static const DBusAuthMechanismHandler*
01339 find_mech (const DBusString  *name,
01340            char             **allowed_mechs)
01341 {
01342   int i;
01343   
01344   if (allowed_mechs != NULL &&
01345       !_dbus_string_array_contains ((const char**) allowed_mechs,
01346                                     _dbus_string_get_const_data (name)))
01347     return NULL;
01348   
01349   i = 0;
01350   while (all_mechanisms[i].mechanism != NULL)
01351     {      
01352       if (_dbus_string_equal_c_str (name,
01353                                     all_mechanisms[i].mechanism))
01354 
01355         return &all_mechanisms[i];
01356       
01357       ++i;
01358     }
01359   
01360   return NULL;
01361 }
01362 
01363 static dbus_bool_t
01364 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01365 {
01366   DBusString auth_command;
01367 
01368   if (!_dbus_string_init (&auth_command))
01369     return FALSE;
01370       
01371   if (!_dbus_string_append (&auth_command,
01372                             "AUTH "))
01373     {
01374       _dbus_string_free (&auth_command);
01375       return FALSE;
01376     }  
01377   
01378   if (!_dbus_string_append (&auth_command,
01379                             mech->mechanism))
01380     {
01381       _dbus_string_free (&auth_command);
01382       return FALSE;
01383     }
01384 
01385   if (mech->client_initial_response_func != NULL)
01386     {
01387       if (!_dbus_string_append (&auth_command, " "))
01388         {
01389           _dbus_string_free (&auth_command);
01390           return FALSE;
01391         }
01392       
01393       if (!(* mech->client_initial_response_func) (auth, &auth_command))
01394         {
01395           _dbus_string_free (&auth_command);
01396           return FALSE;
01397         }
01398     }
01399   
01400   if (!_dbus_string_append (&auth_command,
01401                             "\r\n"))
01402     {
01403       _dbus_string_free (&auth_command);
01404       return FALSE;
01405     }
01406 
01407   if (!_dbus_string_copy (&auth_command, 0,
01408                           &auth->outgoing,
01409                           _dbus_string_get_length (&auth->outgoing)))
01410     {
01411       _dbus_string_free (&auth_command);
01412       return FALSE;
01413     }
01414 
01415   _dbus_string_free (&auth_command);
01416   shutdown_mech (auth);
01417   auth->mech = mech;      
01418   goto_state (auth, &client_state_waiting_for_data);
01419 
01420   return TRUE;
01421 }
01422 
01423 static dbus_bool_t
01424 send_data (DBusAuth *auth, DBusString *data)
01425 {
01426   int old_len;
01427 
01428   if (data == NULL || _dbus_string_get_length (data) == 0)
01429     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01430   else
01431     {
01432       old_len = _dbus_string_get_length (&auth->outgoing);
01433       if (!_dbus_string_append (&auth->outgoing, "DATA "))
01434         goto out;
01435 
01436       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01437                                     _dbus_string_get_length (&auth->outgoing)))
01438         goto out;
01439 
01440       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01441         goto out;
01442 
01443       return TRUE;
01444 
01445     out:
01446       _dbus_string_set_length (&auth->outgoing, old_len);
01447 
01448       return FALSE;
01449     }
01450 }
01451 
01452 static dbus_bool_t
01453 send_rejected (DBusAuth *auth)
01454 {
01455   DBusString command;
01456   DBusAuthServer *server_auth;
01457   int i;
01458   
01459   if (!_dbus_string_init (&command))
01460     return FALSE;
01461   
01462   if (!_dbus_string_append (&command,
01463                             "REJECTED"))
01464     goto nomem;
01465 
01466   i = 0;
01467   while (all_mechanisms[i].mechanism != NULL)
01468     {
01469       if (!_dbus_string_append (&command,
01470                                 " "))
01471         goto nomem;
01472 
01473       if (!_dbus_string_append (&command,
01474                                 all_mechanisms[i].mechanism))
01475         goto nomem;
01476       
01477       ++i;
01478     }
01479   
01480   if (!_dbus_string_append (&command, "\r\n"))
01481     goto nomem;
01482 
01483   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01484                           _dbus_string_get_length (&auth->outgoing)))
01485     goto nomem;
01486 
01487   shutdown_mech (auth);
01488   
01489   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01490   server_auth = DBUS_AUTH_SERVER (auth);
01491   server_auth->failures += 1;
01492 
01493   if (server_auth->failures >= server_auth->max_failures)
01494     goto_state (auth, &common_state_need_disconnect);
01495   else
01496     goto_state (auth, &server_state_waiting_for_auth);
01497 
01498   _dbus_string_free (&command);
01499   
01500   return TRUE;
01501 
01502  nomem:
01503   _dbus_string_free (&command);
01504   return FALSE;
01505 }
01506 
01507 static dbus_bool_t
01508 send_error (DBusAuth *auth, const char *message)
01509 {
01510   return _dbus_string_append_printf (&auth->outgoing,
01511                                      "ERROR \"%s\"\r\n", message);
01512 }
01513 
01514 static dbus_bool_t
01515 send_ok (DBusAuth *auth)
01516 {
01517   int orig_len;
01518 
01519   orig_len = _dbus_string_get_length (&auth->outgoing);
01520   
01521   if (_dbus_string_append (&auth->outgoing, "OK ") &&
01522       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01523                          0,
01524                          &auth->outgoing,
01525                          _dbus_string_get_length (&auth->outgoing)) &&
01526       _dbus_string_append (&auth->outgoing, "\r\n"))
01527     {
01528       goto_state (auth, &server_state_waiting_for_begin);
01529       return TRUE;
01530     }
01531   else
01532     {
01533       _dbus_string_set_length (&auth->outgoing, orig_len);
01534       return FALSE;
01535     }
01536 }
01537 
01538 static dbus_bool_t
01539 send_begin (DBusAuth         *auth)
01540 {
01541 
01542   if (!_dbus_string_append (&auth->outgoing,
01543                             "BEGIN\r\n"))
01544     return FALSE;
01545 
01546   goto_state (auth, &common_state_authenticated);
01547   return TRUE;
01548 }
01549 
01550 static dbus_bool_t
01551 process_ok(DBusAuth *auth,
01552           const DBusString *args_from_ok) {
01553 
01554   int end_of_hex;
01555   
01556   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
01557   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01558 
01559   /* We decode the hex string to binary, using guid_from_server as scratch... */
01560   
01561   end_of_hex = 0;
01562   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01563                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01564     return FALSE;
01565 
01566   /* now clear out the scratch */
01567   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01568   
01569   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01570       end_of_hex == 0)
01571     {
01572       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01573                      end_of_hex, _dbus_string_get_length (args_from_ok));
01574       goto_state (auth, &common_state_need_disconnect);
01575       return TRUE;
01576     }
01577 
01578   if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
01579       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01580       return FALSE;
01581   }
01582 
01583   _dbus_verbose ("Got GUID '%s' from the server\n",
01584                  _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01585 
01586   if (auth->unix_fd_possible)
01587     return send_negotiate_unix_fd(auth);
01588 
01589   _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
01590   return send_begin (auth);
01591 }
01592 
01593 static dbus_bool_t
01594 send_cancel (DBusAuth *auth)
01595 {
01596   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01597     {
01598       goto_state (auth, &client_state_waiting_for_reject);
01599       return TRUE;
01600     }
01601   else
01602     return FALSE;
01603 }
01604 
01605 static dbus_bool_t
01606 process_data (DBusAuth             *auth,
01607               const DBusString     *args,
01608               DBusAuthDataFunction  data_func)
01609 {
01610   int end;
01611   DBusString decoded;
01612 
01613   if (!_dbus_string_init (&decoded))
01614     return FALSE;
01615 
01616   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01617     {
01618       _dbus_string_free (&decoded);
01619       return FALSE;
01620     }
01621 
01622   if (_dbus_string_get_length (args) != end)
01623     {
01624       _dbus_string_free (&decoded);
01625       if (!send_error (auth, "Invalid hex encoding"))
01626         return FALSE;
01627 
01628       return TRUE;
01629     }
01630 
01631 #ifdef DBUS_ENABLE_VERBOSE_MODE
01632   if (_dbus_string_validate_ascii (&decoded, 0,
01633                                    _dbus_string_get_length (&decoded)))
01634     _dbus_verbose ("%s: data: '%s'\n",
01635                    DBUS_AUTH_NAME (auth),
01636                    _dbus_string_get_const_data (&decoded));
01637 #endif
01638       
01639   if (!(* data_func) (auth, &decoded))
01640     {
01641       _dbus_string_free (&decoded);
01642       return FALSE;
01643     }
01644 
01645   _dbus_string_free (&decoded);
01646   return TRUE;
01647 }
01648 
01649 static dbus_bool_t
01650 send_negotiate_unix_fd (DBusAuth *auth)
01651 {
01652   if (!_dbus_string_append (&auth->outgoing,
01653                             "NEGOTIATE_UNIX_FD\r\n"))
01654     return FALSE;
01655 
01656   goto_state (auth, &client_state_waiting_for_agree_unix_fd);
01657   return TRUE;
01658 }
01659 
01660 static dbus_bool_t
01661 send_agree_unix_fd (DBusAuth *auth)
01662 {
01663   _dbus_assert(auth->unix_fd_possible);
01664 
01665   auth->unix_fd_negotiated = TRUE;
01666   _dbus_verbose("Agreed to UNIX FD passing\n");
01667 
01668   if (!_dbus_string_append (&auth->outgoing,
01669                             "AGREE_UNIX_FD\r\n"))
01670     return FALSE;
01671 
01672   goto_state (auth, &server_state_waiting_for_begin);
01673   return TRUE;
01674 }
01675 
01676 static dbus_bool_t
01677 handle_auth (DBusAuth *auth, const DBusString *args)
01678 {
01679   if (_dbus_string_get_length (args) == 0)
01680     {
01681       /* No args to the auth, send mechanisms */
01682       if (!send_rejected (auth))
01683         return FALSE;
01684 
01685       return TRUE;
01686     }
01687   else
01688     {
01689       int i;
01690       DBusString mech;
01691       DBusString hex_response;
01692       
01693       _dbus_string_find_blank (args, 0, &i);
01694 
01695       if (!_dbus_string_init (&mech))
01696         return FALSE;
01697 
01698       if (!_dbus_string_init (&hex_response))
01699         {
01700           _dbus_string_free (&mech);
01701           return FALSE;
01702         }
01703       
01704       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01705         goto failed;
01706 
01707       _dbus_string_skip_blank (args, i, &i);
01708       if (!_dbus_string_copy (args, i, &hex_response, 0))
01709         goto failed;
01710      
01711       auth->mech = find_mech (&mech, auth->allowed_mechs);
01712       if (auth->mech != NULL)
01713         {
01714           _dbus_verbose ("%s: Trying mechanism %s\n",
01715                          DBUS_AUTH_NAME (auth),
01716                          auth->mech->mechanism);
01717           
01718           if (!process_data (auth, &hex_response,
01719                              auth->mech->server_data_func))
01720             goto failed;
01721         }
01722       else
01723         {
01724           /* Unsupported mechanism */
01725           _dbus_verbose ("%s: Unsupported mechanism %s\n",
01726                          DBUS_AUTH_NAME (auth),
01727                          _dbus_string_get_const_data (&mech));
01728           
01729           if (!send_rejected (auth))
01730             goto failed;
01731         }
01732 
01733       _dbus_string_free (&mech);      
01734       _dbus_string_free (&hex_response);
01735 
01736       return TRUE;
01737       
01738     failed:
01739       auth->mech = NULL;
01740       _dbus_string_free (&mech);
01741       _dbus_string_free (&hex_response);
01742       return FALSE;
01743     }
01744 }
01745 
01746 static dbus_bool_t
01747 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
01748                                        DBusAuthCommand   command,
01749                                        const DBusString *args)
01750 {
01751   switch (command)
01752     {
01753     case DBUS_AUTH_COMMAND_AUTH:
01754       return handle_auth (auth, args);
01755 
01756     case DBUS_AUTH_COMMAND_CANCEL:
01757     case DBUS_AUTH_COMMAND_DATA:
01758       return send_error (auth, "Not currently in an auth conversation");
01759 
01760     case DBUS_AUTH_COMMAND_BEGIN:
01761       goto_state (auth, &common_state_need_disconnect);
01762       return TRUE;
01763 
01764     case DBUS_AUTH_COMMAND_ERROR:
01765       return send_rejected (auth);
01766 
01767     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01768       return send_error (auth, "Need to authenticate first");
01769 
01770     case DBUS_AUTH_COMMAND_REJECTED:
01771     case DBUS_AUTH_COMMAND_OK:
01772     case DBUS_AUTH_COMMAND_UNKNOWN:
01773     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
01774     default:
01775       return send_error (auth, "Unknown command");
01776     }
01777 }
01778 
01779 static dbus_bool_t
01780 handle_server_state_waiting_for_data  (DBusAuth         *auth,
01781                                        DBusAuthCommand   command,
01782                                        const DBusString *args)
01783 {
01784   switch (command)
01785     {
01786     case DBUS_AUTH_COMMAND_AUTH:
01787       return send_error (auth, "Sent AUTH while another AUTH in progress");
01788 
01789     case DBUS_AUTH_COMMAND_CANCEL:
01790     case DBUS_AUTH_COMMAND_ERROR:
01791       return send_rejected (auth);
01792 
01793     case DBUS_AUTH_COMMAND_DATA:
01794       return process_data (auth, args, auth->mech->server_data_func);
01795 
01796     case DBUS_AUTH_COMMAND_BEGIN:
01797       goto_state (auth, &common_state_need_disconnect);
01798       return TRUE;
01799 
01800     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01801       return send_error (auth, "Need to authenticate first");
01802 
01803     case DBUS_AUTH_COMMAND_REJECTED:
01804     case DBUS_AUTH_COMMAND_OK:
01805     case DBUS_AUTH_COMMAND_UNKNOWN:
01806     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
01807     default:
01808       return send_error (auth, "Unknown command");
01809     }
01810 }
01811 
01812 static dbus_bool_t
01813 handle_server_state_waiting_for_begin (DBusAuth         *auth,
01814                                        DBusAuthCommand   command,
01815                                        const DBusString *args)
01816 {
01817   switch (command)
01818     {
01819     case DBUS_AUTH_COMMAND_AUTH:
01820       return send_error (auth, "Sent AUTH while expecting BEGIN");
01821 
01822     case DBUS_AUTH_COMMAND_DATA:
01823       return send_error (auth, "Sent DATA while expecting BEGIN");
01824 
01825     case DBUS_AUTH_COMMAND_BEGIN:
01826       goto_state (auth, &common_state_authenticated);
01827       return TRUE;
01828 
01829     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
01830       if (auth->unix_fd_possible)
01831         return send_agree_unix_fd(auth);
01832       else
01833         return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
01834 
01835     case DBUS_AUTH_COMMAND_REJECTED:
01836     case DBUS_AUTH_COMMAND_OK:
01837     case DBUS_AUTH_COMMAND_UNKNOWN:
01838     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
01839     default:
01840       return send_error (auth, "Unknown command");
01841 
01842     case DBUS_AUTH_COMMAND_CANCEL:
01843     case DBUS_AUTH_COMMAND_ERROR:
01844       return send_rejected (auth);
01845     }
01846 }
01847 
01848 /* return FALSE if no memory, TRUE if all OK */
01849 static dbus_bool_t
01850 get_word (const DBusString *str,
01851           int              *start,
01852           DBusString       *word)
01853 {
01854   int i;
01855 
01856   _dbus_string_skip_blank (str, *start, start);
01857   _dbus_string_find_blank (str, *start, &i);
01858   
01859   if (i > *start)
01860     {
01861       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01862         return FALSE;
01863       
01864       *start = i;
01865     }
01866 
01867   return TRUE;
01868 }
01869 
01870 static dbus_bool_t
01871 record_mechanisms (DBusAuth         *auth,
01872                    const DBusString *args)
01873 {
01874   int next;
01875   int len;
01876 
01877   if (auth->already_got_mechanisms)
01878     return TRUE;
01879   
01880   len = _dbus_string_get_length (args);
01881   
01882   next = 0;
01883   while (next < len)
01884     {
01885       DBusString m;
01886       const DBusAuthMechanismHandler *mech;
01887       
01888       if (!_dbus_string_init (&m))
01889         goto nomem;
01890       
01891       if (!get_word (args, &next, &m))
01892         {
01893           _dbus_string_free (&m);
01894           goto nomem;
01895         }
01896 
01897       mech = find_mech (&m, auth->allowed_mechs);
01898 
01899       if (mech != NULL)
01900         {
01901           /* FIXME right now we try mechanisms in the order
01902            * the server lists them; should we do them in
01903            * some more deterministic order?
01904            *
01905            * Probably in all_mechanisms order, our order of
01906            * preference. Of course when the server is us,
01907            * it lists things in that order anyhow.
01908            */
01909 
01910           if (mech != &all_mechanisms[0])
01911             {
01912               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01913                              DBUS_AUTH_NAME (auth), mech->mechanism);
01914           
01915               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01916                                       (void*) mech))
01917                 {
01918                   _dbus_string_free (&m);
01919                   goto nomem;
01920                 }
01921             }
01922           else
01923             {
01924               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
01925                              DBUS_AUTH_NAME (auth), mech->mechanism);
01926             }
01927         }
01928       else
01929         {
01930           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01931                          DBUS_AUTH_NAME (auth),
01932                          _dbus_string_get_const_data (&m));
01933         }
01934 
01935       _dbus_string_free (&m);
01936     }
01937   
01938   auth->already_got_mechanisms = TRUE;
01939   
01940   return TRUE;
01941 
01942  nomem:
01943   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01944   
01945   return FALSE;
01946 }
01947 
01948 static dbus_bool_t
01949 process_rejected (DBusAuth *auth, const DBusString *args)
01950 {
01951   const DBusAuthMechanismHandler *mech;
01952   DBusAuthClient *client;
01953 
01954   client = DBUS_AUTH_CLIENT (auth);
01955 
01956   if (!auth->already_got_mechanisms)
01957     {
01958       if (!record_mechanisms (auth, args))
01959         return FALSE;
01960     }
01961   
01962   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01963     {
01964       mech = client->mechs_to_try->data;
01965 
01966       if (!send_auth (auth, mech))
01967         return FALSE;
01968 
01969       _dbus_list_pop_first (&client->mechs_to_try);
01970 
01971       _dbus_verbose ("%s: Trying mechanism %s\n",
01972                      DBUS_AUTH_NAME (auth),
01973                      mech->mechanism);
01974     }
01975   else
01976     {
01977       /* Give up */
01978       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01979                      DBUS_AUTH_NAME (auth));
01980       goto_state (auth, &common_state_need_disconnect);
01981     }
01982   
01983   return TRUE;
01984 }
01985 
01986 
01987 static dbus_bool_t
01988 handle_client_state_waiting_for_data (DBusAuth         *auth,
01989                                       DBusAuthCommand   command,
01990                                       const DBusString *args)
01991 {
01992   _dbus_assert (auth->mech != NULL);
01993  
01994   switch (command)
01995     {
01996     case DBUS_AUTH_COMMAND_DATA:
01997       return process_data (auth, args, auth->mech->client_data_func);
01998 
01999     case DBUS_AUTH_COMMAND_REJECTED:
02000       return process_rejected (auth, args);
02001 
02002     case DBUS_AUTH_COMMAND_OK:
02003       return process_ok(auth, args);
02004 
02005     case DBUS_AUTH_COMMAND_ERROR:
02006       return send_cancel (auth);
02007 
02008     case DBUS_AUTH_COMMAND_AUTH:
02009     case DBUS_AUTH_COMMAND_CANCEL:
02010     case DBUS_AUTH_COMMAND_BEGIN:
02011     case DBUS_AUTH_COMMAND_UNKNOWN:
02012     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02013     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02014     default:
02015       return send_error (auth, "Unknown command");
02016     }
02017 }
02018 
02019 static dbus_bool_t
02020 handle_client_state_waiting_for_ok (DBusAuth         *auth,
02021                                     DBusAuthCommand   command,
02022                                     const DBusString *args)
02023 {
02024   switch (command)
02025     {
02026     case DBUS_AUTH_COMMAND_REJECTED:
02027       return process_rejected (auth, args);
02028 
02029     case DBUS_AUTH_COMMAND_OK:
02030       return process_ok(auth, args);
02031 
02032     case DBUS_AUTH_COMMAND_DATA:
02033     case DBUS_AUTH_COMMAND_ERROR:
02034       return send_cancel (auth);
02035 
02036     case DBUS_AUTH_COMMAND_AUTH:
02037     case DBUS_AUTH_COMMAND_CANCEL:
02038     case DBUS_AUTH_COMMAND_BEGIN:
02039     case DBUS_AUTH_COMMAND_UNKNOWN:
02040     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02041     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02042     default:
02043       return send_error (auth, "Unknown command");
02044     }
02045 }
02046 
02047 static dbus_bool_t
02048 handle_client_state_waiting_for_reject (DBusAuth         *auth,
02049                                         DBusAuthCommand   command,
02050                                         const DBusString *args)
02051 {
02052   switch (command)
02053     {
02054     case DBUS_AUTH_COMMAND_REJECTED:
02055       return process_rejected (auth, args);
02056       
02057     case DBUS_AUTH_COMMAND_AUTH:
02058     case DBUS_AUTH_COMMAND_CANCEL:
02059     case DBUS_AUTH_COMMAND_DATA:
02060     case DBUS_AUTH_COMMAND_BEGIN:
02061     case DBUS_AUTH_COMMAND_OK:
02062     case DBUS_AUTH_COMMAND_ERROR:
02063     case DBUS_AUTH_COMMAND_UNKNOWN:
02064     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02065     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02066     default:
02067       goto_state (auth, &common_state_need_disconnect);
02068       return TRUE;
02069     }
02070 }
02071 
02072 static dbus_bool_t
02073 handle_client_state_waiting_for_agree_unix_fd(DBusAuth         *auth,
02074                                               DBusAuthCommand   command,
02075                                               const DBusString *args)
02076 {
02077   switch (command)
02078     {
02079     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
02080       _dbus_assert(auth->unix_fd_possible);
02081       auth->unix_fd_negotiated = TRUE;
02082       _dbus_verbose("Sucessfully negotiated UNIX FD passing\n");
02083       return send_begin (auth);
02084 
02085     case DBUS_AUTH_COMMAND_ERROR:
02086       _dbus_assert(auth->unix_fd_possible);
02087       auth->unix_fd_negotiated = FALSE;
02088       _dbus_verbose("Failed to negotiate UNIX FD passing\n");
02089       return send_begin (auth);
02090 
02091     case DBUS_AUTH_COMMAND_OK:
02092     case DBUS_AUTH_COMMAND_DATA:
02093     case DBUS_AUTH_COMMAND_REJECTED:
02094     case DBUS_AUTH_COMMAND_AUTH:
02095     case DBUS_AUTH_COMMAND_CANCEL:
02096     case DBUS_AUTH_COMMAND_BEGIN:
02097     case DBUS_AUTH_COMMAND_UNKNOWN:
02098     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
02099     default:
02100       return send_error (auth, "Unknown command");
02101     }
02102 }
02103 
02107 typedef struct {
02108   const char *name;        
02109   DBusAuthCommand command; 
02110 } DBusAuthCommandName;
02111 
02112 static const DBusAuthCommandName auth_command_names[] = {
02113   { "AUTH",              DBUS_AUTH_COMMAND_AUTH },
02114   { "CANCEL",            DBUS_AUTH_COMMAND_CANCEL },
02115   { "DATA",              DBUS_AUTH_COMMAND_DATA },
02116   { "BEGIN",             DBUS_AUTH_COMMAND_BEGIN },
02117   { "REJECTED",          DBUS_AUTH_COMMAND_REJECTED },
02118   { "OK",                DBUS_AUTH_COMMAND_OK },
02119   { "ERROR",             DBUS_AUTH_COMMAND_ERROR },
02120   { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
02121   { "AGREE_UNIX_FD",     DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
02122 };
02123 
02124 static DBusAuthCommand
02125 lookup_command_from_name (DBusString *command)
02126 {
02127   int i;
02128 
02129   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
02130     {
02131       if (_dbus_string_equal_c_str (command,
02132                                     auth_command_names[i].name))
02133         return auth_command_names[i].command;
02134     }
02135 
02136   return DBUS_AUTH_COMMAND_UNKNOWN;
02137 }
02138 
02139 static void
02140 goto_state (DBusAuth *auth,
02141             const DBusAuthStateData *state)
02142 {
02143   _dbus_verbose ("%s: going from state %s to state %s\n",
02144                  DBUS_AUTH_NAME (auth),
02145                  auth->state->name,
02146                  state->name);
02147 
02148   auth->state = state;
02149 }
02150 
02151 /* returns whether to call it again right away */
02152 static dbus_bool_t
02153 process_command (DBusAuth *auth)
02154 {
02155   DBusAuthCommand command;
02156   DBusString line;
02157   DBusString args;
02158   int eol;
02159   int i, j;
02160   dbus_bool_t retval;
02161 
02162   /* _dbus_verbose ("%s:   trying process_command()\n"); */
02163   
02164   retval = FALSE;
02165   
02166   eol = 0;
02167   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
02168     return FALSE;
02169   
02170   if (!_dbus_string_init (&line))
02171     {
02172       auth->needed_memory = TRUE;
02173       return FALSE;
02174     }
02175 
02176   if (!_dbus_string_init (&args))
02177     {
02178       _dbus_string_free (&line);
02179       auth->needed_memory = TRUE;
02180       return FALSE;
02181     }
02182   
02183   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
02184     goto out;
02185 
02186   if (!_dbus_string_validate_ascii (&line, 0,
02187                                     _dbus_string_get_length (&line)))
02188     {
02189       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
02190                      DBUS_AUTH_NAME (auth));
02191       if (!send_error (auth, "Command contained non-ASCII"))
02192         goto out;
02193       else
02194         goto next_command;
02195     }
02196   
02197   _dbus_verbose ("%s: got command \"%s\"\n",
02198                  DBUS_AUTH_NAME (auth),
02199                  _dbus_string_get_const_data (&line));
02200   
02201   _dbus_string_find_blank (&line, 0, &i);
02202   _dbus_string_skip_blank (&line, i, &j);
02203 
02204   if (j > i)
02205     _dbus_string_delete (&line, i, j - i);
02206   
02207   if (!_dbus_string_move (&line, i, &args, 0))
02208     goto out;
02209 
02210   /* FIXME 1.0 we should probably validate that only the allowed
02211    * chars are in the command name
02212    */
02213   
02214   command = lookup_command_from_name (&line);
02215   if (!(* auth->state->handler) (auth, command, &args))
02216     goto out;
02217 
02218  next_command:
02219   
02220   /* We've succeeded in processing the whole command so drop it out
02221    * of the incoming buffer and return TRUE to try another command.
02222    */
02223 
02224   _dbus_string_delete (&auth->incoming, 0, eol);
02225   
02226   /* kill the \r\n */
02227   _dbus_string_delete (&auth->incoming, 0, 2);
02228 
02229   retval = TRUE;
02230   
02231  out:
02232   _dbus_string_free (&args);
02233   _dbus_string_free (&line);
02234 
02235   if (!retval)
02236     auth->needed_memory = TRUE;
02237   else
02238     auth->needed_memory = FALSE;
02239   
02240   return retval;
02241 }
02242 
02243 
02258 DBusAuth*
02259 _dbus_auth_server_new (const DBusString *guid)
02260 {
02261   DBusAuth *auth;
02262   DBusAuthServer *server_auth;
02263   DBusString guid_copy;
02264 
02265   if (!_dbus_string_init (&guid_copy))
02266     return NULL;
02267 
02268   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
02269     {
02270       _dbus_string_free (&guid_copy);
02271       return NULL;
02272     }
02273 
02274   auth = _dbus_auth_new (sizeof (DBusAuthServer));
02275   if (auth == NULL)
02276     {
02277       _dbus_string_free (&guid_copy);
02278       return NULL;
02279     }
02280   
02281   auth->side = auth_side_server;
02282   auth->state = &server_state_waiting_for_auth;
02283 
02284   server_auth = DBUS_AUTH_SERVER (auth);
02285 
02286   server_auth->guid = guid_copy;
02287   
02288   /* perhaps this should be per-mechanism with a lower
02289    * max
02290    */
02291   server_auth->failures = 0;
02292   server_auth->max_failures = 6;
02293   
02294   return auth;
02295 }
02296 
02304 DBusAuth*
02305 _dbus_auth_client_new (void)
02306 {
02307   DBusAuth *auth;
02308   DBusString guid_str;
02309 
02310   if (!_dbus_string_init (&guid_str))
02311     return NULL;
02312 
02313   auth = _dbus_auth_new (sizeof (DBusAuthClient));
02314   if (auth == NULL)
02315     {
02316       _dbus_string_free (&guid_str);
02317       return NULL;
02318     }
02319 
02320   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02321 
02322   auth->side = auth_side_client;
02323   auth->state = &client_state_need_send_auth;
02324 
02325   /* Start the auth conversation by sending AUTH for our default
02326    * mechanism */
02327   if (!send_auth (auth, &all_mechanisms[0]))
02328     {
02329       _dbus_auth_unref (auth);
02330       return NULL;
02331     }
02332   
02333   return auth;
02334 }
02335 
02342 DBusAuth *
02343 _dbus_auth_ref (DBusAuth *auth)
02344 {
02345   _dbus_assert (auth != NULL);
02346   
02347   auth->refcount += 1;
02348   
02349   return auth;
02350 }
02351 
02357 void
02358 _dbus_auth_unref (DBusAuth *auth)
02359 {
02360   _dbus_assert (auth != NULL);
02361   _dbus_assert (auth->refcount > 0);
02362 
02363   auth->refcount -= 1;
02364   if (auth->refcount == 0)
02365     {
02366       shutdown_mech (auth);
02367 
02368       if (DBUS_AUTH_IS_CLIENT (auth))
02369         {
02370           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02371           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02372         }
02373       else
02374         {
02375           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02376 
02377           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02378         }
02379 
02380       if (auth->keyring)
02381         _dbus_keyring_unref (auth->keyring);
02382 
02383       _dbus_string_free (&auth->context);
02384       _dbus_string_free (&auth->challenge);
02385       _dbus_string_free (&auth->identity);
02386       _dbus_string_free (&auth->incoming);
02387       _dbus_string_free (&auth->outgoing);
02388 
02389       dbus_free_string_array (auth->allowed_mechs);
02390 
02391       _dbus_credentials_unref (auth->credentials);
02392       _dbus_credentials_unref (auth->authorized_identity);
02393       _dbus_credentials_unref (auth->desired_identity);
02394       
02395       dbus_free (auth);
02396     }
02397 }
02398 
02407 dbus_bool_t
02408 _dbus_auth_set_mechanisms (DBusAuth    *auth,
02409                            const char **mechanisms)
02410 {
02411   char **copy;
02412 
02413   if (mechanisms != NULL)
02414     {
02415       copy = _dbus_dup_string_array (mechanisms);
02416       if (copy == NULL)
02417         return FALSE;
02418     }
02419   else
02420     copy = NULL;
02421   
02422   dbus_free_string_array (auth->allowed_mechs);
02423 
02424   auth->allowed_mechs = copy;
02425 
02426   return TRUE;
02427 }
02428 
02433 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02434 
02442 DBusAuthState
02443 _dbus_auth_do_work (DBusAuth *auth)
02444 {
02445   auth->needed_memory = FALSE;
02446 
02447   /* Max amount we'll buffer up before deciding someone's on crack */
02448 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02449 
02450   do
02451     {
02452       if (DBUS_AUTH_IN_END_STATE (auth))
02453         break;
02454       
02455       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02456           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02457         {
02458           goto_state (auth, &common_state_need_disconnect);
02459           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02460                          DBUS_AUTH_NAME (auth));
02461           break;
02462         }
02463     }
02464   while (process_command (auth));
02465 
02466   if (auth->needed_memory)
02467     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02468   else if (_dbus_string_get_length (&auth->outgoing) > 0)
02469     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02470   else if (auth->state == &common_state_need_disconnect)
02471     return DBUS_AUTH_STATE_NEED_DISCONNECT;
02472   else if (auth->state == &common_state_authenticated)
02473     return DBUS_AUTH_STATE_AUTHENTICATED;
02474   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02475 }
02476 
02486 dbus_bool_t
02487 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
02488                               const DBusString **str)
02489 {
02490   _dbus_assert (auth != NULL);
02491   _dbus_assert (str != NULL);
02492 
02493   *str = NULL;
02494   
02495   if (_dbus_string_get_length (&auth->outgoing) == 0)
02496     return FALSE;
02497 
02498   *str = &auth->outgoing;
02499 
02500   return TRUE;
02501 }
02502 
02511 void
02512 _dbus_auth_bytes_sent (DBusAuth *auth,
02513                        int       bytes_sent)
02514 {
02515   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02516                  DBUS_AUTH_NAME (auth),
02517                  bytes_sent,
02518                  _dbus_string_get_const_data (&auth->outgoing));
02519   
02520   _dbus_string_delete (&auth->outgoing,
02521                        0, bytes_sent);
02522 }
02523 
02531 void
02532 _dbus_auth_get_buffer (DBusAuth     *auth,
02533                        DBusString **buffer)
02534 {
02535   _dbus_assert (auth != NULL);
02536   _dbus_assert (!auth->buffer_outstanding);
02537   
02538   *buffer = &auth->incoming;
02539 
02540   auth->buffer_outstanding = TRUE;
02541 }
02542 
02550 void
02551 _dbus_auth_return_buffer (DBusAuth               *auth,
02552                           DBusString             *buffer,
02553                           int                     bytes_read)
02554 {
02555   _dbus_assert (buffer == &auth->incoming);
02556   _dbus_assert (auth->buffer_outstanding);
02557 
02558   auth->buffer_outstanding = FALSE;
02559 }
02560 
02570 void
02571 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
02572                              const DBusString **str)
02573 {
02574   if (!DBUS_AUTH_IN_END_STATE (auth))
02575     return;
02576 
02577   *str = &auth->incoming;
02578 }
02579 
02580 
02587 void
02588 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02589 {
02590   if (!DBUS_AUTH_IN_END_STATE (auth))
02591     return;
02592 
02593   _dbus_string_set_length (&auth->incoming, 0);
02594 }
02595 
02604 dbus_bool_t
02605 _dbus_auth_needs_encoding (DBusAuth *auth)
02606 {
02607   if (auth->state != &common_state_authenticated)
02608     return FALSE;
02609   
02610   if (auth->mech != NULL)
02611     {
02612       if (DBUS_AUTH_IS_CLIENT (auth))
02613         return auth->mech->client_encode_func != NULL;
02614       else
02615         return auth->mech->server_encode_func != NULL;
02616     }
02617   else
02618     return FALSE;
02619 }
02620 
02631 dbus_bool_t
02632 _dbus_auth_encode_data (DBusAuth         *auth,
02633                         const DBusString *plaintext,
02634                         DBusString       *encoded)
02635 {
02636   _dbus_assert (plaintext != encoded);
02637   
02638   if (auth->state != &common_state_authenticated)
02639     return FALSE;
02640   
02641   if (_dbus_auth_needs_encoding (auth))
02642     {
02643       if (DBUS_AUTH_IS_CLIENT (auth))
02644         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02645       else
02646         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02647     }
02648   else
02649     {
02650       return _dbus_string_copy (plaintext, 0, encoded,
02651                                 _dbus_string_get_length (encoded));
02652     }
02653 }
02654 
02663 dbus_bool_t
02664 _dbus_auth_needs_decoding (DBusAuth *auth)
02665 {
02666   if (auth->state != &common_state_authenticated)
02667     return FALSE;
02668     
02669   if (auth->mech != NULL)
02670     {
02671       if (DBUS_AUTH_IS_CLIENT (auth))
02672         return auth->mech->client_decode_func != NULL;
02673       else
02674         return auth->mech->server_decode_func != NULL;
02675     }
02676   else
02677     return FALSE;
02678 }
02679 
02680 
02694 dbus_bool_t
02695 _dbus_auth_decode_data (DBusAuth         *auth,
02696                         const DBusString *encoded,
02697                         DBusString       *plaintext)
02698 {
02699   _dbus_assert (plaintext != encoded);
02700   
02701   if (auth->state != &common_state_authenticated)
02702     return FALSE;
02703   
02704   if (_dbus_auth_needs_decoding (auth))
02705     {
02706       if (DBUS_AUTH_IS_CLIENT (auth))
02707         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02708       else
02709         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02710     }
02711   else
02712     {
02713       return _dbus_string_copy (encoded, 0, plaintext,
02714                                 _dbus_string_get_length (plaintext));
02715     }
02716 }
02717 
02726 dbus_bool_t
02727 _dbus_auth_set_credentials (DBusAuth               *auth,
02728                             DBusCredentials        *credentials)
02729 {
02730   _dbus_credentials_clear (auth->credentials);
02731   return _dbus_credentials_add_credentials (auth->credentials,
02732                                             credentials);
02733 }
02734 
02744 DBusCredentials*
02745 _dbus_auth_get_identity (DBusAuth               *auth)
02746 {
02747   if (auth->state == &common_state_authenticated)
02748     {
02749       return auth->authorized_identity;
02750     }
02751   else
02752     {
02753       /* FIXME instead of this, keep an empty credential around that
02754        * doesn't require allocation or something
02755        */
02756       /* return empty credentials */
02757       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
02758       return auth->authorized_identity;
02759     }
02760 }
02761 
02768 const char*
02769 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02770 {
02771   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02772   
02773   if (auth->state == &common_state_authenticated)
02774     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02775   else
02776     return NULL;
02777 }
02778 
02787 dbus_bool_t
02788 _dbus_auth_set_context (DBusAuth               *auth,
02789                         const DBusString       *context)
02790 {
02791   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02792                                    &auth->context, 0, _dbus_string_get_length (context));
02793 }
02794 
02802 void
02803 _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
02804 {
02805   auth->unix_fd_possible = b;
02806 }
02807 
02814 dbus_bool_t
02815 _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
02816 {
02817   return auth->unix_fd_negotiated;
02818 }
02819 
02822 /* tests in dbus-auth-util.c */

Generated on Sun Aug 28 2011 for D-Bus by  doxygen 1.7.1