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