Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      2 /* dbus-auth.c Authentication
      3  *
      4  * Copyright (C) 2002, 2003, 2004 Red Hat Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21  *
     22  */
     23 #include "dbus-auth.h"
     24 #include "dbus-string.h"
     25 #include "dbus-list.h"
     26 #include "dbus-internals.h"
     27 #include "dbus-keyring.h"
     28 #include "dbus-sha.h"
     29 #include "dbus-protocol.h"
     30 #include "dbus-userdb.h"
     31 
     32 /**
     33  * @defgroup DBusAuth Authentication
     34  * @ingroup  DBusInternals
     35  * @brief DBusAuth object
     36  *
     37  * DBusAuth manages the authentication negotiation when a connection
     38  * is first established, and also manage any encryption used over a
     39  * connection.
     40  *
     41  * @todo some SASL profiles require sending the empty string as a
     42  * challenge/response, but we don't currently allow that in our
     43  * protocol.
     44  *
     45  * @todo right now sometimes both ends will block waiting for input
     46  * from the other end, e.g. if there's an error during
     47  * DBUS_COOKIE_SHA1.
     48  *
     49  * @todo the cookie keyring needs to be cached globally not just
     50  * per-auth (which raises threadsafety issues too)
     51  *
     52  * @todo grep FIXME in dbus-auth.c
     53  */
     54 
     55 /**
     56  * @defgroup DBusAuthInternals Authentication implementation details
     57  * @ingroup  DBusInternals
     58  * @brief DBusAuth implementation details
     59  *
     60  * Private details of authentication code.
     61  *
     62  * @{
     63  */
     64 
     65 /**
     66  * This function appends an initial client response to the given string
     67  */
     68 typedef dbus_bool_t (* DBusInitialResponseFunction)  (DBusAuth         *auth,
     69                                                       DBusString       *response);
     70 
     71 /**
     72  * This function processes a block of data received from the peer.
     73  * i.e. handles a DATA command.
     74  */
     75 typedef dbus_bool_t (* DBusAuthDataFunction)     (DBusAuth         *auth,
     76                                                   const DBusString *data);
     77 
     78 /**
     79  * This function encodes a block of data from the peer.
     80  */
     81 typedef dbus_bool_t (* DBusAuthEncodeFunction)   (DBusAuth         *auth,
     82                                                   const DBusString *data,
     83                                                   DBusString       *encoded);
     84 
     85 /**
     86  * This function decodes a block of data from the peer.
     87  */
     88 typedef dbus_bool_t (* DBusAuthDecodeFunction)   (DBusAuth         *auth,
     89                                                   const DBusString *data,
     90                                                   DBusString       *decoded);
     91 
     92 /**
     93  * This function is called when the mechanism is abandoned.
     94  */
     95 typedef void        (* DBusAuthShutdownFunction) (DBusAuth       *auth);
     96 
     97 /**
     98  * Virtual table representing a particular auth mechanism.
     99  */
    100 typedef struct
    101 {
    102   const char *mechanism; /**< Name of the mechanism */
    103   DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */
    104   DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */
    105   DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */
    106   DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */
    107   DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */
    108   DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */
    109   DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */
    110   DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */
    111   DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */
    112 } DBusAuthMechanismHandler;
    113 
    114 /**
    115  * Enumeration for the known authentication commands.
    116  */
    117 typedef enum {
    118   DBUS_AUTH_COMMAND_AUTH,
    119   DBUS_AUTH_COMMAND_CANCEL,
    120   DBUS_AUTH_COMMAND_DATA,
    121   DBUS_AUTH_COMMAND_BEGIN,
    122   DBUS_AUTH_COMMAND_REJECTED,
    123   DBUS_AUTH_COMMAND_OK,
    124   DBUS_AUTH_COMMAND_ERROR,
    125   DBUS_AUTH_COMMAND_UNKNOWN
    126 } DBusAuthCommand;
    127 
    128 /**
    129  * Auth state function, determines the reaction to incoming events for
    130  * a particular state. Returns whether we had enough memory to
    131  * complete the operation.
    132  */
    133 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth         *auth,
    134                                                DBusAuthCommand   command,
    135                                                const DBusString *args);
    136 
    137 /**
    138  * Information about a auth state.
    139  */
    140 typedef struct
    141 {
    142   const char *name;               /**< Name of the state */
    143   DBusAuthStateFunction handler;  /**< State function for this state */
    144 } DBusAuthStateData;
    145 
    146 /**
    147  * Internal members of DBusAuth.
    148  */
    149 struct DBusAuth
    150 {
    151   int refcount;           /**< reference count */
    152   const char *side;       /**< Client or server */
    153 
    154   DBusString incoming;    /**< Incoming data buffer */
    155   DBusString outgoing;    /**< Outgoing data buffer */
    156 
    157   const DBusAuthStateData *state;         /**< Current protocol state */
    158 
    159   const DBusAuthMechanismHandler *mech;   /**< Current auth mechanism */
    160 
    161   DBusString identity;                   /**< Current identity we're authorizing
    162                                           *   as.
    163                                           */
    164 
    165   DBusCredentials credentials;      /**< Credentials read from socket,
    166                                      * fields may be -1
    167                                      */
    168 
    169   DBusCredentials authorized_identity; /**< Credentials that are authorized */
    170 
    171   DBusCredentials desired_identity;    /**< Identity client has requested */
    172 
    173   DBusString context;               /**< Cookie scope */
    174   DBusKeyring *keyring;             /**< Keyring for cookie mechanism. */
    175   int cookie_id;                    /**< ID of cookie to use */
    176   DBusString challenge;             /**< Challenge sent to client */
    177 
    178   char **allowed_mechs;             /**< Mechanisms we're allowed to use,
    179                                      * or #NULL if we can use any
    180                                      */
    181 
    182   unsigned int needed_memory : 1;   /**< We needed memory to continue since last
    183                                      * successful getting something done
    184                                      */
    185   unsigned int already_got_mechanisms : 1;       /**< Client already got mech list */
    186   unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */
    187   unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
    188 };
    189 
    190 /**
    191  * "Subclass" of DBusAuth for client side
    192  */
    193 typedef struct
    194 {
    195   DBusAuth base;    /**< Parent class */
    196 
    197   DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */
    198 
    199   DBusString guid_from_server; /**< GUID received from server */
    200 
    201 } DBusAuthClient;
    202 
    203 /**
    204  * "Subclass" of DBusAuth for server side.
    205  */
    206 typedef struct
    207 {
    208   DBusAuth base;    /**< Parent class */
    209 
    210   int failures;     /**< Number of times client has been rejected */
    211   int max_failures; /**< Number of times we reject before disconnect */
    212 
    213   DBusString guid;  /**< Our globally unique ID in hex encoding */
    214 
    215 } DBusAuthServer;
    216 
    217 static void        goto_state                (DBusAuth                       *auth,
    218                                               const DBusAuthStateData        *new_state);
    219 static dbus_bool_t send_auth                 (DBusAuth *auth,
    220                                               const DBusAuthMechanismHandler *mech);
    221 static dbus_bool_t send_data                 (DBusAuth *auth,
    222                                               DBusString *data);
    223 static dbus_bool_t send_rejected             (DBusAuth *auth);
    224 static dbus_bool_t send_error                (DBusAuth *auth,
    225                                               const char *message);
    226 static dbus_bool_t send_ok                   (DBusAuth *auth);
    227 static dbus_bool_t send_begin                (DBusAuth *auth,
    228                                               const DBusString *args_from_ok);
    229 static dbus_bool_t send_cancel               (DBusAuth *auth);
    230 
    231 /**
    232  * Client states
    233  */
    234 
    235 static dbus_bool_t handle_server_state_waiting_for_auth  (DBusAuth         *auth,
    236                                                           DBusAuthCommand   command,
    237                                                           const DBusString *args);
    238 static dbus_bool_t handle_server_state_waiting_for_data  (DBusAuth         *auth,
    239                                                           DBusAuthCommand   command,
    240                                                           const DBusString *args);
    241 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth         *auth,
    242                                                           DBusAuthCommand   command,
    243                                                           const DBusString *args);
    244 
    245 static const DBusAuthStateData server_state_waiting_for_auth = {
    246   "WaitingForAuth", handle_server_state_waiting_for_auth
    247 };
    248 static const DBusAuthStateData server_state_waiting_for_data = {
    249   "WaitingForData", handle_server_state_waiting_for_data
    250 };
    251 static const DBusAuthStateData server_state_waiting_for_begin = {
    252   "WaitingForBegin", handle_server_state_waiting_for_begin
    253 };
    254 
    255 /**
    256  * Client states
    257  */
    258 
    259 static dbus_bool_t handle_client_state_waiting_for_data   (DBusAuth         *auth,
    260                                                            DBusAuthCommand   command,
    261                                                            const DBusString *args);
    262 static dbus_bool_t handle_client_state_waiting_for_ok     (DBusAuth         *auth,
    263                                                            DBusAuthCommand   command,
    264                                                            const DBusString *args);
    265 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth         *auth,
    266                                                            DBusAuthCommand   command,
    267                                                            const DBusString *args);
    268 
    269 static const DBusAuthStateData client_state_need_send_auth = {
    270   "NeedSendAuth", NULL
    271 };
    272 static const DBusAuthStateData client_state_waiting_for_data = {
    273   "WaitingForData", handle_client_state_waiting_for_data
    274 };
    275 static const DBusAuthStateData client_state_waiting_for_ok = {
    276   "WaitingForOK", handle_client_state_waiting_for_ok
    277 };
    278 static const DBusAuthStateData client_state_waiting_for_reject = {
    279   "WaitingForReject", handle_client_state_waiting_for_reject
    280 };
    281 
    282 /**
    283  * Common terminal states.  Terminal states have handler == NULL.
    284  */
    285 
    286 static const DBusAuthStateData common_state_authenticated = {
    287   "Authenticated",  NULL
    288 };
    289 
    290 static const DBusAuthStateData common_state_need_disconnect = {
    291   "NeedDisconnect",  NULL
    292 };
    293 
    294 static const char auth_side_client[] = "client";
    295 static const char auth_side_server[] = "server";
    296 /**
    297  * @param auth the auth conversation
    298  * @returns #TRUE if the conversation is the server side
    299  */
    300 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
    301 /**
    302  * @param auth the auth conversation
    303  * @returns #TRUE if the conversation is the client side
    304  */
    305 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
    306 /**
    307  * @param auth the auth conversation
    308  * @returns auth cast to DBusAuthClient
    309  */
    310 #define DBUS_AUTH_CLIENT(auth)    ((DBusAuthClient*)(auth))
    311 /**
    312  * @param auth the auth conversation
    313  * @returns auth cast to DBusAuthServer
    314  */
    315 #define DBUS_AUTH_SERVER(auth)    ((DBusAuthServer*)(auth))
    316 
    317 /**
    318  * The name of the auth ("client" or "server")
    319  * @param auth the auth conversation
    320  * @returns a string
    321  */
    322 #define DBUS_AUTH_NAME(auth)      ((auth)->side)
    323 
    324 static DBusAuth*
    325 _dbus_auth_new (int size)
    326 {
    327   DBusAuth *auth;
    328 
    329   auth = dbus_malloc0 (size);
    330   if (auth == NULL)
    331     return NULL;
    332 
    333   auth->refcount = 1;
    334 
    335   _dbus_credentials_clear (&auth->credentials);
    336   _dbus_credentials_clear (&auth->authorized_identity);
    337   _dbus_credentials_clear (&auth->desired_identity);
    338 
    339   auth->keyring = NULL;
    340   auth->cookie_id = -1;
    341 
    342   /* note that we don't use the max string length feature,
    343    * because you can't use that feature if you're going to
    344    * try to recover from out-of-memory (it creates
    345    * what looks like unrecoverable inability to alloc
    346    * more space in the string). But we do handle
    347    * overlong buffers in _dbus_auth_do_work().
    348    */
    349 
    350   if (!_dbus_string_init (&auth->incoming))
    351     goto enomem_0;
    352 
    353   if (!_dbus_string_init (&auth->outgoing))
    354     goto enomem_1;
    355 
    356   if (!_dbus_string_init (&auth->identity))
    357     goto enomem_2;
    358 
    359   if (!_dbus_string_init (&auth->context))
    360     goto enomem_3;
    361 
    362   if (!_dbus_string_init (&auth->challenge))
    363     goto enomem_4;
    364 
    365   /* default context if none is specified */
    366   if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
    367     goto enomem_5;
    368 
    369   return auth;
    370 
    371  enomem_5:
    372   _dbus_string_free (&auth->challenge);
    373  enomem_4:
    374   _dbus_string_free (&auth->context);
    375  enomem_3:
    376   _dbus_string_free (&auth->identity);
    377  enomem_2:
    378   _dbus_string_free (&auth->outgoing);
    379  enomem_1:
    380   _dbus_string_free (&auth->incoming);
    381  enomem_0:
    382   dbus_free (auth);
    383   return NULL;
    384 }
    385 
    386 static void
    387 shutdown_mech (DBusAuth *auth)
    388 {
    389   /* Cancel any auth */
    390   auth->already_asked_for_initial_response = FALSE;
    391   _dbus_string_set_length (&auth->identity, 0);
    392 
    393   _dbus_credentials_clear (&auth->authorized_identity);
    394   _dbus_credentials_clear (&auth->desired_identity);
    395 
    396   if (auth->mech != NULL)
    397     {
    398       _dbus_verbose ("%s: Shutting down mechanism %s\n",
    399                      DBUS_AUTH_NAME (auth), auth->mech->mechanism);
    400 
    401       if (DBUS_AUTH_IS_CLIENT (auth))
    402         (* auth->mech->client_shutdown_func) (auth);
    403       else
    404         (* auth->mech->server_shutdown_func) (auth);
    405 
    406       auth->mech = NULL;
    407     }
    408 }
    409 
    410 /* Returns TRUE but with an empty string hash if the
    411  * cookie_id isn't known. As with all this code
    412  * TRUE just means we had enough memory.
    413  */
    414 static dbus_bool_t
    415 sha1_compute_hash (DBusAuth         *auth,
    416                    int               cookie_id,
    417                    const DBusString *server_challenge,
    418                    const DBusString *client_challenge,
    419                    DBusString       *hash)
    420 {
    421   DBusString cookie;
    422   DBusString to_hash;
    423   dbus_bool_t retval;
    424 
    425   _dbus_assert (auth->keyring != NULL);
    426 
    427   retval = FALSE;
    428 
    429   if (!_dbus_string_init (&cookie))
    430     return FALSE;
    431 
    432   if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
    433                                   &cookie))
    434     goto out_0;
    435 
    436   if (_dbus_string_get_length (&cookie) == 0)
    437     {
    438       retval = TRUE;
    439       goto out_0;
    440     }
    441 
    442   if (!_dbus_string_init (&to_hash))
    443     goto out_0;
    444 
    445   if (!_dbus_string_copy (server_challenge, 0,
    446                           &to_hash, _dbus_string_get_length (&to_hash)))
    447     goto out_1;
    448 
    449   if (!_dbus_string_append (&to_hash, ":"))
    450     goto out_1;
    451 
    452   if (!_dbus_string_copy (client_challenge, 0,
    453                           &to_hash, _dbus_string_get_length (&to_hash)))
    454     goto out_1;
    455 
    456   if (!_dbus_string_append (&to_hash, ":"))
    457     goto out_1;
    458 
    459   if (!_dbus_string_copy (&cookie, 0,
    460                           &to_hash, _dbus_string_get_length (&to_hash)))
    461     goto out_1;
    462 
    463   if (!_dbus_sha_compute (&to_hash, hash))
    464     goto out_1;
    465 
    466   retval = TRUE;
    467 
    468  out_1:
    469   _dbus_string_zero (&to_hash);
    470   _dbus_string_free (&to_hash);
    471  out_0:
    472   _dbus_string_zero (&cookie);
    473   _dbus_string_free (&cookie);
    474   return retval;
    475 }
    476 
    477 /** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of
    478  * entropy, we use 128. This is the number of bytes in the random
    479  * challenge.
    480  */
    481 #define N_CHALLENGE_BYTES (128/8)
    482 
    483 static dbus_bool_t
    484 sha1_handle_first_client_response (DBusAuth         *auth,
    485                                    const DBusString *data)
    486 {
    487   /* We haven't sent a challenge yet, we're expecting a desired
    488    * username from the client.
    489    */
    490   DBusString tmp;
    491   DBusString tmp2;
    492   dbus_bool_t retval;
    493   DBusError error;
    494 
    495   retval = FALSE;
    496 
    497   _dbus_string_set_length (&auth->challenge, 0);
    498 
    499   if (_dbus_string_get_length (data) > 0)
    500     {
    501       if (_dbus_string_get_length (&auth->identity) > 0)
    502         {
    503           /* Tried to send two auth identities, wtf */
    504           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
    505                          DBUS_AUTH_NAME (auth));
    506           return send_rejected (auth);
    507         }
    508       else
    509         {
    510           /* this is our auth identity */
    511           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
    512             return FALSE;
    513         }
    514     }
    515 
    516   if (!_dbus_credentials_from_username (data, &auth->desired_identity))
    517     {
    518       _dbus_verbose ("%s: Did not get a valid username from client\n",
    519                      DBUS_AUTH_NAME (auth));
    520       return send_rejected (auth);
    521     }
    522 
    523   if (!_dbus_string_init (&tmp))
    524     return FALSE;
    525 
    526   if (!_dbus_string_init (&tmp2))
    527     {
    528       _dbus_string_free (&tmp);
    529       return FALSE;
    530     }
    531 
    532   /* we cache the keyring for speed, so here we drop it if it's the
    533    * wrong one. FIXME caching the keyring here is useless since we use
    534    * a different DBusAuth for every connection.
    535    */
    536   if (auth->keyring &&
    537       !_dbus_keyring_is_for_user (auth->keyring,
    538                                   data))
    539     {
    540       _dbus_keyring_unref (auth->keyring);
    541       auth->keyring = NULL;
    542     }
    543 
    544   if (auth->keyring == NULL)
    545     {
    546       dbus_error_init (&error);
    547       auth->keyring = _dbus_keyring_new_homedir (data,
    548                                                  &auth->context,
    549                                                  &error);
    550 
    551       if (auth->keyring == NULL)
    552         {
    553           if (dbus_error_has_name (&error,
    554                                    DBUS_ERROR_NO_MEMORY))
    555             {
    556               dbus_error_free (&error);
    557               goto out;
    558             }
    559           else
    560             {
    561               _DBUS_ASSERT_ERROR_IS_SET (&error);
    562               _dbus_verbose ("%s: Error loading keyring: %s\n",
    563                              DBUS_AUTH_NAME (auth), error.message);
    564               if (send_rejected (auth))
    565                 retval = TRUE; /* retval is only about mem */
    566               dbus_error_free (&error);
    567               goto out;
    568             }
    569         }
    570       else
    571         {
    572           _dbus_assert (!dbus_error_is_set (&error));
    573         }
    574     }
    575 
    576   _dbus_assert (auth->keyring != NULL);
    577 
    578   dbus_error_init (&error);
    579   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
    580   if (auth->cookie_id < 0)
    581     {
    582       _DBUS_ASSERT_ERROR_IS_SET (&error);
    583       _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
    584                      DBUS_AUTH_NAME (auth), error.message);
    585       if (send_rejected (auth))
    586         retval = TRUE;
    587       dbus_error_free (&error);
    588       goto out;
    589     }
    590   else
    591     {
    592       _dbus_assert (!dbus_error_is_set (&error));
    593     }
    594 
    595   if (!_dbus_string_copy (&auth->context, 0,
    596                           &tmp2, _dbus_string_get_length (&tmp2)))
    597     goto out;
    598 
    599   if (!_dbus_string_append (&tmp2, " "))
    600     goto out;
    601 
    602   if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
    603     goto out;
    604 
    605   if (!_dbus_string_append (&tmp2, " "))
    606     goto out;
    607 
    608   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
    609     goto out;
    610 
    611   _dbus_string_set_length (&auth->challenge, 0);
    612   if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
    613     goto out;
    614 
    615   if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
    616                                 _dbus_string_get_length (&tmp2)))
    617     goto out;
    618 
    619   if (!send_data (auth, &tmp2))
    620     goto out;
    621 
    622   goto_state (auth, &server_state_waiting_for_data);
    623   retval = TRUE;
    624 
    625  out:
    626   _dbus_string_zero (&tmp);
    627   _dbus_string_free (&tmp);
    628   _dbus_string_zero (&tmp2);
    629   _dbus_string_free (&tmp2);
    630 
    631   return retval;
    632 }
    633 
    634 static dbus_bool_t
    635 sha1_handle_second_client_response (DBusAuth         *auth,
    636                                     const DBusString *data)
    637 {
    638   /* We are expecting a response which is the hex-encoded client
    639    * challenge, space, then SHA-1 hash of the concatenation of our
    640    * challenge, ":", client challenge, ":", secret key, all
    641    * hex-encoded.
    642    */
    643   int i;
    644   DBusString client_challenge;
    645   DBusString client_hash;
    646   dbus_bool_t retval;
    647   DBusString correct_hash;
    648 
    649   retval = FALSE;
    650 
    651   if (!_dbus_string_find_blank (data, 0, &i))
    652     {
    653       _dbus_verbose ("%s: no space separator in client response\n",
    654                      DBUS_AUTH_NAME (auth));
    655       return send_rejected (auth);
    656     }
    657 
    658   if (!_dbus_string_init (&client_challenge))
    659     goto out_0;
    660 
    661   if (!_dbus_string_init (&client_hash))
    662     goto out_1;
    663 
    664   if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
    665                               0))
    666     goto out_2;
    667 
    668   _dbus_string_skip_blank (data, i, &i);
    669 
    670   if (!_dbus_string_copy_len (data, i,
    671                               _dbus_string_get_length (data) - i,
    672                               &client_hash,
    673                               0))
    674     goto out_2;
    675 
    676   if (_dbus_string_get_length (&client_challenge) == 0 ||
    677       _dbus_string_get_length (&client_hash) == 0)
    678     {
    679       _dbus_verbose ("%s: zero-length client challenge or hash\n",
    680                      DBUS_AUTH_NAME (auth));
    681       if (send_rejected (auth))
    682         retval = TRUE;
    683       goto out_2;
    684     }
    685 
    686   if (!_dbus_string_init (&correct_hash))
    687     goto out_2;
    688 
    689   if (!sha1_compute_hash (auth, auth->cookie_id,
    690                           &auth->challenge,
    691                           &client_challenge,
    692                           &correct_hash))
    693     goto out_3;
    694 
    695   /* if cookie_id was invalid, then we get an empty hash */
    696   if (_dbus_string_get_length (&correct_hash) == 0)
    697     {
    698       if (send_rejected (auth))
    699         retval = TRUE;
    700       goto out_3;
    701     }
    702 
    703   if (!_dbus_string_equal (&client_hash, &correct_hash))
    704     {
    705       if (send_rejected (auth))
    706         retval = TRUE;
    707       goto out_3;
    708     }
    709 
    710   if (!send_ok (auth))
    711     goto out_3;
    712 
    713   _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n",
    714                  DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
    715 
    716   auth->authorized_identity = auth->desired_identity;
    717   retval = TRUE;
    718 
    719  out_3:
    720   _dbus_string_zero (&correct_hash);
    721   _dbus_string_free (&correct_hash);
    722  out_2:
    723   _dbus_string_zero (&client_hash);
    724   _dbus_string_free (&client_hash);
    725  out_1:
    726   _dbus_string_free (&client_challenge);
    727  out_0:
    728   return retval;
    729 }
    730 
    731 static dbus_bool_t
    732 handle_server_data_cookie_sha1_mech (DBusAuth         *auth,
    733                                      const DBusString *data)
    734 {
    735   if (auth->cookie_id < 0)
    736     return sha1_handle_first_client_response (auth, data);
    737   else
    738     return sha1_handle_second_client_response (auth, data);
    739 }
    740 
    741 static void
    742 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
    743 {
    744   auth->cookie_id = -1;
    745   _dbus_string_set_length (&auth->challenge, 0);
    746 }
    747 
    748 static dbus_bool_t
    749 handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
    750                                                  DBusString *response)
    751 {
    752   const DBusString *username;
    753   dbus_bool_t retval;
    754 
    755   retval = FALSE;
    756 
    757   if (!_dbus_username_from_current_process (&username))
    758     goto out_0;
    759 
    760   if (!_dbus_string_hex_encode (username, 0,
    761 				response,
    762 				_dbus_string_get_length (response)))
    763     goto out_0;
    764 
    765   retval = TRUE;
    766 
    767  out_0:
    768   return retval;
    769 }
    770 
    771 static dbus_bool_t
    772 handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
    773                                      const DBusString *data)
    774 {
    775   /* The data we get from the server should be the cookie context
    776    * name, the cookie ID, and the server challenge, separated by
    777    * spaces. We send back our challenge string and the correct hash.
    778    */
    779   dbus_bool_t retval;
    780   DBusString context;
    781   DBusString cookie_id_str;
    782   DBusString server_challenge;
    783   DBusString client_challenge;
    784   DBusString correct_hash;
    785   DBusString tmp;
    786   int i, j;
    787   long val;
    788 
    789   retval = FALSE;
    790 
    791   if (!_dbus_string_find_blank (data, 0, &i))
    792     {
    793       if (send_error (auth,
    794                       "Server did not send context/ID/challenge properly"))
    795         retval = TRUE;
    796       goto out_0;
    797     }
    798 
    799   if (!_dbus_string_init (&context))
    800     goto out_0;
    801 
    802   if (!_dbus_string_copy_len (data, 0, i,
    803                               &context, 0))
    804     goto out_1;
    805 
    806   _dbus_string_skip_blank (data, i, &i);
    807   if (!_dbus_string_find_blank (data, i, &j))
    808     {
    809       if (send_error (auth,
    810                       "Server did not send context/ID/challenge properly"))
    811         retval = TRUE;
    812       goto out_1;
    813     }
    814 
    815   if (!_dbus_string_init (&cookie_id_str))
    816     goto out_1;
    817 
    818   if (!_dbus_string_copy_len (data, i, j - i,
    819                               &cookie_id_str, 0))
    820     goto out_2;
    821 
    822   if (!_dbus_string_init (&server_challenge))
    823     goto out_2;
    824 
    825   i = j;
    826   _dbus_string_skip_blank (data, i, &i);
    827   j = _dbus_string_get_length (data);
    828 
    829   if (!_dbus_string_copy_len (data, i, j - i,
    830                               &server_challenge, 0))
    831     goto out_3;
    832 
    833   if (!_dbus_keyring_validate_context (&context))
    834     {
    835       if (send_error (auth, "Server sent invalid cookie context"))
    836         retval = TRUE;
    837       goto out_3;
    838     }
    839 
    840   if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
    841     {
    842       if (send_error (auth, "Could not parse cookie ID as an integer"))
    843         retval = TRUE;
    844       goto out_3;
    845     }
    846 
    847   if (_dbus_string_get_length (&server_challenge) == 0)
    848     {
    849       if (send_error (auth, "Empty server challenge string"))
    850         retval = TRUE;
    851       goto out_3;
    852     }
    853 
    854   if (auth->keyring == NULL)
    855     {
    856       DBusError error;
    857 
    858       dbus_error_init (&error);
    859       auth->keyring = _dbus_keyring_new_homedir (NULL,
    860                                                  &context,
    861                                                  &error);
    862 
    863       if (auth->keyring == NULL)
    864         {
    865           if (dbus_error_has_name (&error,
    866                                    DBUS_ERROR_NO_MEMORY))
    867             {
    868               dbus_error_free (&error);
    869               goto out_3;
    870             }
    871           else
    872             {
    873               _DBUS_ASSERT_ERROR_IS_SET (&error);
    874 
    875               _dbus_verbose ("%s: Error loading keyring: %s\n",
    876                              DBUS_AUTH_NAME (auth), error.message);
    877 
    878               if (send_error (auth, "Could not load cookie file"))
    879                 retval = TRUE; /* retval is only about mem */
    880 
    881               dbus_error_free (&error);
    882               goto out_3;
    883             }
    884         }
    885       else
    886         {
    887           _dbus_assert (!dbus_error_is_set (&error));
    888         }
    889     }
    890 
    891   _dbus_assert (auth->keyring != NULL);
    892 
    893   if (!_dbus_string_init (&tmp))
    894     goto out_3;
    895 
    896   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
    897     goto out_4;
    898 
    899   if (!_dbus_string_init (&client_challenge))
    900     goto out_4;
    901 
    902   if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
    903     goto out_5;
    904 
    905   if (!_dbus_string_init (&correct_hash))
    906     goto out_5;
    907 
    908   if (!sha1_compute_hash (auth, val,
    909                           &server_challenge,
    910                           &client_challenge,
    911                           &correct_hash))
    912     goto out_6;
    913 
    914   if (_dbus_string_get_length (&correct_hash) == 0)
    915     {
    916       /* couldn't find the cookie ID or something */
    917       if (send_error (auth, "Don't have the requested cookie ID"))
    918         retval = TRUE;
    919       goto out_6;
    920     }
    921 
    922   _dbus_string_set_length (&tmp, 0);
    923 
    924   if (!_dbus_string_copy (&client_challenge, 0, &tmp,
    925                           _dbus_string_get_length (&tmp)))
    926     goto out_6;
    927 
    928   if (!_dbus_string_append (&tmp, " "))
    929     goto out_6;
    930 
    931   if (!_dbus_string_copy (&correct_hash, 0, &tmp,
    932                           _dbus_string_get_length (&tmp)))
    933     goto out_6;
    934 
    935   if (!send_data (auth, &tmp))
    936     goto out_6;
    937 
    938   retval = TRUE;
    939 
    940  out_6:
    941   _dbus_string_zero (&correct_hash);
    942   _dbus_string_free (&correct_hash);
    943  out_5:
    944   _dbus_string_free (&client_challenge);
    945  out_4:
    946   _dbus_string_zero (&tmp);
    947   _dbus_string_free (&tmp);
    948  out_3:
    949   _dbus_string_free (&server_challenge);
    950  out_2:
    951   _dbus_string_free (&cookie_id_str);
    952  out_1:
    953   _dbus_string_free (&context);
    954  out_0:
    955   return retval;
    956 }
    957 
    958 static void
    959 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
    960 {
    961   auth->cookie_id = -1;
    962   _dbus_string_set_length (&auth->challenge, 0);
    963 }
    964 
    965 static dbus_bool_t
    966 handle_server_data_external_mech (DBusAuth         *auth,
    967                                   const DBusString *data)
    968 {
    969   if (auth->credentials.uid == DBUS_UID_UNSET)
    970     {
    971       _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
    972                      DBUS_AUTH_NAME (auth));
    973       return send_rejected (auth);
    974     }
    975 
    976   if (_dbus_string_get_length (data) > 0)
    977     {
    978       if (_dbus_string_get_length (&auth->identity) > 0)
    979         {
    980           /* Tried to send two auth identities, wtf */
    981           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
    982                          DBUS_AUTH_NAME (auth));
    983           return send_rejected (auth);
    984         }
    985       else
    986         {
    987           /* this is our auth identity */
    988           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
    989             return FALSE;
    990         }
    991     }
    992 
    993   /* Poke client for an auth identity, if none given */
    994   if (_dbus_string_get_length (&auth->identity) == 0 &&
    995       !auth->already_asked_for_initial_response)
    996     {
    997       if (send_data (auth, NULL))
    998         {
    999           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
   1000                          DBUS_AUTH_NAME (auth));
   1001           auth->already_asked_for_initial_response = TRUE;
   1002           return TRUE;
   1003         }
   1004       else
   1005         return FALSE;
   1006     }
   1007 
   1008   _dbus_credentials_clear (&auth->desired_identity);
   1009 
   1010   /* If auth->identity is still empty here, then client
   1011    * responded with an empty string after we poked it for
   1012    * an initial response. This means to try to auth the
   1013    * identity provided in the credentials.
   1014    */
   1015   if (_dbus_string_get_length (&auth->identity) == 0)
   1016     {
   1017       auth->desired_identity.uid = auth->credentials.uid;
   1018     }
   1019   else
   1020     {
   1021       if (!_dbus_parse_uid (&auth->identity,
   1022                             &auth->desired_identity.uid))
   1023         {
   1024           _dbus_verbose ("%s: could not get credentials from uid string\n",
   1025                          DBUS_AUTH_NAME (auth));
   1026           return send_rejected (auth);
   1027         }
   1028     }
   1029 
   1030   if (auth->desired_identity.uid == DBUS_UID_UNSET)
   1031     {
   1032       _dbus_verbose ("%s: desired user %s is no good\n",
   1033                      DBUS_AUTH_NAME (auth),
   1034                      _dbus_string_get_const_data (&auth->identity));
   1035       return send_rejected (auth);
   1036     }
   1037 
   1038   if (_dbus_credentials_match (&auth->desired_identity,
   1039                                &auth->credentials))
   1040     {
   1041       /* client has authenticated */
   1042       if (!send_ok (auth))
   1043         return FALSE;
   1044 
   1045       _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
   1046                      " matching socket credentials UID "DBUS_UID_FORMAT"\n",
   1047                      DBUS_AUTH_NAME (auth),
   1048                      auth->desired_identity.uid,
   1049                      auth->credentials.uid);
   1050 
   1051       auth->authorized_identity.pid = auth->credentials.pid;
   1052       auth->authorized_identity.uid = auth->desired_identity.uid;
   1053       return TRUE;
   1054     }
   1055   else
   1056     {
   1057       _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
   1058                      " gid="DBUS_GID_FORMAT
   1059                      " do not allow uid="DBUS_UID_FORMAT
   1060                      " gid="DBUS_GID_FORMAT"\n",
   1061                      DBUS_AUTH_NAME (auth),
   1062                      auth->credentials.uid, auth->credentials.gid,
   1063                      auth->desired_identity.uid, auth->desired_identity.gid);
   1064       return send_rejected (auth);
   1065     }
   1066 }
   1067 
   1068 static void
   1069 handle_server_shutdown_external_mech (DBusAuth *auth)
   1070 {
   1071 
   1072 }
   1073 
   1074 static dbus_bool_t
   1075 handle_client_initial_response_external_mech (DBusAuth         *auth,
   1076                                               DBusString       *response)
   1077 {
   1078   /* We always append our UID as an initial response, so the server
   1079    * doesn't have to send back an empty challenge to check whether we
   1080    * want to specify an identity. i.e. this avoids a round trip that
   1081    * the spec for the EXTERNAL mechanism otherwise requires.
   1082    */
   1083   DBusString plaintext;
   1084 
   1085   if (!_dbus_string_init (&plaintext))
   1086     return FALSE;
   1087 
   1088   if (!_dbus_string_append_uint (&plaintext,
   1089                                  _dbus_getuid ()))
   1090     goto failed;
   1091 
   1092   if (!_dbus_string_hex_encode (&plaintext, 0,
   1093 				response,
   1094 				_dbus_string_get_length (response)))
   1095     goto failed;
   1096 
   1097   _dbus_string_free (&plaintext);
   1098 
   1099   return TRUE;
   1100 
   1101  failed:
   1102   _dbus_string_free (&plaintext);
   1103   return FALSE;
   1104 }
   1105 
   1106 static dbus_bool_t
   1107 handle_client_data_external_mech (DBusAuth         *auth,
   1108                                   const DBusString *data)
   1109 {
   1110 
   1111   return TRUE;
   1112 }
   1113 
   1114 static void
   1115 handle_client_shutdown_external_mech (DBusAuth *auth)
   1116 {
   1117 
   1118 }
   1119 
   1120 /* Put mechanisms here in order of preference.
   1121  * What I eventually want to have is:
   1122  *
   1123  *  - a mechanism that checks UNIX domain socket credentials
   1124  *  - a simple magic cookie mechanism like X11 or ICE
   1125  *  - mechanisms that chain to Cyrus SASL, so we can use anything it
   1126  *    offers such as Kerberos, X509, whatever.
   1127  *
   1128  */
   1129 static const DBusAuthMechanismHandler
   1130 all_mechanisms[] = {
   1131   { "EXTERNAL",
   1132     handle_server_data_external_mech,
   1133     NULL, NULL,
   1134     handle_server_shutdown_external_mech,
   1135     handle_client_initial_response_external_mech,
   1136     handle_client_data_external_mech,
   1137     NULL, NULL,
   1138     handle_client_shutdown_external_mech },
   1139   { "DBUS_COOKIE_SHA1",
   1140     handle_server_data_cookie_sha1_mech,
   1141     NULL, NULL,
   1142     handle_server_shutdown_cookie_sha1_mech,
   1143     handle_client_initial_response_cookie_sha1_mech,
   1144     handle_client_data_cookie_sha1_mech,
   1145     NULL, NULL,
   1146     handle_client_shutdown_cookie_sha1_mech },
   1147   { NULL, NULL }
   1148 };
   1149 
   1150 static const DBusAuthMechanismHandler*
   1151 find_mech (const DBusString  *name,
   1152            char             **allowed_mechs)
   1153 {
   1154   int i;
   1155 
   1156   if (allowed_mechs != NULL &&
   1157       !_dbus_string_array_contains ((const char**) allowed_mechs,
   1158                                     _dbus_string_get_const_data (name)))
   1159     return NULL;
   1160 
   1161   i = 0;
   1162   while (all_mechanisms[i].mechanism != NULL)
   1163     {
   1164       if (_dbus_string_equal_c_str (name,
   1165                                     all_mechanisms[i].mechanism))
   1166 
   1167         return &all_mechanisms[i];
   1168 
   1169       ++i;
   1170     }
   1171 
   1172   return NULL;
   1173 }
   1174 
   1175 static dbus_bool_t
   1176 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
   1177 {
   1178   DBusString auth_command;
   1179 
   1180   if (!_dbus_string_init (&auth_command))
   1181     return FALSE;
   1182 
   1183   if (!_dbus_string_append (&auth_command,
   1184                             "AUTH "))
   1185     {
   1186       _dbus_string_free (&auth_command);
   1187       return FALSE;
   1188     }
   1189 
   1190   if (!_dbus_string_append (&auth_command,
   1191                             mech->mechanism))
   1192     {
   1193       _dbus_string_free (&auth_command);
   1194       return FALSE;
   1195     }
   1196 
   1197   if (mech->client_initial_response_func != NULL)
   1198     {
   1199       if (!_dbus_string_append (&auth_command, " "))
   1200         {
   1201           _dbus_string_free (&auth_command);
   1202           return FALSE;
   1203         }
   1204 
   1205       if (!(* mech->client_initial_response_func) (auth, &auth_command))
   1206         {
   1207           _dbus_string_free (&auth_command);
   1208           return FALSE;
   1209         }
   1210     }
   1211 
   1212   if (!_dbus_string_append (&auth_command,
   1213                             "\r\n"))
   1214     {
   1215       _dbus_string_free (&auth_command);
   1216       return FALSE;
   1217     }
   1218 
   1219   if (!_dbus_string_copy (&auth_command, 0,
   1220                           &auth->outgoing,
   1221                           _dbus_string_get_length (&auth->outgoing)))
   1222     {
   1223       _dbus_string_free (&auth_command);
   1224       return FALSE;
   1225     }
   1226 
   1227   _dbus_string_free (&auth_command);
   1228   shutdown_mech (auth);
   1229   auth->mech = mech;
   1230   goto_state (auth, &client_state_waiting_for_data);
   1231 
   1232   return TRUE;
   1233 }
   1234 
   1235 static dbus_bool_t
   1236 send_data (DBusAuth *auth, DBusString *data)
   1237 {
   1238   int old_len;
   1239 
   1240   if (data == NULL || _dbus_string_get_length (data) == 0)
   1241     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
   1242   else
   1243     {
   1244       old_len = _dbus_string_get_length (&auth->outgoing);
   1245       if (!_dbus_string_append (&auth->outgoing, "DATA "))
   1246         goto out;
   1247 
   1248       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
   1249                                     _dbus_string_get_length (&auth->outgoing)))
   1250         goto out;
   1251 
   1252       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
   1253         goto out;
   1254 
   1255       return TRUE;
   1256 
   1257     out:
   1258       _dbus_string_set_length (&auth->outgoing, old_len);
   1259 
   1260       return FALSE;
   1261     }
   1262 }
   1263 
   1264 static dbus_bool_t
   1265 send_rejected (DBusAuth *auth)
   1266 {
   1267   DBusString command;
   1268   DBusAuthServer *server_auth;
   1269   int i;
   1270 
   1271   if (!_dbus_string_init (&command))
   1272     return FALSE;
   1273 
   1274   if (!_dbus_string_append (&command,
   1275                             "REJECTED"))
   1276     goto nomem;
   1277 
   1278   i = 0;
   1279   while (all_mechanisms[i].mechanism != NULL)
   1280     {
   1281       if (!_dbus_string_append (&command,
   1282                                 " "))
   1283         goto nomem;
   1284 
   1285       if (!_dbus_string_append (&command,
   1286                                 all_mechanisms[i].mechanism))
   1287         goto nomem;
   1288 
   1289       ++i;
   1290     }
   1291 
   1292   if (!_dbus_string_append (&command, "\r\n"))
   1293     goto nomem;
   1294 
   1295   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
   1296                           _dbus_string_get_length (&auth->outgoing)))
   1297     goto nomem;
   1298 
   1299   shutdown_mech (auth);
   1300 
   1301   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
   1302   server_auth = DBUS_AUTH_SERVER (auth);
   1303   server_auth->failures += 1;
   1304 
   1305   if (server_auth->failures >= server_auth->max_failures)
   1306     goto_state (auth, &common_state_need_disconnect);
   1307   else
   1308     goto_state (auth, &server_state_waiting_for_auth);
   1309 
   1310   _dbus_string_free (&command);
   1311 
   1312   return TRUE;
   1313 
   1314  nomem:
   1315   _dbus_string_free (&command);
   1316   return FALSE;
   1317 }
   1318 
   1319 static dbus_bool_t
   1320 send_error (DBusAuth *auth, const char *message)
   1321 {
   1322   return _dbus_string_append_printf (&auth->outgoing,
   1323                                      "ERROR \"%s\"\r\n", message);
   1324 }
   1325 
   1326 static dbus_bool_t
   1327 send_ok (DBusAuth *auth)
   1328 {
   1329   int orig_len;
   1330 
   1331   orig_len = _dbus_string_get_length (&auth->outgoing);
   1332 
   1333   if (_dbus_string_append (&auth->outgoing, "OK ") &&
   1334       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
   1335                          0,
   1336                          &auth->outgoing,
   1337                          _dbus_string_get_length (&auth->outgoing)) &&
   1338       _dbus_string_append (&auth->outgoing, "\r\n"))
   1339     {
   1340       goto_state (auth, &server_state_waiting_for_begin);
   1341       return TRUE;
   1342     }
   1343   else
   1344     {
   1345       _dbus_string_set_length (&auth->outgoing, orig_len);
   1346       return FALSE;
   1347     }
   1348 }
   1349 
   1350 static dbus_bool_t
   1351 send_begin (DBusAuth         *auth,
   1352             const DBusString *args_from_ok)
   1353 {
   1354   int end_of_hex;
   1355 
   1356   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
   1357   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
   1358 
   1359   /* We decode the hex string to binary, using guid_from_server as scratch... */
   1360 
   1361   end_of_hex = 0;
   1362   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
   1363                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
   1364     return FALSE;
   1365 
   1366   /* now clear out the scratch */
   1367   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
   1368 
   1369   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
   1370       end_of_hex == 0)
   1371     {
   1372       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
   1373                      end_of_hex, _dbus_string_get_length (args_from_ok));
   1374       goto_state (auth, &common_state_need_disconnect);
   1375       return TRUE;
   1376     }
   1377 
   1378   if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
   1379       _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
   1380     {
   1381       _dbus_verbose ("Got GUID '%s' from the server\n",
   1382                      _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
   1383 
   1384       goto_state (auth, &common_state_authenticated);
   1385       return TRUE;
   1386     }
   1387   else
   1388     {
   1389       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
   1390       return FALSE;
   1391     }
   1392 }
   1393 
   1394 static dbus_bool_t
   1395 send_cancel (DBusAuth *auth)
   1396 {
   1397   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
   1398     {
   1399       goto_state (auth, &client_state_waiting_for_reject);
   1400       return TRUE;
   1401     }
   1402   else
   1403     return FALSE;
   1404 }
   1405 
   1406 static dbus_bool_t
   1407 process_data (DBusAuth             *auth,
   1408               const DBusString     *args,
   1409               DBusAuthDataFunction  data_func)
   1410 {
   1411   int end;
   1412   DBusString decoded;
   1413 
   1414   if (!_dbus_string_init (&decoded))
   1415     return FALSE;
   1416 
   1417   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
   1418     {
   1419       _dbus_string_free (&decoded);
   1420       return FALSE;
   1421     }
   1422 
   1423   if (_dbus_string_get_length (args) != end)
   1424     {
   1425       _dbus_string_free (&decoded);
   1426       if (!send_error (auth, "Invalid hex encoding"))
   1427         return FALSE;
   1428 
   1429       return TRUE;
   1430     }
   1431 
   1432 #ifdef DBUS_ENABLE_VERBOSE_MODE
   1433   if (_dbus_string_validate_ascii (&decoded, 0,
   1434                                    _dbus_string_get_length (&decoded)))
   1435     _dbus_verbose ("%s: data: '%s'\n",
   1436                    DBUS_AUTH_NAME (auth),
   1437                    _dbus_string_get_const_data (&decoded));
   1438 #endif
   1439 
   1440   if (!(* data_func) (auth, &decoded))
   1441     {
   1442       _dbus_string_free (&decoded);
   1443       return FALSE;
   1444     }
   1445 
   1446   _dbus_string_free (&decoded);
   1447   return TRUE;
   1448 }
   1449 
   1450 static dbus_bool_t
   1451 handle_auth (DBusAuth *auth, const DBusString *args)
   1452 {
   1453   if (_dbus_string_get_length (args) == 0)
   1454     {
   1455       /* No args to the auth, send mechanisms */
   1456       if (!send_rejected (auth))
   1457         return FALSE;
   1458 
   1459       return TRUE;
   1460     }
   1461   else
   1462     {
   1463       int i;
   1464       DBusString mech;
   1465       DBusString hex_response;
   1466 
   1467       _dbus_string_find_blank (args, 0, &i);
   1468 
   1469       if (!_dbus_string_init (&mech))
   1470         return FALSE;
   1471 
   1472       if (!_dbus_string_init (&hex_response))
   1473         {
   1474           _dbus_string_free (&mech);
   1475           return FALSE;
   1476         }
   1477 
   1478       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
   1479         goto failed;
   1480 
   1481       _dbus_string_skip_blank (args, i, &i);
   1482       if (!_dbus_string_copy (args, i, &hex_response, 0))
   1483         goto failed;
   1484 
   1485       auth->mech = find_mech (&mech, auth->allowed_mechs);
   1486       if (auth->mech != NULL)
   1487         {
   1488           _dbus_verbose ("%s: Trying mechanism %s\n",
   1489                          DBUS_AUTH_NAME (auth),
   1490                          auth->mech->mechanism);
   1491 
   1492           if (!process_data (auth, &hex_response,
   1493                              auth->mech->server_data_func))
   1494             goto failed;
   1495         }
   1496       else
   1497         {
   1498           /* Unsupported mechanism */
   1499           _dbus_verbose ("%s: Unsupported mechanism %s\n",
   1500                          DBUS_AUTH_NAME (auth),
   1501                          _dbus_string_get_const_data (&mech));
   1502 
   1503           if (!send_rejected (auth))
   1504             goto failed;
   1505         }
   1506 
   1507       _dbus_string_free (&mech);
   1508       _dbus_string_free (&hex_response);
   1509 
   1510       return TRUE;
   1511 
   1512     failed:
   1513       auth->mech = NULL;
   1514       _dbus_string_free (&mech);
   1515       _dbus_string_free (&hex_response);
   1516       return FALSE;
   1517     }
   1518 }
   1519 
   1520 static dbus_bool_t
   1521 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
   1522                                        DBusAuthCommand   command,
   1523                                        const DBusString *args)
   1524 {
   1525   switch (command)
   1526     {
   1527     case DBUS_AUTH_COMMAND_AUTH:
   1528       return handle_auth (auth, args);
   1529 
   1530     case DBUS_AUTH_COMMAND_CANCEL:
   1531     case DBUS_AUTH_COMMAND_DATA:
   1532       return send_error (auth, "Not currently in an auth conversation");
   1533 
   1534     case DBUS_AUTH_COMMAND_BEGIN:
   1535       goto_state (auth, &common_state_need_disconnect);
   1536       return TRUE;
   1537 
   1538     case DBUS_AUTH_COMMAND_ERROR:
   1539       return send_rejected (auth);
   1540 
   1541     case DBUS_AUTH_COMMAND_REJECTED:
   1542     case DBUS_AUTH_COMMAND_OK:
   1543     case DBUS_AUTH_COMMAND_UNKNOWN:
   1544     default:
   1545       return send_error (auth, "Unknown command");
   1546     }
   1547 }
   1548 
   1549 static dbus_bool_t
   1550 handle_server_state_waiting_for_data  (DBusAuth         *auth,
   1551                                        DBusAuthCommand   command,
   1552                                        const DBusString *args)
   1553 {
   1554   switch (command)
   1555     {
   1556     case DBUS_AUTH_COMMAND_AUTH:
   1557       return send_error (auth, "Sent AUTH while another AUTH in progress");
   1558 
   1559     case DBUS_AUTH_COMMAND_CANCEL:
   1560     case DBUS_AUTH_COMMAND_ERROR:
   1561       return send_rejected (auth);
   1562 
   1563     case DBUS_AUTH_COMMAND_DATA:
   1564       return process_data (auth, args, auth->mech->server_data_func);
   1565 
   1566     case DBUS_AUTH_COMMAND_BEGIN:
   1567       goto_state (auth, &common_state_need_disconnect);
   1568       return TRUE;
   1569 
   1570     case DBUS_AUTH_COMMAND_REJECTED:
   1571     case DBUS_AUTH_COMMAND_OK:
   1572     case DBUS_AUTH_COMMAND_UNKNOWN:
   1573     default:
   1574       return send_error (auth, "Unknown command");
   1575     }
   1576 }
   1577 
   1578 static dbus_bool_t
   1579 handle_server_state_waiting_for_begin (DBusAuth         *auth,
   1580                                        DBusAuthCommand   command,
   1581                                        const DBusString *args)
   1582 {
   1583   switch (command)
   1584     {
   1585     case DBUS_AUTH_COMMAND_AUTH:
   1586       return send_error (auth, "Sent AUTH while expecting BEGIN");
   1587 
   1588     case DBUS_AUTH_COMMAND_DATA:
   1589       return send_error (auth, "Sent DATA while expecting BEGIN");
   1590 
   1591     case DBUS_AUTH_COMMAND_BEGIN:
   1592       goto_state (auth, &common_state_authenticated);
   1593       return TRUE;
   1594 
   1595     case DBUS_AUTH_COMMAND_REJECTED:
   1596     case DBUS_AUTH_COMMAND_OK:
   1597     case DBUS_AUTH_COMMAND_UNKNOWN:
   1598     default:
   1599       return send_error (auth, "Unknown command");
   1600 
   1601     case DBUS_AUTH_COMMAND_CANCEL:
   1602     case DBUS_AUTH_COMMAND_ERROR:
   1603       return send_rejected (auth);
   1604     }
   1605 }
   1606 
   1607 /* return FALSE if no memory, TRUE if all OK */
   1608 static dbus_bool_t
   1609 get_word (const DBusString *str,
   1610           int              *start,
   1611           DBusString       *word)
   1612 {
   1613   int i;
   1614 
   1615   _dbus_string_skip_blank (str, *start, start);
   1616   _dbus_string_find_blank (str, *start, &i);
   1617 
   1618   if (i > *start)
   1619     {
   1620       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
   1621         return FALSE;
   1622 
   1623       *start = i;
   1624     }
   1625 
   1626   return TRUE;
   1627 }
   1628 
   1629 static dbus_bool_t
   1630 record_mechanisms (DBusAuth         *auth,
   1631                    const DBusString *args)
   1632 {
   1633   int next;
   1634   int len;
   1635 
   1636   if (auth->already_got_mechanisms)
   1637     return TRUE;
   1638 
   1639   len = _dbus_string_get_length (args);
   1640 
   1641   next = 0;
   1642   while (next < len)
   1643     {
   1644       DBusString m;
   1645       const DBusAuthMechanismHandler *mech;
   1646 
   1647       if (!_dbus_string_init (&m))
   1648         goto nomem;
   1649 
   1650       if (!get_word (args, &next, &m))
   1651         {
   1652           _dbus_string_free (&m);
   1653           goto nomem;
   1654         }
   1655 
   1656       mech = find_mech (&m, auth->allowed_mechs);
   1657 
   1658       if (mech != NULL)
   1659         {
   1660           /* FIXME right now we try mechanisms in the order
   1661            * the server lists them; should we do them in
   1662            * some more deterministic order?
   1663            *
   1664            * Probably in all_mechanisms order, our order of
   1665            * preference. Of course when the server is us,
   1666            * it lists things in that order anyhow.
   1667            */
   1668 
   1669           if (mech != &all_mechanisms[0])
   1670             {
   1671               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
   1672                              DBUS_AUTH_NAME (auth), mech->mechanism);
   1673 
   1674               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
   1675                                       (void*) mech))
   1676                 {
   1677                   _dbus_string_free (&m);
   1678                   goto nomem;
   1679                 }
   1680             }
   1681           else
   1682             {
   1683               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
   1684                              DBUS_AUTH_NAME (auth), mech->mechanism);
   1685             }
   1686         }
   1687       else
   1688         {
   1689           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
   1690                          DBUS_AUTH_NAME (auth),
   1691                          _dbus_string_get_const_data (&m));
   1692         }
   1693 
   1694       _dbus_string_free (&m);
   1695     }
   1696 
   1697   auth->already_got_mechanisms = TRUE;
   1698 
   1699   return TRUE;
   1700 
   1701  nomem:
   1702   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
   1703 
   1704   return FALSE;
   1705 }
   1706 
   1707 static dbus_bool_t
   1708 process_rejected (DBusAuth *auth, const DBusString *args)
   1709 {
   1710   const DBusAuthMechanismHandler *mech;
   1711   DBusAuthClient *client;
   1712 
   1713   client = DBUS_AUTH_CLIENT (auth);
   1714 
   1715   if (!auth->already_got_mechanisms)
   1716     {
   1717       if (!record_mechanisms (auth, args))
   1718         return FALSE;
   1719     }
   1720 
   1721   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
   1722     {
   1723       mech = client->mechs_to_try->data;
   1724 
   1725       if (!send_auth (auth, mech))
   1726         return FALSE;
   1727 
   1728       _dbus_list_pop_first (&client->mechs_to_try);
   1729 
   1730       _dbus_verbose ("%s: Trying mechanism %s\n",
   1731                      DBUS_AUTH_NAME (auth),
   1732                      mech->mechanism);
   1733     }
   1734   else
   1735     {
   1736       /* Give up */
   1737       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
   1738                      DBUS_AUTH_NAME (auth));
   1739       goto_state (auth, &common_state_need_disconnect);
   1740     }
   1741 
   1742   return TRUE;
   1743 }
   1744 
   1745 
   1746 static dbus_bool_t
   1747 handle_client_state_waiting_for_data (DBusAuth         *auth,
   1748                                       DBusAuthCommand   command,
   1749                                       const DBusString *args)
   1750 {
   1751   _dbus_assert (auth->mech != NULL);
   1752 
   1753   switch (command)
   1754     {
   1755     case DBUS_AUTH_COMMAND_DATA:
   1756       return process_data (auth, args, auth->mech->client_data_func);
   1757 
   1758     case DBUS_AUTH_COMMAND_REJECTED:
   1759       return process_rejected (auth, args);
   1760 
   1761     case DBUS_AUTH_COMMAND_OK:
   1762       return send_begin (auth, args);
   1763 
   1764     case DBUS_AUTH_COMMAND_ERROR:
   1765       return send_cancel (auth);
   1766 
   1767     case DBUS_AUTH_COMMAND_AUTH:
   1768     case DBUS_AUTH_COMMAND_CANCEL:
   1769     case DBUS_AUTH_COMMAND_BEGIN:
   1770     case DBUS_AUTH_COMMAND_UNKNOWN:
   1771     default:
   1772       return send_error (auth, "Unknown command");
   1773     }
   1774 }
   1775 
   1776 static dbus_bool_t
   1777 handle_client_state_waiting_for_ok (DBusAuth         *auth,
   1778                                     DBusAuthCommand   command,
   1779                                     const DBusString *args)
   1780 {
   1781   switch (command)
   1782     {
   1783     case DBUS_AUTH_COMMAND_REJECTED:
   1784       return process_rejected (auth, args);
   1785 
   1786     case DBUS_AUTH_COMMAND_OK:
   1787       return send_begin (auth, args);
   1788 
   1789     case DBUS_AUTH_COMMAND_DATA:
   1790     case DBUS_AUTH_COMMAND_ERROR:
   1791       return send_cancel (auth);
   1792 
   1793     case DBUS_AUTH_COMMAND_AUTH:
   1794     case DBUS_AUTH_COMMAND_CANCEL:
   1795     case DBUS_AUTH_COMMAND_BEGIN:
   1796     case DBUS_AUTH_COMMAND_UNKNOWN:
   1797     default:
   1798       return send_error (auth, "Unknown command");
   1799     }
   1800 }
   1801 
   1802 static dbus_bool_t
   1803 handle_client_state_waiting_for_reject (DBusAuth         *auth,
   1804                                         DBusAuthCommand   command,
   1805                                         const DBusString *args)
   1806 {
   1807   switch (command)
   1808     {
   1809     case DBUS_AUTH_COMMAND_REJECTED:
   1810       return process_rejected (auth, args);
   1811 
   1812     case DBUS_AUTH_COMMAND_AUTH:
   1813     case DBUS_AUTH_COMMAND_CANCEL:
   1814     case DBUS_AUTH_COMMAND_DATA:
   1815     case DBUS_AUTH_COMMAND_BEGIN:
   1816     case DBUS_AUTH_COMMAND_OK:
   1817     case DBUS_AUTH_COMMAND_ERROR:
   1818     case DBUS_AUTH_COMMAND_UNKNOWN:
   1819     default:
   1820       goto_state (auth, &common_state_need_disconnect);
   1821       return TRUE;
   1822     }
   1823 }
   1824 
   1825 /**
   1826  * Mapping from command name to enum
   1827  */
   1828 typedef struct {
   1829   const char *name;        /**< Name of the command */
   1830   DBusAuthCommand command; /**< Corresponding enum */
   1831 } DBusAuthCommandName;
   1832 
   1833 static const DBusAuthCommandName auth_command_names[] = {
   1834   { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
   1835   { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
   1836   { "DATA",     DBUS_AUTH_COMMAND_DATA },
   1837   { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
   1838   { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
   1839   { "OK",       DBUS_AUTH_COMMAND_OK },
   1840   { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
   1841 };
   1842 
   1843 static DBusAuthCommand
   1844 lookup_command_from_name (DBusString *command)
   1845 {
   1846   int i;
   1847 
   1848   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
   1849     {
   1850       if (_dbus_string_equal_c_str (command,
   1851                                     auth_command_names[i].name))
   1852         return auth_command_names[i].command;
   1853     }
   1854 
   1855   return DBUS_AUTH_COMMAND_UNKNOWN;
   1856 }
   1857 
   1858 static void
   1859 goto_state (DBusAuth *auth, const DBusAuthStateData *state)
   1860 {
   1861   _dbus_verbose ("%s: going from state %s to state %s\n",
   1862                  DBUS_AUTH_NAME (auth),
   1863                  auth->state->name,
   1864                  state->name);
   1865 
   1866   auth->state = state;
   1867 }
   1868 
   1869 /* returns whether to call it again right away */
   1870 static dbus_bool_t
   1871 process_command (DBusAuth *auth)
   1872 {
   1873   DBusAuthCommand command;
   1874   DBusString line;
   1875   DBusString args;
   1876   int eol;
   1877   int i, j;
   1878   dbus_bool_t retval;
   1879 
   1880   /* _dbus_verbose ("%s:   trying process_command()\n"); */
   1881 
   1882   retval = FALSE;
   1883 
   1884   eol = 0;
   1885   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
   1886     return FALSE;
   1887 
   1888   if (!_dbus_string_init (&line))
   1889     {
   1890       auth->needed_memory = TRUE;
   1891       return FALSE;
   1892     }
   1893 
   1894   if (!_dbus_string_init (&args))
   1895     {
   1896       _dbus_string_free (&line);
   1897       auth->needed_memory = TRUE;
   1898       return FALSE;
   1899     }
   1900 
   1901   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
   1902     goto out;
   1903 
   1904   if (!_dbus_string_validate_ascii (&line, 0,
   1905                                     _dbus_string_get_length (&line)))
   1906     {
   1907       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
   1908                      DBUS_AUTH_NAME (auth));
   1909       if (!send_error (auth, "Command contained non-ASCII"))
   1910         goto out;
   1911       else
   1912         goto next_command;
   1913     }
   1914 
   1915   _dbus_verbose ("%s: got command \"%s\"\n",
   1916                  DBUS_AUTH_NAME (auth),
   1917                  _dbus_string_get_const_data (&line));
   1918 
   1919   _dbus_string_find_blank (&line, 0, &i);
   1920   _dbus_string_skip_blank (&line, i, &j);
   1921 
   1922   if (j > i)
   1923     _dbus_string_delete (&line, i, j - i);
   1924 
   1925   if (!_dbus_string_move (&line, i, &args, 0))
   1926     goto out;
   1927 
   1928   /* FIXME 1.0 we should probably validate that only the allowed
   1929    * chars are in the command name
   1930    */
   1931 
   1932   command = lookup_command_from_name (&line);
   1933   if (!(* auth->state->handler) (auth, command, &args))
   1934     goto out;
   1935 
   1936  next_command:
   1937 
   1938   /* We've succeeded in processing the whole command so drop it out
   1939    * of the incoming buffer and return TRUE to try another command.
   1940    */
   1941 
   1942   _dbus_string_delete (&auth->incoming, 0, eol);
   1943 
   1944   /* kill the \r\n */
   1945   _dbus_string_delete (&auth->incoming, 0, 2);
   1946 
   1947   retval = TRUE;
   1948 
   1949  out:
   1950   _dbus_string_free (&args);
   1951   _dbus_string_free (&line);
   1952 
   1953   if (!retval)
   1954     auth->needed_memory = TRUE;
   1955   else
   1956     auth->needed_memory = FALSE;
   1957 
   1958   return retval;
   1959 }
   1960 
   1961 
   1962 /** @} */
   1963 
   1964 /**
   1965  * @addtogroup DBusAuth
   1966  * @{
   1967  */
   1968 
   1969 /**
   1970  * Creates a new auth conversation object for the server side.
   1971  * See doc/dbus-sasl-profile.txt for full details on what
   1972  * this object does.
   1973  *
   1974  * @returns the new object or #NULL if no memory
   1975  */
   1976 DBusAuth*
   1977 _dbus_auth_server_new (const DBusString *guid)
   1978 {
   1979   DBusAuth *auth;
   1980   DBusAuthServer *server_auth;
   1981   DBusString guid_copy;
   1982 
   1983   if (!_dbus_string_init (&guid_copy))
   1984     return NULL;
   1985 
   1986   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
   1987     {
   1988       _dbus_string_free (&guid_copy);
   1989       return NULL;
   1990     }
   1991 
   1992   auth = _dbus_auth_new (sizeof (DBusAuthServer));
   1993   if (auth == NULL)
   1994     {
   1995       _dbus_string_free (&guid_copy);
   1996       return NULL;
   1997     }
   1998 
   1999   auth->side = auth_side_server;
   2000   auth->state = &server_state_waiting_for_auth;
   2001 
   2002   server_auth = DBUS_AUTH_SERVER (auth);
   2003 
   2004   server_auth->guid = guid_copy;
   2005 
   2006   /* perhaps this should be per-mechanism with a lower
   2007    * max
   2008    */
   2009   server_auth->failures = 0;
   2010   server_auth->max_failures = 6;
   2011 
   2012   return auth;
   2013 }
   2014 
   2015 /**
   2016  * Creates a new auth conversation object for the client side.
   2017  * See doc/dbus-sasl-profile.txt for full details on what
   2018  * this object does.
   2019  *
   2020  * @returns the new object or #NULL if no memory
   2021  */
   2022 DBusAuth*
   2023 _dbus_auth_client_new (void)
   2024 {
   2025   DBusAuth *auth;
   2026   DBusString guid_str;
   2027 
   2028   if (!_dbus_string_init (&guid_str))
   2029     return NULL;
   2030 
   2031   auth = _dbus_auth_new (sizeof (DBusAuthClient));
   2032   if (auth == NULL)
   2033     {
   2034       _dbus_string_free (&guid_str);
   2035       return NULL;
   2036     }
   2037 
   2038   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
   2039 
   2040   auth->side = auth_side_client;
   2041   auth->state = &client_state_need_send_auth;
   2042 
   2043   /* Start the auth conversation by sending AUTH for our default
   2044    * mechanism */
   2045   if (!send_auth (auth, &all_mechanisms[0]))
   2046     {
   2047       _dbus_auth_unref (auth);
   2048       return NULL;
   2049     }
   2050 
   2051   return auth;
   2052 }
   2053 
   2054 /**
   2055  * Increments the refcount of an auth object.
   2056  *
   2057  * @param auth the auth conversation
   2058  * @returns the auth conversation
   2059  */
   2060 DBusAuth *
   2061 _dbus_auth_ref (DBusAuth *auth)
   2062 {
   2063   _dbus_assert (auth != NULL);
   2064 
   2065   auth->refcount += 1;
   2066 
   2067   return auth;
   2068 }
   2069 
   2070 /**
   2071  * Decrements the refcount of an auth object.
   2072  *
   2073  * @param auth the auth conversation
   2074  */
   2075 void
   2076 _dbus_auth_unref (DBusAuth *auth)
   2077 {
   2078   _dbus_assert (auth != NULL);
   2079   _dbus_assert (auth->refcount > 0);
   2080 
   2081   auth->refcount -= 1;
   2082   if (auth->refcount == 0)
   2083     {
   2084       shutdown_mech (auth);
   2085 
   2086       if (DBUS_AUTH_IS_CLIENT (auth))
   2087         {
   2088           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
   2089           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
   2090         }
   2091       else
   2092         {
   2093           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
   2094 
   2095           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
   2096         }
   2097 
   2098       if (auth->keyring)
   2099         _dbus_keyring_unref (auth->keyring);
   2100 
   2101       _dbus_string_free (&auth->context);
   2102       _dbus_string_free (&auth->challenge);
   2103       _dbus_string_free (&auth->identity);
   2104       _dbus_string_free (&auth->incoming);
   2105       _dbus_string_free (&auth->outgoing);
   2106 
   2107       dbus_free_string_array (auth->allowed_mechs);
   2108 
   2109       dbus_free (auth);
   2110     }
   2111 }
   2112 
   2113 /**
   2114  * Sets an array of authentication mechanism names
   2115  * that we are willing to use.
   2116  *
   2117  * @param auth the auth conversation
   2118  * @param mechanisms #NULL-terminated array of mechanism names
   2119  * @returns #FALSE if no memory
   2120  */
   2121 dbus_bool_t
   2122 _dbus_auth_set_mechanisms (DBusAuth    *auth,
   2123                            const char **mechanisms)
   2124 {
   2125   char **copy;
   2126 
   2127   if (mechanisms != NULL)
   2128     {
   2129       copy = _dbus_dup_string_array (mechanisms);
   2130       if (copy == NULL)
   2131         return FALSE;
   2132     }
   2133   else
   2134     copy = NULL;
   2135 
   2136   dbus_free_string_array (auth->allowed_mechs);
   2137 
   2138   auth->allowed_mechs = copy;
   2139 
   2140   return TRUE;
   2141 }
   2142 
   2143 /**
   2144  * @param auth the auth conversation object
   2145  * @returns #TRUE if we're in a final state
   2146  */
   2147 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
   2148 
   2149 /**
   2150  * Analyzes buffered input and moves the auth conversation forward,
   2151  * returning the new state of the auth conversation.
   2152  *
   2153  * @param auth the auth conversation
   2154  * @returns the new state
   2155  */
   2156 DBusAuthState
   2157 _dbus_auth_do_work (DBusAuth *auth)
   2158 {
   2159   auth->needed_memory = FALSE;
   2160 
   2161   /* Max amount we'll buffer up before deciding someone's on crack */
   2162 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
   2163 
   2164   do
   2165     {
   2166       if (DBUS_AUTH_IN_END_STATE (auth))
   2167         break;
   2168 
   2169       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
   2170           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
   2171         {
   2172           goto_state (auth, &common_state_need_disconnect);
   2173           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
   2174                          DBUS_AUTH_NAME (auth));
   2175           break;
   2176         }
   2177     }
   2178   while (process_command (auth));
   2179 
   2180   if (auth->needed_memory)
   2181     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
   2182   else if (_dbus_string_get_length (&auth->outgoing) > 0)
   2183     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
   2184   else if (auth->state == &common_state_need_disconnect)
   2185     return DBUS_AUTH_STATE_NEED_DISCONNECT;
   2186   else if (auth->state == &common_state_authenticated)
   2187     return DBUS_AUTH_STATE_AUTHENTICATED;
   2188   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
   2189 }
   2190 
   2191 /**
   2192  * Gets bytes that need to be sent to the peer we're conversing with.
   2193  * After writing some bytes, _dbus_auth_bytes_sent() must be called
   2194  * to notify the auth object that they were written.
   2195  *
   2196  * @param auth the auth conversation
   2197  * @param str return location for a ref to the buffer to send
   2198  * @returns #FALSE if nothing to send
   2199  */
   2200 dbus_bool_t
   2201 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
   2202                               const DBusString **str)
   2203 {
   2204   _dbus_assert (auth != NULL);
   2205   _dbus_assert (str != NULL);
   2206 
   2207   *str = NULL;
   2208 
   2209   if (_dbus_string_get_length (&auth->outgoing) == 0)
   2210     return FALSE;
   2211 
   2212   *str = &auth->outgoing;
   2213 
   2214   return TRUE;
   2215 }
   2216 
   2217 /**
   2218  * Notifies the auth conversation object that
   2219  * the given number of bytes of the outgoing buffer
   2220  * have been written out.
   2221  *
   2222  * @param auth the auth conversation
   2223  * @param bytes_sent number of bytes written out
   2224  */
   2225 void
   2226 _dbus_auth_bytes_sent (DBusAuth *auth,
   2227                        int       bytes_sent)
   2228 {
   2229   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
   2230                  DBUS_AUTH_NAME (auth),
   2231                  bytes_sent,
   2232                  _dbus_string_get_const_data (&auth->outgoing));
   2233 
   2234   _dbus_string_delete (&auth->outgoing,
   2235                        0, bytes_sent);
   2236 }
   2237 
   2238 /**
   2239  * Get a buffer to be used for reading bytes from the peer we're conversing
   2240  * with. Bytes should be appended to this buffer.
   2241  *
   2242  * @param auth the auth conversation
   2243  * @param buffer return location for buffer to append bytes to
   2244  */
   2245 void
   2246 _dbus_auth_get_buffer (DBusAuth     *auth,
   2247                        DBusString **buffer)
   2248 {
   2249   _dbus_assert (auth != NULL);
   2250   _dbus_assert (!auth->buffer_outstanding);
   2251 
   2252   *buffer = &auth->incoming;
   2253 
   2254   auth->buffer_outstanding = TRUE;
   2255 }
   2256 
   2257 /**
   2258  * Returns a buffer with new data read into it.
   2259  *
   2260  * @param auth the auth conversation
   2261  * @param buffer the buffer being returned
   2262  * @param bytes_read number of new bytes added
   2263  */
   2264 void
   2265 _dbus_auth_return_buffer (DBusAuth               *auth,
   2266                           DBusString             *buffer,
   2267                           int                     bytes_read)
   2268 {
   2269   _dbus_assert (buffer == &auth->incoming);
   2270   _dbus_assert (auth->buffer_outstanding);
   2271 
   2272   auth->buffer_outstanding = FALSE;
   2273 }
   2274 
   2275 /**
   2276  * Returns leftover bytes that were not used as part of the auth
   2277  * conversation.  These bytes will be part of the message stream
   2278  * instead. This function may not be called until authentication has
   2279  * succeeded.
   2280  *
   2281  * @param auth the auth conversation
   2282  * @param str return location for pointer to string of unused bytes
   2283  */
   2284 void
   2285 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
   2286                              const DBusString **str)
   2287 {
   2288   if (!DBUS_AUTH_IN_END_STATE (auth))
   2289     return;
   2290 
   2291   *str = &auth->incoming;
   2292 }
   2293 
   2294 
   2295 /**
   2296  * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
   2297  * after we've gotten them and successfully moved them elsewhere.
   2298  *
   2299  * @param auth the auth conversation
   2300  */
   2301 void
   2302 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
   2303 {
   2304   if (!DBUS_AUTH_IN_END_STATE (auth))
   2305     return;
   2306 
   2307   _dbus_string_set_length (&auth->incoming, 0);
   2308 }
   2309 
   2310 /**
   2311  * Called post-authentication, indicates whether we need to encode
   2312  * the message stream with _dbus_auth_encode_data() prior to
   2313  * sending it to the peer.
   2314  *
   2315  * @param auth the auth conversation
   2316  * @returns #TRUE if we need to encode the stream
   2317  */
   2318 dbus_bool_t
   2319 _dbus_auth_needs_encoding (DBusAuth *auth)
   2320 {
   2321   if (auth->state != &common_state_authenticated)
   2322     return FALSE;
   2323 
   2324   if (auth->mech != NULL)
   2325     {
   2326       if (DBUS_AUTH_IS_CLIENT (auth))
   2327         return auth->mech->client_encode_func != NULL;
   2328       else
   2329         return auth->mech->server_encode_func != NULL;
   2330     }
   2331   else
   2332     return FALSE;
   2333 }
   2334 
   2335 /**
   2336  * Called post-authentication, encodes a block of bytes for sending to
   2337  * the peer. If no encoding was negotiated, just copies the bytes
   2338  * (you can avoid this by checking _dbus_auth_needs_encoding()).
   2339  *
   2340  * @param auth the auth conversation
   2341  * @param plaintext the plain text data
   2342  * @param encoded initialized string to where encoded data is appended
   2343  * @returns #TRUE if we had enough memory and successfully encoded
   2344  */
   2345 dbus_bool_t
   2346 _dbus_auth_encode_data (DBusAuth         *auth,
   2347                         const DBusString *plaintext,
   2348                         DBusString       *encoded)
   2349 {
   2350   _dbus_assert (plaintext != encoded);
   2351 
   2352   if (auth->state != &common_state_authenticated)
   2353     return FALSE;
   2354 
   2355   if (_dbus_auth_needs_encoding (auth))
   2356     {
   2357       if (DBUS_AUTH_IS_CLIENT (auth))
   2358         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
   2359       else
   2360         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
   2361     }
   2362   else
   2363     {
   2364       return _dbus_string_copy (plaintext, 0, encoded,
   2365                                 _dbus_string_get_length (encoded));
   2366     }
   2367 }
   2368 
   2369 /**
   2370  * Called post-authentication, indicates whether we need to decode
   2371  * the message stream with _dbus_auth_decode_data() after
   2372  * receiving it from the peer.
   2373  *
   2374  * @param auth the auth conversation
   2375  * @returns #TRUE if we need to encode the stream
   2376  */
   2377 dbus_bool_t
   2378 _dbus_auth_needs_decoding (DBusAuth *auth)
   2379 {
   2380   if (auth->state != &common_state_authenticated)
   2381     return FALSE;
   2382 
   2383   if (auth->mech != NULL)
   2384     {
   2385       if (DBUS_AUTH_IS_CLIENT (auth))
   2386         return auth->mech->client_decode_func != NULL;
   2387       else
   2388         return auth->mech->server_decode_func != NULL;
   2389     }
   2390   else
   2391     return FALSE;
   2392 }
   2393 
   2394 
   2395 /**
   2396  * Called post-authentication, decodes a block of bytes received from
   2397  * the peer. If no encoding was negotiated, just copies the bytes (you
   2398  * can avoid this by checking _dbus_auth_needs_decoding()).
   2399  *
   2400  * @todo 1.0? We need to be able to distinguish "out of memory" error
   2401  * from "the data is hosed" error.
   2402  *
   2403  * @param auth the auth conversation
   2404  * @param encoded the encoded data
   2405  * @param plaintext initialized string where decoded data is appended
   2406  * @returns #TRUE if we had enough memory and successfully decoded
   2407  */
   2408 dbus_bool_t
   2409 _dbus_auth_decode_data (DBusAuth         *auth,
   2410                         const DBusString *encoded,
   2411                         DBusString       *plaintext)
   2412 {
   2413   _dbus_assert (plaintext != encoded);
   2414 
   2415   if (auth->state != &common_state_authenticated)
   2416     return FALSE;
   2417 
   2418   if (_dbus_auth_needs_decoding (auth))
   2419     {
   2420       if (DBUS_AUTH_IS_CLIENT (auth))
   2421         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
   2422       else
   2423         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
   2424     }
   2425   else
   2426     {
   2427       return _dbus_string_copy (encoded, 0, plaintext,
   2428                                 _dbus_string_get_length (plaintext));
   2429     }
   2430 }
   2431 
   2432 /**
   2433  * Sets credentials received via reliable means from the operating
   2434  * system.
   2435  *
   2436  * @param auth the auth conversation
   2437  * @param credentials the credentials received
   2438  */
   2439 void
   2440 _dbus_auth_set_credentials (DBusAuth               *auth,
   2441                             const DBusCredentials  *credentials)
   2442 {
   2443   auth->credentials = *credentials;
   2444 }
   2445 
   2446 /**
   2447  * Gets the identity we authorized the client as.  Apps may have
   2448  * different policies as to what identities they allow.
   2449  *
   2450  * @param auth the auth conversation
   2451  * @param credentials the credentials we've authorized
   2452  */
   2453 void
   2454 _dbus_auth_get_identity (DBusAuth               *auth,
   2455                          DBusCredentials        *credentials)
   2456 {
   2457   if (auth->state == &common_state_authenticated)
   2458     *credentials = auth->authorized_identity;
   2459   else
   2460     _dbus_credentials_clear (credentials);
   2461 }
   2462 
   2463 /**
   2464  * Gets the GUID from the server if we've authenticated; gets
   2465  * #NULL otherwise.
   2466  * @param auth the auth object
   2467  * @returns the GUID in ASCII hex format
   2468  */
   2469 const char*
   2470 _dbus_auth_get_guid_from_server (DBusAuth *auth)
   2471 {
   2472   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
   2473 
   2474   if (auth->state == &common_state_authenticated)
   2475     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
   2476   else
   2477     return NULL;
   2478 }
   2479 
   2480 /**
   2481  * Sets the "authentication context" which scopes cookies
   2482  * with the DBUS_COOKIE_SHA1 auth mechanism for example.
   2483  *
   2484  * @param auth the auth conversation
   2485  * @param context the context
   2486  * @returns #FALSE if no memory
   2487  */
   2488 dbus_bool_t
   2489 _dbus_auth_set_context (DBusAuth               *auth,
   2490                         const DBusString       *context)
   2491 {
   2492   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
   2493                                    &auth->context, 0, _dbus_string_get_length (context));
   2494 }
   2495 
   2496 /** @} */
   2497 
   2498 /* tests in dbus-auth-util.c */
   2499