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