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           return TRUE;
01043         }
01044       else
01045         return FALSE;
01046     }
01047 
01048   _dbus_credentials_clear (auth->desired_identity);
01049   
01050   /* If auth->identity is still empty here, then client
01051    * responded with an empty string after we poked it for
01052    * an initial response. This means to try to auth the
01053    * identity provided in the credentials.
01054    */
01055   if (_dbus_string_get_length (&auth->identity) == 0)
01056     {
01057       if (!_dbus_credentials_add_credentials (auth->desired_identity,
01058                                               auth->credentials))
01059         {
01060           return FALSE; /* OOM */
01061         }
01062     }
01063   else
01064     {
01065       if (!_dbus_credentials_add_from_user (auth->desired_identity,
01066                                             &auth->identity))
01067         {
01068           _dbus_verbose ("%s: could not get credentials from uid string\n",
01069                          DBUS_AUTH_NAME (auth));
01070           return send_rejected (auth);
01071         }
01072     }
01073 
01074   if (_dbus_credentials_are_anonymous (auth->desired_identity))
01075     {
01076       _dbus_verbose ("%s: desired user %s is no good\n",
01077                      DBUS_AUTH_NAME (auth),
01078                      _dbus_string_get_const_data (&auth->identity));
01079       return send_rejected (auth);
01080     }
01081   
01082   if (_dbus_credentials_are_superset (auth->credentials,
01083                                       auth->desired_identity))
01084     {
01085       /* client has authenticated */
01086       if (!_dbus_credentials_add_credentials (auth->authorized_identity,
01087                                               auth->desired_identity))
01088         return FALSE;
01089 
01090       /* also copy process ID from the socket credentials
01091        */
01092       if (!_dbus_credentials_add_credential (auth->authorized_identity,
01093                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01094                                              auth->credentials))
01095         return FALSE;
01096       
01097       if (!send_ok (auth))
01098         return FALSE;
01099 
01100       _dbus_verbose ("%s: authenticated client based on socket credentials\n",
01101                      DBUS_AUTH_NAME (auth));
01102 
01103       return TRUE;
01104     }
01105   else
01106     {
01107       _dbus_verbose ("%s: desired identity not found in socket credentials\n",
01108                      DBUS_AUTH_NAME (auth));
01109       return send_rejected (auth);
01110     }
01111 }
01112 
01113 static void
01114 handle_server_shutdown_external_mech (DBusAuth *auth)
01115 {
01116 
01117 }
01118 
01119 static dbus_bool_t
01120 handle_client_initial_response_external_mech (DBusAuth         *auth,
01121                                               DBusString       *response)
01122 {
01123   /* We always append our UID as an initial response, so the server
01124    * doesn't have to send back an empty challenge to check whether we
01125    * want to specify an identity. i.e. this avoids a round trip that
01126    * the spec for the EXTERNAL mechanism otherwise requires.
01127    */
01128   DBusString plaintext;
01129 
01130   if (!_dbus_string_init (&plaintext))
01131     return FALSE;
01132 
01133   if (!_dbus_append_user_from_current_process (&plaintext))
01134     goto failed;
01135 
01136   if (!_dbus_string_hex_encode (&plaintext, 0,
01137                                 response,
01138                                 _dbus_string_get_length (response)))
01139     goto failed;
01140 
01141   _dbus_string_free (&plaintext);
01142   
01143   return TRUE;
01144 
01145  failed:
01146   _dbus_string_free (&plaintext);
01147   return FALSE;  
01148 }
01149 
01150 static dbus_bool_t
01151 handle_client_data_external_mech (DBusAuth         *auth,
01152                                   const DBusString *data)
01153 {
01154   
01155   return TRUE;
01156 }
01157 
01158 static void
01159 handle_client_shutdown_external_mech (DBusAuth *auth)
01160 {
01161 
01162 }
01163 
01164 /*
01165  * ANONYMOUS mechanism
01166  */
01167 
01168 static dbus_bool_t
01169 handle_server_data_anonymous_mech (DBusAuth         *auth,
01170                                    const DBusString *data)
01171 {  
01172   if (_dbus_string_get_length (data) > 0)
01173     {
01174       /* Client is allowed to send "trace" data, the only defined
01175        * meaning is that if it contains '@' it is an email address,
01176        * and otherwise it is anything else, and it's supposed to be
01177        * UTF-8
01178        */
01179       if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
01180         {
01181           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
01182                          DBUS_AUTH_NAME (auth));
01183 
01184           {
01185             DBusString plaintext;
01186             DBusString encoded;
01187             _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
01188             _dbus_string_init (&encoded);
01189             _dbus_string_hex_encode (&plaintext, 0,
01190                                      &encoded,
01191                                      0);
01192               _dbus_verbose ("%s: try '%s'\n",
01193                              DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
01194           }
01195           return send_rejected (auth);
01196         }
01197       
01198       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
01199                      DBUS_AUTH_NAME (auth),
01200                      _dbus_string_get_const_data (data));
01201     }
01202 
01203   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
01204   _dbus_credentials_clear (auth->desired_identity);
01205 
01206   /* Copy process ID from the socket credentials
01207    */
01208   if (!_dbus_credentials_add_credential (auth->authorized_identity,
01209                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01210                                          auth->credentials))
01211     return FALSE;
01212   
01213   /* Anonymous is always allowed */
01214   if (!send_ok (auth))
01215     return FALSE;
01216 
01217   _dbus_verbose ("%s: authenticated client as anonymous\n",
01218                  DBUS_AUTH_NAME (auth));
01219 
01220   return TRUE;
01221 }
01222 
01223 static void
01224 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
01225 {
01226   
01227 }
01228 
01229 static dbus_bool_t
01230 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
01231                                                DBusString       *response)
01232 {
01233   /* Our initial response is a "trace" string which must be valid UTF-8
01234    * and must be an email address if it contains '@'.
01235    * We just send the dbus implementation info, like a user-agent or
01236    * something, because... why not. There's nothing guaranteed here
01237    * though, we could change it later.
01238    */
01239   DBusString plaintext;
01240 
01241   if (!_dbus_string_init (&plaintext))
01242     return FALSE;
01243 
01244   if (!_dbus_string_append (&plaintext,
01245                             "libdbus " VERSION))
01246     goto failed;
01247 
01248   if (!_dbus_string_hex_encode (&plaintext, 0,
01249                                 response,
01250                                 _dbus_string_get_length (response)))
01251     goto failed;
01252 
01253   _dbus_string_free (&plaintext);
01254   
01255   return TRUE;
01256 
01257  failed:
01258   _dbus_string_free (&plaintext);
01259   return FALSE;  
01260 }
01261 
01262 static dbus_bool_t
01263 handle_client_data_anonymous_mech (DBusAuth         *auth,
01264                                   const DBusString *data)
01265 {
01266   
01267   return TRUE;
01268 }
01269 
01270 static void
01271 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
01272 {
01273   
01274 }
01275 
01276 /* Put mechanisms here in order of preference.
01277  * Right now we have:
01278  *
01279  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
01280  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
01281  * - ANONYMOUS checks nothing but doesn't auth the person as a user
01282  *
01283  * We might ideally add a mechanism to chain to Cyrus SASL so we can
01284  * use its mechanisms as well.
01285  * 
01286  */
01287 static const DBusAuthMechanismHandler
01288 all_mechanisms[] = {
01289   { "EXTERNAL",
01290     handle_server_data_external_mech,
01291     NULL, NULL,
01292     handle_server_shutdown_external_mech,
01293     handle_client_initial_response_external_mech,
01294     handle_client_data_external_mech,
01295     NULL, NULL,
01296     handle_client_shutdown_external_mech },
01297   { "DBUS_COOKIE_SHA1",
01298     handle_server_data_cookie_sha1_mech,
01299     NULL, NULL,
01300     handle_server_shutdown_cookie_sha1_mech,
01301     handle_client_initial_response_cookie_sha1_mech,
01302     handle_client_data_cookie_sha1_mech,
01303     NULL, NULL,
01304     handle_client_shutdown_cookie_sha1_mech },
01305   { "ANONYMOUS",
01306     handle_server_data_anonymous_mech,
01307     NULL, NULL,
01308     handle_server_shutdown_anonymous_mech,
01309     handle_client_initial_response_anonymous_mech,
01310     handle_client_data_anonymous_mech,
01311     NULL, NULL,
01312     handle_client_shutdown_anonymous_mech },  
01313   { NULL, NULL }
01314 };
01315 
01316 static const DBusAuthMechanismHandler*
01317 find_mech (const DBusString  *name,
01318            char             **allowed_mechs)
01319 {
01320   int i;
01321   
01322   if (allowed_mechs != NULL &&
01323       !_dbus_string_array_contains ((const char**) allowed_mechs,
01324                                     _dbus_string_get_const_data (name)))
01325     return NULL;
01326   
01327   i = 0;
01328   while (all_mechanisms[i].mechanism != NULL)
01329     {      
01330       if (_dbus_string_equal_c_str (name,
01331                                     all_mechanisms[i].mechanism))
01332 
01333         return &all_mechanisms[i];
01334       
01335       ++i;
01336     }
01337   
01338   return NULL;
01339 }
01340 
01341 static dbus_bool_t
01342 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01343 {
01344   DBusString auth_command;
01345 
01346   if (!_dbus_string_init (&auth_command))
01347     return FALSE;
01348       
01349   if (!_dbus_string_append (&auth_command,
01350                             "AUTH "))
01351     {
01352       _dbus_string_free (&auth_command);
01353       return FALSE;
01354     }  
01355   
01356   if (!_dbus_string_append (&auth_command,
01357                             mech->mechanism))
01358     {
01359       _dbus_string_free (&auth_command);
01360       return FALSE;
01361     }
01362 
01363   if (mech->client_initial_response_func != NULL)
01364     {
01365       if (!_dbus_string_append (&auth_command, " "))
01366         {
01367           _dbus_string_free (&auth_command);
01368           return FALSE;
01369         }
01370       
01371       if (!(* mech->client_initial_response_func) (auth, &auth_command))
01372         {
01373           _dbus_string_free (&auth_command);
01374           return FALSE;
01375         }
01376     }
01377   
01378   if (!_dbus_string_append (&auth_command,
01379                             "\r\n"))
01380     {
01381       _dbus_string_free (&auth_command);
01382       return FALSE;
01383     }
01384 
01385   if (!_dbus_string_copy (&auth_command, 0,
01386                           &auth->outgoing,
01387                           _dbus_string_get_length (&auth->outgoing)))
01388     {
01389       _dbus_string_free (&auth_command);
01390       return FALSE;
01391     }
01392 
01393   _dbus_string_free (&auth_command);
01394   shutdown_mech (auth);
01395   auth->mech = mech;      
01396   goto_state (auth, &client_state_waiting_for_data);
01397 
01398   return TRUE;
01399 }
01400 
01401 static dbus_bool_t
01402 send_data (DBusAuth *auth, DBusString *data)
01403 {
01404   int old_len;
01405 
01406   if (data == NULL || _dbus_string_get_length (data) == 0)
01407     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01408   else
01409     {
01410       old_len = _dbus_string_get_length (&auth->outgoing);
01411       if (!_dbus_string_append (&auth->outgoing, "DATA "))
01412         goto out;
01413 
01414       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01415                                     _dbus_string_get_length (&auth->outgoing)))
01416         goto out;
01417 
01418       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01419         goto out;
01420 
01421       return TRUE;
01422 
01423     out:
01424       _dbus_string_set_length (&auth->outgoing, old_len);
01425 
01426       return FALSE;
01427     }
01428 }
01429 
01430 static dbus_bool_t
01431 send_rejected (DBusAuth *auth)
01432 {
01433   DBusString command;
01434   DBusAuthServer *server_auth;
01435   int i;
01436   
01437   if (!_dbus_string_init (&command))
01438     return FALSE;
01439   
01440   if (!_dbus_string_append (&command,
01441                             "REJECTED"))
01442     goto nomem;
01443 
01444   i = 0;
01445   while (all_mechanisms[i].mechanism != NULL)
01446     {
01447       if (!_dbus_string_append (&command,
01448                                 " "))
01449         goto nomem;
01450 
01451       if (!_dbus_string_append (&command,
01452                                 all_mechanisms[i].mechanism))
01453         goto nomem;
01454       
01455       ++i;
01456     }
01457   
01458   if (!_dbus_string_append (&command, "\r\n"))
01459     goto nomem;
01460 
01461   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01462                           _dbus_string_get_length (&auth->outgoing)))
01463     goto nomem;
01464 
01465   shutdown_mech (auth);
01466   
01467   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01468   server_auth = DBUS_AUTH_SERVER (auth);
01469   server_auth->failures += 1;
01470 
01471   if (server_auth->failures >= server_auth->max_failures)
01472     goto_state (auth, &common_state_need_disconnect);
01473   else
01474     goto_state (auth, &server_state_waiting_for_auth);
01475 
01476   _dbus_string_free (&command);
01477   
01478   return TRUE;
01479 
01480  nomem:
01481   _dbus_string_free (&command);
01482   return FALSE;
01483 }
01484 
01485 static dbus_bool_t
01486 send_error (DBusAuth *auth, const char *message)
01487 {
01488   return _dbus_string_append_printf (&auth->outgoing,
01489                                      "ERROR \"%s\"\r\n", message);
01490 }
01491 
01492 static dbus_bool_t
01493 send_ok (DBusAuth *auth)
01494 {
01495   int orig_len;
01496 
01497   orig_len = _dbus_string_get_length (&auth->outgoing);
01498   
01499   if (_dbus_string_append (&auth->outgoing, "OK ") &&
01500       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01501                          0,
01502                          &auth->outgoing,
01503                          _dbus_string_get_length (&auth->outgoing)) &&
01504       _dbus_string_append (&auth->outgoing, "\r\n"))
01505     {
01506       goto_state (auth, &server_state_waiting_for_begin);
01507       return TRUE;
01508     }
01509   else
01510     {
01511       _dbus_string_set_length (&auth->outgoing, orig_len);
01512       return FALSE;
01513     }
01514 }
01515 
01516 static dbus_bool_t
01517 send_begin (DBusAuth         *auth,
01518             const DBusString *args_from_ok)
01519 {
01520   int end_of_hex;
01521   
01522   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
01523   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01524 
01525   /* We decode the hex string to binary, using guid_from_server as scratch... */
01526   
01527   end_of_hex = 0;
01528   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01529                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01530     return FALSE;
01531 
01532   /* now clear out the scratch */
01533   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01534   
01535   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01536       end_of_hex == 0)
01537     {
01538       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01539                      end_of_hex, _dbus_string_get_length (args_from_ok));
01540       goto_state (auth, &common_state_need_disconnect);
01541       return TRUE;
01542     }
01543 
01544   if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01545       _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01546     {
01547       _dbus_verbose ("Got GUID '%s' from the server\n",
01548                      _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01549       
01550       goto_state (auth, &common_state_authenticated);
01551       return TRUE;
01552     }
01553   else
01554     {
01555       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01556       return FALSE;
01557     }
01558 }
01559 
01560 static dbus_bool_t
01561 send_cancel (DBusAuth *auth)
01562 {
01563   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01564     {
01565       goto_state (auth, &client_state_waiting_for_reject);
01566       return TRUE;
01567     }
01568   else
01569     return FALSE;
01570 }
01571 
01572 static dbus_bool_t
01573 process_data (DBusAuth             *auth,
01574               const DBusString     *args,
01575               DBusAuthDataFunction  data_func)
01576 {
01577   int end;
01578   DBusString decoded;
01579 
01580   if (!_dbus_string_init (&decoded))
01581     return FALSE;
01582 
01583   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01584     {
01585       _dbus_string_free (&decoded);
01586       return FALSE;
01587     }
01588 
01589   if (_dbus_string_get_length (args) != end)
01590     {
01591       _dbus_string_free (&decoded);
01592       if (!send_error (auth, "Invalid hex encoding"))
01593         return FALSE;
01594 
01595       return TRUE;
01596     }
01597 
01598 #ifdef DBUS_ENABLE_VERBOSE_MODE
01599   if (_dbus_string_validate_ascii (&decoded, 0,
01600                                    _dbus_string_get_length (&decoded)))
01601     _dbus_verbose ("%s: data: '%s'\n",
01602                    DBUS_AUTH_NAME (auth),
01603                    _dbus_string_get_const_data (&decoded));
01604 #endif
01605       
01606   if (!(* data_func) (auth, &decoded))
01607     {
01608       _dbus_string_free (&decoded);
01609       return FALSE;
01610     }
01611 
01612   _dbus_string_free (&decoded);
01613   return TRUE;
01614 }
01615 
01616 static dbus_bool_t
01617 handle_auth (DBusAuth *auth, const DBusString *args)
01618 {
01619   if (_dbus_string_get_length (args) == 0)
01620     {
01621       /* No args to the auth, send mechanisms */
01622       if (!send_rejected (auth))
01623         return FALSE;
01624 
01625       return TRUE;
01626     }
01627   else
01628     {
01629       int i;
01630       DBusString mech;
01631       DBusString hex_response;
01632       
01633       _dbus_string_find_blank (args, 0, &i);
01634 
01635       if (!_dbus_string_init (&mech))
01636         return FALSE;
01637 
01638       if (!_dbus_string_init (&hex_response))
01639         {
01640           _dbus_string_free (&mech);
01641           return FALSE;
01642         }
01643       
01644       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01645         goto failed;
01646 
01647       _dbus_string_skip_blank (args, i, &i);
01648       if (!_dbus_string_copy (args, i, &hex_response, 0))
01649         goto failed;
01650      
01651       auth->mech = find_mech (&mech, auth->allowed_mechs);
01652       if (auth->mech != NULL)
01653         {
01654           _dbus_verbose ("%s: Trying mechanism %s\n",
01655                          DBUS_AUTH_NAME (auth),
01656                          auth->mech->mechanism);
01657           
01658           if (!process_data (auth, &hex_response,
01659                              auth->mech->server_data_func))
01660             goto failed;
01661         }
01662       else
01663         {
01664           /* Unsupported mechanism */
01665           _dbus_verbose ("%s: Unsupported mechanism %s\n",
01666                          DBUS_AUTH_NAME (auth),
01667                          _dbus_string_get_const_data (&mech));
01668           
01669           if (!send_rejected (auth))
01670             goto failed;
01671         }
01672 
01673       _dbus_string_free (&mech);      
01674       _dbus_string_free (&hex_response);
01675 
01676       return TRUE;
01677       
01678     failed:
01679       auth->mech = NULL;
01680       _dbus_string_free (&mech);
01681       _dbus_string_free (&hex_response);
01682       return FALSE;
01683     }
01684 }
01685 
01686 static dbus_bool_t
01687 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
01688                                        DBusAuthCommand   command,
01689                                        const DBusString *args)
01690 {
01691   switch (command)
01692     {
01693     case DBUS_AUTH_COMMAND_AUTH:
01694       return handle_auth (auth, args);
01695 
01696     case DBUS_AUTH_COMMAND_CANCEL:
01697     case DBUS_AUTH_COMMAND_DATA:
01698       return send_error (auth, "Not currently in an auth conversation");
01699 
01700     case DBUS_AUTH_COMMAND_BEGIN:
01701       goto_state (auth, &common_state_need_disconnect);
01702       return TRUE;
01703 
01704     case DBUS_AUTH_COMMAND_ERROR:
01705       return send_rejected (auth);
01706 
01707     case DBUS_AUTH_COMMAND_REJECTED:
01708     case DBUS_AUTH_COMMAND_OK:
01709     case DBUS_AUTH_COMMAND_UNKNOWN:
01710     default:
01711       return send_error (auth, "Unknown command");
01712     }
01713 }
01714 
01715 static dbus_bool_t
01716 handle_server_state_waiting_for_data  (DBusAuth         *auth,
01717                                        DBusAuthCommand   command,
01718                                        const DBusString *args)
01719 {
01720   switch (command)
01721     {
01722     case DBUS_AUTH_COMMAND_AUTH:
01723       return send_error (auth, "Sent AUTH while another AUTH in progress");
01724 
01725     case DBUS_AUTH_COMMAND_CANCEL:
01726     case DBUS_AUTH_COMMAND_ERROR:
01727       return send_rejected (auth);
01728 
01729     case DBUS_AUTH_COMMAND_DATA:
01730       return process_data (auth, args, auth->mech->server_data_func);
01731 
01732     case DBUS_AUTH_COMMAND_BEGIN:
01733       goto_state (auth, &common_state_need_disconnect);
01734       return TRUE;
01735 
01736     case DBUS_AUTH_COMMAND_REJECTED:
01737     case DBUS_AUTH_COMMAND_OK:
01738     case DBUS_AUTH_COMMAND_UNKNOWN:
01739     default:
01740       return send_error (auth, "Unknown command");
01741     }
01742 }
01743 
01744 static dbus_bool_t
01745 handle_server_state_waiting_for_begin (DBusAuth         *auth,
01746                                        DBusAuthCommand   command,
01747                                        const DBusString *args)
01748 {
01749   switch (command)
01750     {
01751     case DBUS_AUTH_COMMAND_AUTH:
01752       return send_error (auth, "Sent AUTH while expecting BEGIN");
01753 
01754     case DBUS_AUTH_COMMAND_DATA:
01755       return send_error (auth, "Sent DATA while expecting BEGIN");
01756 
01757     case DBUS_AUTH_COMMAND_BEGIN:
01758       goto_state (auth, &common_state_authenticated);
01759       return TRUE;
01760 
01761     case DBUS_AUTH_COMMAND_REJECTED:
01762     case DBUS_AUTH_COMMAND_OK:
01763     case DBUS_AUTH_COMMAND_UNKNOWN:
01764     default:
01765       return send_error (auth, "Unknown command");
01766 
01767     case DBUS_AUTH_COMMAND_CANCEL:
01768     case DBUS_AUTH_COMMAND_ERROR:
01769       return send_rejected (auth);
01770     }
01771 }
01772 
01773 /* return FALSE if no memory, TRUE if all OK */
01774 static dbus_bool_t
01775 get_word (const DBusString *str,
01776           int              *start,
01777           DBusString       *word)
01778 {
01779   int i;
01780 
01781   _dbus_string_skip_blank (str, *start, start);
01782   _dbus_string_find_blank (str, *start, &i);
01783   
01784   if (i > *start)
01785     {
01786       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01787         return FALSE;
01788       
01789       *start = i;
01790     }
01791 
01792   return TRUE;
01793 }
01794 
01795 static dbus_bool_t
01796 record_mechanisms (DBusAuth         *auth,
01797                    const DBusString *args)
01798 {
01799   int next;
01800   int len;
01801 
01802   if (auth->already_got_mechanisms)
01803     return TRUE;
01804   
01805   len = _dbus_string_get_length (args);
01806   
01807   next = 0;
01808   while (next < len)
01809     {
01810       DBusString m;
01811       const DBusAuthMechanismHandler *mech;
01812       
01813       if (!_dbus_string_init (&m))
01814         goto nomem;
01815       
01816       if (!get_word (args, &next, &m))
01817         {
01818           _dbus_string_free (&m);
01819           goto nomem;
01820         }
01821 
01822       mech = find_mech (&m, auth->allowed_mechs);
01823 
01824       if (mech != NULL)
01825         {
01826           /* FIXME right now we try mechanisms in the order
01827            * the server lists them; should we do them in
01828            * some more deterministic order?
01829            *
01830            * Probably in all_mechanisms order, our order of
01831            * preference. Of course when the server is us,
01832            * it lists things in that order anyhow.
01833            */
01834 
01835           if (mech != &all_mechanisms[0])
01836             {
01837               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01838                              DBUS_AUTH_NAME (auth), mech->mechanism);
01839           
01840               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01841                                       (void*) mech))
01842                 {
01843                   _dbus_string_free (&m);
01844                   goto nomem;
01845                 }
01846             }
01847           else
01848             {
01849               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
01850                              DBUS_AUTH_NAME (auth), mech->mechanism);
01851             }
01852         }
01853       else
01854         {
01855           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01856                          DBUS_AUTH_NAME (auth),
01857                          _dbus_string_get_const_data (&m));
01858         }
01859 
01860       _dbus_string_free (&m);
01861     }
01862   
01863   auth->already_got_mechanisms = TRUE;
01864   
01865   return TRUE;
01866 
01867  nomem:
01868   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01869   
01870   return FALSE;
01871 }
01872 
01873 static dbus_bool_t
01874 process_rejected (DBusAuth *auth, const DBusString *args)
01875 {
01876   const DBusAuthMechanismHandler *mech;
01877   DBusAuthClient *client;
01878 
01879   client = DBUS_AUTH_CLIENT (auth);
01880 
01881   if (!auth->already_got_mechanisms)
01882     {
01883       if (!record_mechanisms (auth, args))
01884         return FALSE;
01885     }
01886   
01887   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01888     {
01889       mech = client->mechs_to_try->data;
01890 
01891       if (!send_auth (auth, mech))
01892         return FALSE;
01893 
01894       _dbus_list_pop_first (&client->mechs_to_try);
01895 
01896       _dbus_verbose ("%s: Trying mechanism %s\n",
01897                      DBUS_AUTH_NAME (auth),
01898                      mech->mechanism);
01899     }
01900   else
01901     {
01902       /* Give up */
01903       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01904                      DBUS_AUTH_NAME (auth));
01905       goto_state (auth, &common_state_need_disconnect);
01906     }
01907   
01908   return TRUE;
01909 }
01910 
01911 
01912 static dbus_bool_t
01913 handle_client_state_waiting_for_data (DBusAuth         *auth,
01914                                       DBusAuthCommand   command,
01915                                       const DBusString *args)
01916 {
01917   _dbus_assert (auth->mech != NULL);
01918  
01919   switch (command)
01920     {
01921     case DBUS_AUTH_COMMAND_DATA:
01922       return process_data (auth, args, auth->mech->client_data_func);
01923 
01924     case DBUS_AUTH_COMMAND_REJECTED:
01925       return process_rejected (auth, args);
01926 
01927     case DBUS_AUTH_COMMAND_OK:
01928       return send_begin (auth, args);
01929 
01930     case DBUS_AUTH_COMMAND_ERROR:
01931       return send_cancel (auth);
01932 
01933     case DBUS_AUTH_COMMAND_AUTH:
01934     case DBUS_AUTH_COMMAND_CANCEL:
01935     case DBUS_AUTH_COMMAND_BEGIN:
01936     case DBUS_AUTH_COMMAND_UNKNOWN:
01937     default:
01938       return send_error (auth, "Unknown command");
01939     }
01940 }
01941 
01942 static dbus_bool_t
01943 handle_client_state_waiting_for_ok (DBusAuth         *auth,
01944                                     DBusAuthCommand   command,
01945                                     const DBusString *args)
01946 {
01947   switch (command)
01948     {
01949     case DBUS_AUTH_COMMAND_REJECTED:
01950       return process_rejected (auth, args);
01951 
01952     case DBUS_AUTH_COMMAND_OK:
01953       return send_begin (auth, args);
01954 
01955     case DBUS_AUTH_COMMAND_DATA:
01956     case DBUS_AUTH_COMMAND_ERROR:
01957       return send_cancel (auth);
01958 
01959     case DBUS_AUTH_COMMAND_AUTH:
01960     case DBUS_AUTH_COMMAND_CANCEL:
01961     case DBUS_AUTH_COMMAND_BEGIN:
01962     case DBUS_AUTH_COMMAND_UNKNOWN:
01963     default:
01964       return send_error (auth, "Unknown command");
01965     }
01966 }
01967 
01968 static dbus_bool_t
01969 handle_client_state_waiting_for_reject (DBusAuth         *auth,
01970                                         DBusAuthCommand   command,
01971                                         const DBusString *args)
01972 {
01973   switch (command)
01974     {
01975     case DBUS_AUTH_COMMAND_REJECTED:
01976       return process_rejected (auth, args);
01977       
01978     case DBUS_AUTH_COMMAND_AUTH:
01979     case DBUS_AUTH_COMMAND_CANCEL:
01980     case DBUS_AUTH_COMMAND_DATA:
01981     case DBUS_AUTH_COMMAND_BEGIN:
01982     case DBUS_AUTH_COMMAND_OK:
01983     case DBUS_AUTH_COMMAND_ERROR:
01984     case DBUS_AUTH_COMMAND_UNKNOWN:
01985     default:
01986       goto_state (auth, &common_state_need_disconnect);
01987       return TRUE;
01988     }
01989 }
01990 
01994 typedef struct {
01995   const char *name;        
01996   DBusAuthCommand command; 
01997 } DBusAuthCommandName;
01998 
01999 static const DBusAuthCommandName auth_command_names[] = {
02000   { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
02001   { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
02002   { "DATA",     DBUS_AUTH_COMMAND_DATA },
02003   { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
02004   { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
02005   { "OK",       DBUS_AUTH_COMMAND_OK },
02006   { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
02007 };
02008 
02009 static DBusAuthCommand
02010 lookup_command_from_name (DBusString *command)
02011 {
02012   int i;
02013 
02014   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
02015     {
02016       if (_dbus_string_equal_c_str (command,
02017                                     auth_command_names[i].name))
02018         return auth_command_names[i].command;
02019     }
02020 
02021   return DBUS_AUTH_COMMAND_UNKNOWN;
02022 }
02023 
02024 static void
02025 goto_state (DBusAuth *auth,
02026             const DBusAuthStateData *state)
02027 {
02028   _dbus_verbose ("%s: going from state %s to state %s\n",
02029                  DBUS_AUTH_NAME (auth),
02030                  auth->state->name,
02031                  state->name);
02032 
02033   auth->state = state;
02034 }
02035 
02036 /* returns whether to call it again right away */
02037 static dbus_bool_t
02038 process_command (DBusAuth *auth)
02039 {
02040   DBusAuthCommand command;
02041   DBusString line;
02042   DBusString args;
02043   int eol;
02044   int i, j;
02045   dbus_bool_t retval;
02046 
02047   /* _dbus_verbose ("%s:   trying process_command()\n"); */
02048   
02049   retval = FALSE;
02050   
02051   eol = 0;
02052   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
02053     return FALSE;
02054   
02055   if (!_dbus_string_init (&line))
02056     {
02057       auth->needed_memory = TRUE;
02058       return FALSE;
02059     }
02060 
02061   if (!_dbus_string_init (&args))
02062     {
02063       _dbus_string_free (&line);
02064       auth->needed_memory = TRUE;
02065       return FALSE;
02066     }
02067   
02068   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
02069     goto out;
02070 
02071   if (!_dbus_string_validate_ascii (&line, 0,
02072                                     _dbus_string_get_length (&line)))
02073     {
02074       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
02075                      DBUS_AUTH_NAME (auth));
02076       if (!send_error (auth, "Command contained non-ASCII"))
02077         goto out;
02078       else
02079         goto next_command;
02080     }
02081   
02082   _dbus_verbose ("%s: got command \"%s\"\n",
02083                  DBUS_AUTH_NAME (auth),
02084                  _dbus_string_get_const_data (&line));
02085   
02086   _dbus_string_find_blank (&line, 0, &i);
02087   _dbus_string_skip_blank (&line, i, &j);
02088 
02089   if (j > i)
02090     _dbus_string_delete (&line, i, j - i);
02091   
02092   if (!_dbus_string_move (&line, i, &args, 0))
02093     goto out;
02094 
02095   /* FIXME 1.0 we should probably validate that only the allowed
02096    * chars are in the command name
02097    */
02098   
02099   command = lookup_command_from_name (&line);
02100   if (!(* auth->state->handler) (auth, command, &args))
02101     goto out;
02102 
02103  next_command:
02104   
02105   /* We've succeeded in processing the whole command so drop it out
02106    * of the incoming buffer and return TRUE to try another command.
02107    */
02108 
02109   _dbus_string_delete (&auth->incoming, 0, eol);
02110   
02111   /* kill the \r\n */
02112   _dbus_string_delete (&auth->incoming, 0, 2);
02113 
02114   retval = TRUE;
02115   
02116  out:
02117   _dbus_string_free (&args);
02118   _dbus_string_free (&line);
02119 
02120   if (!retval)
02121     auth->needed_memory = TRUE;
02122   else
02123     auth->needed_memory = FALSE;
02124   
02125   return retval;
02126 }
02127 
02128 
02143 DBusAuth*
02144 _dbus_auth_server_new (const DBusString *guid)
02145 {
02146   DBusAuth *auth;
02147   DBusAuthServer *server_auth;
02148   DBusString guid_copy;
02149 
02150   if (!_dbus_string_init (&guid_copy))
02151     return NULL;
02152 
02153   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
02154     {
02155       _dbus_string_free (&guid_copy);
02156       return NULL;
02157     }
02158 
02159   auth = _dbus_auth_new (sizeof (DBusAuthServer));
02160   if (auth == NULL)
02161     {
02162       _dbus_string_free (&guid_copy);
02163       return NULL;
02164     }
02165   
02166   auth->side = auth_side_server;
02167   auth->state = &server_state_waiting_for_auth;
02168 
02169   server_auth = DBUS_AUTH_SERVER (auth);
02170 
02171   server_auth->guid = guid_copy;
02172   
02173   /* perhaps this should be per-mechanism with a lower
02174    * max
02175    */
02176   server_auth->failures = 0;
02177   server_auth->max_failures = 6;
02178   
02179   return auth;
02180 }
02181 
02189 DBusAuth*
02190 _dbus_auth_client_new (void)
02191 {
02192   DBusAuth *auth;
02193   DBusString guid_str;
02194 
02195   if (!_dbus_string_init (&guid_str))
02196     return NULL;
02197 
02198   auth = _dbus_auth_new (sizeof (DBusAuthClient));
02199   if (auth == NULL)
02200     {
02201       _dbus_string_free (&guid_str);
02202       return NULL;
02203     }
02204 
02205   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02206 
02207   auth->side = auth_side_client;
02208   auth->state = &client_state_need_send_auth;
02209 
02210   /* Start the auth conversation by sending AUTH for our default
02211    * mechanism */
02212   if (!send_auth (auth, &all_mechanisms[0]))
02213     {
02214       _dbus_auth_unref (auth);
02215       return NULL;
02216     }
02217   
02218   return auth;
02219 }
02220 
02227 DBusAuth *
02228 _dbus_auth_ref (DBusAuth *auth)
02229 {
02230   _dbus_assert (auth != NULL);
02231   
02232   auth->refcount += 1;
02233   
02234   return auth;
02235 }
02236 
02242 void
02243 _dbus_auth_unref (DBusAuth *auth)
02244 {
02245   _dbus_assert (auth != NULL);
02246   _dbus_assert (auth->refcount > 0);
02247 
02248   auth->refcount -= 1;
02249   if (auth->refcount == 0)
02250     {
02251       shutdown_mech (auth);
02252 
02253       if (DBUS_AUTH_IS_CLIENT (auth))
02254         {
02255           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02256           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02257         }
02258       else
02259         {
02260           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02261 
02262           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02263         }
02264 
02265       if (auth->keyring)
02266         _dbus_keyring_unref (auth->keyring);
02267 
02268       _dbus_string_free (&auth->context);
02269       _dbus_string_free (&auth->challenge);
02270       _dbus_string_free (&auth->identity);
02271       _dbus_string_free (&auth->incoming);
02272       _dbus_string_free (&auth->outgoing);
02273 
02274       dbus_free_string_array (auth->allowed_mechs);
02275 
02276       _dbus_credentials_unref (auth->credentials);
02277       _dbus_credentials_unref (auth->authorized_identity);
02278       _dbus_credentials_unref (auth->desired_identity);
02279       
02280       dbus_free (auth);
02281     }
02282 }
02283 
02292 dbus_bool_t
02293 _dbus_auth_set_mechanisms (DBusAuth    *auth,
02294                            const char **mechanisms)
02295 {
02296   char **copy;
02297 
02298   if (mechanisms != NULL)
02299     {
02300       copy = _dbus_dup_string_array (mechanisms);
02301       if (copy == NULL)
02302         return FALSE;
02303     }
02304   else
02305     copy = NULL;
02306   
02307   dbus_free_string_array (auth->allowed_mechs);
02308 
02309   auth->allowed_mechs = copy;
02310 
02311   return TRUE;
02312 }
02313 
02318 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02319 
02327 DBusAuthState
02328 _dbus_auth_do_work (DBusAuth *auth)
02329 {
02330   auth->needed_memory = FALSE;
02331 
02332   /* Max amount we'll buffer up before deciding someone's on crack */
02333 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02334 
02335   do
02336     {
02337       if (DBUS_AUTH_IN_END_STATE (auth))
02338         break;
02339       
02340       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02341           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02342         {
02343           goto_state (auth, &common_state_need_disconnect);
02344           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02345                          DBUS_AUTH_NAME (auth));
02346           break;
02347         }
02348     }
02349   while (process_command (auth));
02350 
02351   if (auth->needed_memory)
02352     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02353   else if (_dbus_string_get_length (&auth->outgoing) > 0)
02354     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02355   else if (auth->state == &common_state_need_disconnect)
02356     return DBUS_AUTH_STATE_NEED_DISCONNECT;
02357   else if (auth->state == &common_state_authenticated)
02358     return DBUS_AUTH_STATE_AUTHENTICATED;
02359   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02360 }
02361 
02371 dbus_bool_t
02372 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
02373                               const DBusString **str)
02374 {
02375   _dbus_assert (auth != NULL);
02376   _dbus_assert (str != NULL);
02377 
02378   *str = NULL;
02379   
02380   if (_dbus_string_get_length (&auth->outgoing) == 0)
02381     return FALSE;
02382 
02383   *str = &auth->outgoing;
02384 
02385   return TRUE;
02386 }
02387 
02396 void
02397 _dbus_auth_bytes_sent (DBusAuth *auth,
02398                        int       bytes_sent)
02399 {
02400   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02401                  DBUS_AUTH_NAME (auth),
02402                  bytes_sent,
02403                  _dbus_string_get_const_data (&auth->outgoing));
02404   
02405   _dbus_string_delete (&auth->outgoing,
02406                        0, bytes_sent);
02407 }
02408 
02416 void
02417 _dbus_auth_get_buffer (DBusAuth     *auth,
02418                        DBusString **buffer)
02419 {
02420   _dbus_assert (auth != NULL);
02421   _dbus_assert (!auth->buffer_outstanding);
02422   
02423   *buffer = &auth->incoming;
02424 
02425   auth->buffer_outstanding = TRUE;
02426 }
02427 
02435 void
02436 _dbus_auth_return_buffer (DBusAuth               *auth,
02437                           DBusString             *buffer,
02438                           int                     bytes_read)
02439 {
02440   _dbus_assert (buffer == &auth->incoming);
02441   _dbus_assert (auth->buffer_outstanding);
02442 
02443   auth->buffer_outstanding = FALSE;
02444 }
02445 
02455 void
02456 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
02457                              const DBusString **str)
02458 {
02459   if (!DBUS_AUTH_IN_END_STATE (auth))
02460     return;
02461 
02462   *str = &auth->incoming;
02463 }
02464 
02465 
02472 void
02473 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02474 {
02475   if (!DBUS_AUTH_IN_END_STATE (auth))
02476     return;
02477 
02478   _dbus_string_set_length (&auth->incoming, 0);
02479 }
02480 
02489 dbus_bool_t
02490 _dbus_auth_needs_encoding (DBusAuth *auth)
02491 {
02492   if (auth->state != &common_state_authenticated)
02493     return FALSE;
02494   
02495   if (auth->mech != NULL)
02496     {
02497       if (DBUS_AUTH_IS_CLIENT (auth))
02498         return auth->mech->client_encode_func != NULL;
02499       else
02500         return auth->mech->server_encode_func != NULL;
02501     }
02502   else
02503     return FALSE;
02504 }
02505 
02516 dbus_bool_t
02517 _dbus_auth_encode_data (DBusAuth         *auth,
02518                         const DBusString *plaintext,
02519                         DBusString       *encoded)
02520 {
02521   _dbus_assert (plaintext != encoded);
02522   
02523   if (auth->state != &common_state_authenticated)
02524     return FALSE;
02525   
02526   if (_dbus_auth_needs_encoding (auth))
02527     {
02528       if (DBUS_AUTH_IS_CLIENT (auth))
02529         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02530       else
02531         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02532     }
02533   else
02534     {
02535       return _dbus_string_copy (plaintext, 0, encoded,
02536                                 _dbus_string_get_length (encoded));
02537     }
02538 }
02539 
02548 dbus_bool_t
02549 _dbus_auth_needs_decoding (DBusAuth *auth)
02550 {
02551   if (auth->state != &common_state_authenticated)
02552     return FALSE;
02553     
02554   if (auth->mech != NULL)
02555     {
02556       if (DBUS_AUTH_IS_CLIENT (auth))
02557         return auth->mech->client_decode_func != NULL;
02558       else
02559         return auth->mech->server_decode_func != NULL;
02560     }
02561   else
02562     return FALSE;
02563 }
02564 
02565 
02579 dbus_bool_t
02580 _dbus_auth_decode_data (DBusAuth         *auth,
02581                         const DBusString *encoded,
02582                         DBusString       *plaintext)
02583 {
02584   _dbus_assert (plaintext != encoded);
02585   
02586   if (auth->state != &common_state_authenticated)
02587     return FALSE;
02588   
02589   if (_dbus_auth_needs_decoding (auth))
02590     {
02591       if (DBUS_AUTH_IS_CLIENT (auth))
02592         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02593       else
02594         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02595     }
02596   else
02597     {
02598       return _dbus_string_copy (encoded, 0, plaintext,
02599                                 _dbus_string_get_length (plaintext));
02600     }
02601 }
02602 
02611 dbus_bool_t
02612 _dbus_auth_set_credentials (DBusAuth               *auth,
02613                             DBusCredentials        *credentials)
02614 {
02615   _dbus_credentials_clear (auth->credentials);
02616   return _dbus_credentials_add_credentials (auth->credentials,
02617                                             credentials);
02618 }
02619 
02629 DBusCredentials*
02630 _dbus_auth_get_identity (DBusAuth               *auth)
02631 {
02632   if (auth->state == &common_state_authenticated)
02633     {
02634       return auth->authorized_identity;
02635     }
02636   else
02637     {
02638       /* FIXME instead of this, keep an empty credential around that
02639        * doesn't require allocation or something
02640        */
02641       /* return empty credentials */
02642       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
02643       return auth->authorized_identity;
02644     }
02645 }
02646 
02653 const char*
02654 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02655 {
02656   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02657   
02658   if (auth->state == &common_state_authenticated)
02659     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02660   else
02661     return NULL;
02662 }
02663 
02672 dbus_bool_t
02673 _dbus_auth_set_context (DBusAuth               *auth,
02674                         const DBusString       *context)
02675 {
02676   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02677                                    &auth->context, 0, _dbus_string_get_length (context));
02678 }
02679 
02682 /* tests in dbus-auth-util.c */

Generated on Mon Feb 1 19:15:25 2010 for D-Bus by  doxygen 1.4.7