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

Generated on Sat Dec 6 19:43:43 2008 for D-Bus by  doxygen 1.5.1