2007-06-09 Havoc Pennington <hp@redhat.com>
[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   if (!send_ok (auth))
736     goto out_3;
737
738   _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n",
739                  DBUS_AUTH_NAME (auth));
740   
741   retval = TRUE;
742   
743  out_3:
744   _dbus_string_zero (&correct_hash);
745   _dbus_string_free (&correct_hash);
746  out_2:
747   _dbus_string_zero (&client_hash);
748   _dbus_string_free (&client_hash);
749  out_1:
750   _dbus_string_free (&client_challenge);
751  out_0:
752   return retval;
753 }
754
755 static dbus_bool_t
756 handle_server_data_cookie_sha1_mech (DBusAuth         *auth,
757                                      const DBusString *data)
758 {
759   if (auth->cookie_id < 0)
760     return sha1_handle_first_client_response (auth, data);
761   else
762     return sha1_handle_second_client_response (auth, data);
763 }
764
765 static void
766 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
767 {
768   auth->cookie_id = -1;  
769   _dbus_string_set_length (&auth->challenge, 0);
770 }
771
772 static dbus_bool_t
773 handle_client_initial_response_cookie_sha1_mech (DBusAuth   *auth,
774                                                  DBusString *response)
775 {
776   const DBusString *username;
777   dbus_bool_t retval;
778
779   retval = FALSE;
780
781   if (!_dbus_username_from_current_process (&username))
782     goto out_0;
783
784   if (!_dbus_string_hex_encode (username, 0,
785                                 response,
786                                 _dbus_string_get_length (response)))
787     goto out_0;
788
789   retval = TRUE;
790   
791  out_0:
792   return retval;
793 }
794
795 static dbus_bool_t
796 handle_client_data_cookie_sha1_mech (DBusAuth         *auth,
797                                      const DBusString *data)
798 {
799   /* The data we get from the server should be the cookie context
800    * name, the cookie ID, and the server challenge, separated by
801    * spaces. We send back our challenge string and the correct hash.
802    */
803   dbus_bool_t retval;
804   DBusString context;
805   DBusString cookie_id_str;
806   DBusString server_challenge;
807   DBusString client_challenge;
808   DBusString correct_hash;
809   DBusString tmp;
810   int i, j;
811   long val;
812   
813   retval = FALSE;                 
814   
815   if (!_dbus_string_find_blank (data, 0, &i))
816     {
817       if (send_error (auth,
818                       "Server did not send context/ID/challenge properly"))
819         retval = TRUE;
820       goto out_0;
821     }
822
823   if (!_dbus_string_init (&context))
824     goto out_0;
825
826   if (!_dbus_string_copy_len (data, 0, i,
827                               &context, 0))
828     goto out_1;
829   
830   _dbus_string_skip_blank (data, i, &i);
831   if (!_dbus_string_find_blank (data, i, &j))
832     {
833       if (send_error (auth,
834                       "Server did not send context/ID/challenge properly"))
835         retval = TRUE;
836       goto out_1;
837     }
838
839   if (!_dbus_string_init (&cookie_id_str))
840     goto out_1;
841   
842   if (!_dbus_string_copy_len (data, i, j - i,
843                               &cookie_id_str, 0))
844     goto out_2;  
845
846   if (!_dbus_string_init (&server_challenge))
847     goto out_2;
848
849   i = j;
850   _dbus_string_skip_blank (data, i, &i);
851   j = _dbus_string_get_length (data);
852
853   if (!_dbus_string_copy_len (data, i, j - i,
854                               &server_challenge, 0))
855     goto out_3;
856
857   if (!_dbus_keyring_validate_context (&context))
858     {
859       if (send_error (auth, "Server sent invalid cookie context"))
860         retval = TRUE;
861       goto out_3;
862     }
863
864   if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
865     {
866       if (send_error (auth, "Could not parse cookie ID as an integer"))
867         retval = TRUE;
868       goto out_3;
869     }
870
871   if (_dbus_string_get_length (&server_challenge) == 0)
872     {
873       if (send_error (auth, "Empty server challenge string"))
874         retval = TRUE;
875       goto out_3;
876     }
877
878   if (auth->keyring == NULL)
879     {
880       DBusError error;
881
882       dbus_error_init (&error);
883       auth->keyring = _dbus_keyring_new_homedir (NULL,
884                                                  &context,
885                                                  &error);
886
887       if (auth->keyring == NULL)
888         {
889           if (dbus_error_has_name (&error,
890                                    DBUS_ERROR_NO_MEMORY))
891             {
892               dbus_error_free (&error);
893               goto out_3;
894             }
895           else
896             {
897               _DBUS_ASSERT_ERROR_IS_SET (&error);
898
899               _dbus_verbose ("%s: Error loading keyring: %s\n",
900                              DBUS_AUTH_NAME (auth), error.message);
901               
902               if (send_error (auth, "Could not load cookie file"))
903                 retval = TRUE; /* retval is only about mem */
904               
905               dbus_error_free (&error);
906               goto out_3;
907             }
908         }
909       else
910         {
911           _dbus_assert (!dbus_error_is_set (&error));
912         }
913     }
914   
915   _dbus_assert (auth->keyring != NULL);
916   
917   if (!_dbus_string_init (&tmp))
918     goto out_3;
919   
920   if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
921     goto out_4;
922
923   if (!_dbus_string_init (&client_challenge))
924     goto out_4;
925
926   if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
927     goto out_5;
928
929   if (!_dbus_string_init (&correct_hash))
930     goto out_5;
931   
932   if (!sha1_compute_hash (auth, val,
933                           &server_challenge,
934                           &client_challenge,
935                           &correct_hash))
936     goto out_6;
937
938   if (_dbus_string_get_length (&correct_hash) == 0)
939     {
940       /* couldn't find the cookie ID or something */
941       if (send_error (auth, "Don't have the requested cookie ID"))
942         retval = TRUE;
943       goto out_6;
944     }
945   
946   _dbus_string_set_length (&tmp, 0);
947   
948   if (!_dbus_string_copy (&client_challenge, 0, &tmp,
949                           _dbus_string_get_length (&tmp)))
950     goto out_6;
951
952   if (!_dbus_string_append (&tmp, " "))
953     goto out_6;
954
955   if (!_dbus_string_copy (&correct_hash, 0, &tmp,
956                           _dbus_string_get_length (&tmp)))
957     goto out_6;
958
959   if (!send_data (auth, &tmp))
960     goto out_6;
961
962   retval = TRUE;
963
964  out_6:
965   _dbus_string_zero (&correct_hash);
966   _dbus_string_free (&correct_hash);
967  out_5:
968   _dbus_string_free (&client_challenge);
969  out_4:
970   _dbus_string_zero (&tmp);
971   _dbus_string_free (&tmp);
972  out_3:
973   _dbus_string_free (&server_challenge);
974  out_2:
975   _dbus_string_free (&cookie_id_str);
976  out_1:
977   _dbus_string_free (&context);
978  out_0:
979   return retval;
980 }
981
982 static void
983 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
984 {
985   auth->cookie_id = -1;  
986   _dbus_string_set_length (&auth->challenge, 0);
987 }
988
989 /*
990  * EXTERNAL mechanism
991  */
992
993 static dbus_bool_t
994 handle_server_data_external_mech (DBusAuth         *auth,
995                                   const DBusString *data)
996 {
997   if (_dbus_credentials_are_empty (auth->credentials))
998     {
999       _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
1000                      DBUS_AUTH_NAME (auth));
1001       return send_rejected (auth);
1002     }
1003   
1004   if (_dbus_string_get_length (data) > 0)
1005     {
1006       if (_dbus_string_get_length (&auth->identity) > 0)
1007         {
1008           /* Tried to send two auth identities, wtf */
1009           _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
1010                          DBUS_AUTH_NAME (auth));
1011           return send_rejected (auth);
1012         }
1013       else
1014         {
1015           /* this is our auth identity */
1016           if (!_dbus_string_copy (data, 0, &auth->identity, 0))
1017             return FALSE;
1018         }
1019     }
1020
1021   /* Poke client for an auth identity, if none given */
1022   if (_dbus_string_get_length (&auth->identity) == 0 &&
1023       !auth->already_asked_for_initial_response)
1024     {
1025       if (send_data (auth, NULL))
1026         {
1027           _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
1028                          DBUS_AUTH_NAME (auth));
1029           auth->already_asked_for_initial_response = TRUE;
1030           return TRUE;
1031         }
1032       else
1033         return FALSE;
1034     }
1035
1036   _dbus_credentials_clear (auth->desired_identity);
1037   
1038   /* If auth->identity is still empty here, then client
1039    * responded with an empty string after we poked it for
1040    * an initial response. This means to try to auth the
1041    * identity provided in the credentials.
1042    */
1043   if (_dbus_string_get_length (&auth->identity) == 0)
1044     {
1045       if (!_dbus_credentials_add_credentials (auth->desired_identity,
1046                                               auth->credentials))
1047         {
1048           return FALSE; /* OOM */
1049         }
1050     }
1051   else
1052     {
1053       if (!_dbus_credentials_parse_and_add_desired(auth->desired_identity,
1054                                                    &auth->identity))
1055         {
1056           _dbus_verbose ("%s: could not get credentials from uid string\n",
1057                          DBUS_AUTH_NAME (auth));
1058           return send_rejected (auth);
1059         }
1060     }
1061
1062   if (_dbus_credentials_are_empty (auth->desired_identity))
1063     {
1064       _dbus_verbose ("%s: desired user %s is no good\n",
1065                      DBUS_AUTH_NAME (auth),
1066                      _dbus_string_get_const_data (&auth->identity));
1067       return send_rejected (auth);
1068     }
1069   
1070   if (_dbus_credentials_are_superset (auth->credentials,
1071                                       auth->desired_identity))
1072     {
1073       /* client has authenticated */
1074       if (!_dbus_credentials_add_credentials (auth->authorized_identity,
1075                                               auth->desired_identity))
1076         return FALSE;
1077
1078       /* also copy process ID from the socket credentials - FIXME this
1079        * should be done even if auth EXTERNAL not used
1080        */
1081       if (!_dbus_credentials_add_credential (auth->authorized_identity,
1082                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
1083                                              auth->credentials))
1084         return FALSE;
1085       
1086       if (!send_ok (auth))
1087         return FALSE;
1088
1089       _dbus_verbose ("%s: authenticated client based on socket credentials\n",
1090                      DBUS_AUTH_NAME (auth));
1091
1092       return TRUE;
1093     }
1094   else
1095     {
1096       _dbus_verbose ("%s: desired identity not found in socket credentials\n",
1097                      DBUS_AUTH_NAME (auth));
1098       return send_rejected (auth);
1099     }
1100 }
1101
1102 static void
1103 handle_server_shutdown_external_mech (DBusAuth *auth)
1104 {
1105
1106 }
1107
1108 static dbus_bool_t
1109 handle_client_initial_response_external_mech (DBusAuth         *auth,
1110                                               DBusString       *response)
1111 {
1112   /* We always append our UID as an initial response, so the server
1113    * doesn't have to send back an empty challenge to check whether we
1114    * want to specify an identity. i.e. this avoids a round trip that
1115    * the spec for the EXTERNAL mechanism otherwise requires.
1116    */
1117   DBusString plaintext;
1118
1119   if (!_dbus_string_init (&plaintext))
1120     return FALSE;
1121
1122   if (!_dbus_append_desired_identity (&plaintext))
1123     goto failed;
1124
1125   if (!_dbus_string_hex_encode (&plaintext, 0,
1126                                 response,
1127                                 _dbus_string_get_length (response)))
1128     goto failed;
1129
1130   _dbus_string_free (&plaintext);
1131   
1132   return TRUE;
1133
1134  failed:
1135   _dbus_string_free (&plaintext);
1136   return FALSE;  
1137 }
1138
1139 static dbus_bool_t
1140 handle_client_data_external_mech (DBusAuth         *auth,
1141                                   const DBusString *data)
1142 {
1143   
1144   return TRUE;
1145 }
1146
1147 static void
1148 handle_client_shutdown_external_mech (DBusAuth *auth)
1149 {
1150
1151 }
1152
1153 /*
1154  * ANONYMOUS mechanism
1155  */
1156
1157 static dbus_bool_t
1158 handle_server_data_anonymous_mech (DBusAuth         *auth,
1159                                    const DBusString *data)
1160 {  
1161   if (_dbus_string_get_length (data) > 0)
1162     {
1163       /* Client is allowed to send "trace" data, the only defined
1164        * meaning is that if it contains '@' it is an email address,
1165        * and otherwise it is anything else, and it's supposed to be
1166        * UTF-8
1167        */
1168       if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
1169         {
1170           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
1171                          DBUS_AUTH_NAME (auth));
1172
1173           {
1174             DBusString plaintext;
1175             DBusString encoded;
1176             _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
1177             _dbus_string_init (&encoded);
1178             _dbus_string_hex_encode (&plaintext, 0,
1179                                      &encoded,
1180                                      0);
1181               _dbus_verbose ("%s: try '%s'\n",
1182                              DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
1183           }
1184           return send_rejected (auth);
1185         }
1186       
1187       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
1188                      DBUS_AUTH_NAME (auth),
1189                      _dbus_string_get_const_data (data));
1190     }
1191
1192   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
1193   _dbus_credentials_clear (auth->desired_identity);
1194
1195   /* Anonymous is always allowed */
1196   if (!send_ok (auth))
1197     return FALSE;
1198
1199   _dbus_verbose ("%s: authenticated client as anonymous\n",
1200                  DBUS_AUTH_NAME (auth));
1201
1202   return TRUE;
1203 }
1204
1205 static void
1206 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
1207 {
1208   
1209 }
1210
1211 static dbus_bool_t
1212 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
1213                                                DBusString       *response)
1214 {
1215   /* Our initial response is a "trace" string which must be valid UTF-8
1216    * and must be an email address if it contains '@'.
1217    * We just send the dbus implementation info, like a user-agent or
1218    * something, because... why not. There's nothing guaranteed here
1219    * though, we could change it later.
1220    */
1221   DBusString plaintext;
1222
1223   if (!_dbus_string_init (&plaintext))
1224     return FALSE;
1225
1226   if (!_dbus_string_append (&plaintext,
1227                             "libdbus " VERSION))
1228     goto failed;
1229
1230   if (!_dbus_string_hex_encode (&plaintext, 0,
1231                                 response,
1232                                 _dbus_string_get_length (response)))
1233     goto failed;
1234
1235   _dbus_string_free (&plaintext);
1236   
1237   return TRUE;
1238
1239  failed:
1240   _dbus_string_free (&plaintext);
1241   return FALSE;  
1242 }
1243
1244 static dbus_bool_t
1245 handle_client_data_anonymous_mech (DBusAuth         *auth,
1246                                   const DBusString *data)
1247 {
1248   
1249   return TRUE;
1250 }
1251
1252 static void
1253 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
1254 {
1255   
1256 }
1257
1258 /* Put mechanisms here in order of preference.
1259  * Right now we have:
1260  *
1261  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
1262  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
1263  * - ANONYMOUS checks nothing but doesn't auth the person as a user
1264  *
1265  * We might ideally add a mechanism to chain to Cyrus SASL so we can
1266  * use its mechanisms as well.
1267  * 
1268  */
1269 static const DBusAuthMechanismHandler
1270 all_mechanisms[] = {
1271   { "EXTERNAL",
1272     handle_server_data_external_mech,
1273     NULL, NULL,
1274     handle_server_shutdown_external_mech,
1275     handle_client_initial_response_external_mech,
1276     handle_client_data_external_mech,
1277     NULL, NULL,
1278     handle_client_shutdown_external_mech },
1279   { "DBUS_COOKIE_SHA1",
1280     handle_server_data_cookie_sha1_mech,
1281     NULL, NULL,
1282     handle_server_shutdown_cookie_sha1_mech,
1283     handle_client_initial_response_cookie_sha1_mech,
1284     handle_client_data_cookie_sha1_mech,
1285     NULL, NULL,
1286     handle_client_shutdown_cookie_sha1_mech },
1287   { "ANONYMOUS",
1288     handle_server_data_anonymous_mech,
1289     NULL, NULL,
1290     handle_server_shutdown_anonymous_mech,
1291     handle_client_initial_response_anonymous_mech,
1292     handle_client_data_anonymous_mech,
1293     NULL, NULL,
1294     handle_client_shutdown_anonymous_mech },  
1295   { NULL, NULL }
1296 };
1297
1298 static const DBusAuthMechanismHandler*
1299 find_mech (const DBusString  *name,
1300            char             **allowed_mechs)
1301 {
1302   int i;
1303   
1304   if (allowed_mechs != NULL &&
1305       !_dbus_string_array_contains ((const char**) allowed_mechs,
1306                                     _dbus_string_get_const_data (name)))
1307     return NULL;
1308   
1309   i = 0;
1310   while (all_mechanisms[i].mechanism != NULL)
1311     {      
1312       if (_dbus_string_equal_c_str (name,
1313                                     all_mechanisms[i].mechanism))
1314
1315         return &all_mechanisms[i];
1316       
1317       ++i;
1318     }
1319   
1320   return NULL;
1321 }
1322
1323 static dbus_bool_t
1324 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
1325 {
1326   DBusString auth_command;
1327
1328   if (!_dbus_string_init (&auth_command))
1329     return FALSE;
1330       
1331   if (!_dbus_string_append (&auth_command,
1332                             "AUTH "))
1333     {
1334       _dbus_string_free (&auth_command);
1335       return FALSE;
1336     }  
1337   
1338   if (!_dbus_string_append (&auth_command,
1339                             mech->mechanism))
1340     {
1341       _dbus_string_free (&auth_command);
1342       return FALSE;
1343     }
1344
1345   if (mech->client_initial_response_func != NULL)
1346     {
1347       if (!_dbus_string_append (&auth_command, " "))
1348         {
1349           _dbus_string_free (&auth_command);
1350           return FALSE;
1351         }
1352       
1353       if (!(* mech->client_initial_response_func) (auth, &auth_command))
1354         {
1355           _dbus_string_free (&auth_command);
1356           return FALSE;
1357         }
1358     }
1359   
1360   if (!_dbus_string_append (&auth_command,
1361                             "\r\n"))
1362     {
1363       _dbus_string_free (&auth_command);
1364       return FALSE;
1365     }
1366
1367   if (!_dbus_string_copy (&auth_command, 0,
1368                           &auth->outgoing,
1369                           _dbus_string_get_length (&auth->outgoing)))
1370     {
1371       _dbus_string_free (&auth_command);
1372       return FALSE;
1373     }
1374
1375   _dbus_string_free (&auth_command);
1376   shutdown_mech (auth);
1377   auth->mech = mech;      
1378   goto_state (auth, &client_state_waiting_for_data);
1379
1380   return TRUE;
1381 }
1382
1383 static dbus_bool_t
1384 send_data (DBusAuth *auth, DBusString *data)
1385 {
1386   int old_len;
1387
1388   if (data == NULL || _dbus_string_get_length (data) == 0)
1389     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
1390   else
1391     {
1392       old_len = _dbus_string_get_length (&auth->outgoing);
1393       if (!_dbus_string_append (&auth->outgoing, "DATA "))
1394         goto out;
1395
1396       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
1397                                     _dbus_string_get_length (&auth->outgoing)))
1398         goto out;
1399
1400       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
1401         goto out;
1402
1403       return TRUE;
1404
1405     out:
1406       _dbus_string_set_length (&auth->outgoing, old_len);
1407
1408       return FALSE;
1409     }
1410 }
1411
1412 static dbus_bool_t
1413 send_rejected (DBusAuth *auth)
1414 {
1415   DBusString command;
1416   DBusAuthServer *server_auth;
1417   int i;
1418   
1419   if (!_dbus_string_init (&command))
1420     return FALSE;
1421   
1422   if (!_dbus_string_append (&command,
1423                             "REJECTED"))
1424     goto nomem;
1425
1426   i = 0;
1427   while (all_mechanisms[i].mechanism != NULL)
1428     {
1429       if (!_dbus_string_append (&command,
1430                                 " "))
1431         goto nomem;
1432
1433       if (!_dbus_string_append (&command,
1434                                 all_mechanisms[i].mechanism))
1435         goto nomem;
1436       
1437       ++i;
1438     }
1439   
1440   if (!_dbus_string_append (&command, "\r\n"))
1441     goto nomem;
1442
1443   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
1444                           _dbus_string_get_length (&auth->outgoing)))
1445     goto nomem;
1446
1447   shutdown_mech (auth);
1448   
1449   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
1450   server_auth = DBUS_AUTH_SERVER (auth);
1451   server_auth->failures += 1;
1452
1453   if (server_auth->failures >= server_auth->max_failures)
1454     goto_state (auth, &common_state_need_disconnect);
1455   else
1456     goto_state (auth, &server_state_waiting_for_auth);
1457
1458   _dbus_string_free (&command);
1459   
1460   return TRUE;
1461
1462  nomem:
1463   _dbus_string_free (&command);
1464   return FALSE;
1465 }
1466
1467 static dbus_bool_t
1468 send_error (DBusAuth *auth, const char *message)
1469 {
1470   return _dbus_string_append_printf (&auth->outgoing,
1471                                      "ERROR \"%s\"\r\n", message);
1472 }
1473
1474 static dbus_bool_t
1475 send_ok (DBusAuth *auth)
1476 {
1477   int orig_len;
1478
1479   orig_len = _dbus_string_get_length (&auth->outgoing);
1480   
1481   if (_dbus_string_append (&auth->outgoing, "OK ") &&
1482       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
1483                          0,
1484                          &auth->outgoing,
1485                          _dbus_string_get_length (&auth->outgoing)) &&
1486       _dbus_string_append (&auth->outgoing, "\r\n"))
1487     {
1488       goto_state (auth, &server_state_waiting_for_begin);
1489       return TRUE;
1490     }
1491   else
1492     {
1493       _dbus_string_set_length (&auth->outgoing, orig_len);
1494       return FALSE;
1495     }
1496 }
1497
1498 static dbus_bool_t
1499 send_begin (DBusAuth         *auth,
1500             const DBusString *args_from_ok)
1501 {
1502   int end_of_hex;
1503   
1504   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
1505   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
1506
1507   /* We decode the hex string to binary, using guid_from_server as scratch... */
1508   
1509   end_of_hex = 0;
1510   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
1511                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
1512     return FALSE;
1513
1514   /* now clear out the scratch */
1515   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1516   
1517   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
1518       end_of_hex == 0)
1519     {
1520       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
1521                      end_of_hex, _dbus_string_get_length (args_from_ok));
1522       goto_state (auth, &common_state_need_disconnect);
1523       return TRUE;
1524     }
1525
1526   if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
1527       _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
1528     {
1529       _dbus_verbose ("Got GUID '%s' from the server\n",
1530                      _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
1531       
1532       goto_state (auth, &common_state_authenticated);
1533       return TRUE;
1534     }
1535   else
1536     {
1537       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1538       return FALSE;
1539     }
1540 }
1541
1542 static dbus_bool_t
1543 send_cancel (DBusAuth *auth)
1544 {
1545   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
1546     {
1547       goto_state (auth, &client_state_waiting_for_reject);
1548       return TRUE;
1549     }
1550   else
1551     return FALSE;
1552 }
1553
1554 static dbus_bool_t
1555 process_data (DBusAuth             *auth,
1556               const DBusString     *args,
1557               DBusAuthDataFunction  data_func)
1558 {
1559   int end;
1560   DBusString decoded;
1561
1562   if (!_dbus_string_init (&decoded))
1563     return FALSE;
1564
1565   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
1566     {
1567       _dbus_string_free (&decoded);
1568       return FALSE;
1569     }
1570
1571   if (_dbus_string_get_length (args) != end)
1572     {
1573       _dbus_string_free (&decoded);
1574       if (!send_error (auth, "Invalid hex encoding"))
1575         return FALSE;
1576
1577       return TRUE;
1578     }
1579
1580 #ifdef DBUS_ENABLE_VERBOSE_MODE
1581   if (_dbus_string_validate_ascii (&decoded, 0,
1582                                    _dbus_string_get_length (&decoded)))
1583     _dbus_verbose ("%s: data: '%s'\n",
1584                    DBUS_AUTH_NAME (auth),
1585                    _dbus_string_get_const_data (&decoded));
1586 #endif
1587       
1588   if (!(* data_func) (auth, &decoded))
1589     {
1590       _dbus_string_free (&decoded);
1591       return FALSE;
1592     }
1593
1594   _dbus_string_free (&decoded);
1595   return TRUE;
1596 }
1597
1598 static dbus_bool_t
1599 handle_auth (DBusAuth *auth, const DBusString *args)
1600 {
1601   if (_dbus_string_get_length (args) == 0)
1602     {
1603       /* No args to the auth, send mechanisms */
1604       if (!send_rejected (auth))
1605         return FALSE;
1606
1607       return TRUE;
1608     }
1609   else
1610     {
1611       int i;
1612       DBusString mech;
1613       DBusString hex_response;
1614       
1615       _dbus_string_find_blank (args, 0, &i);
1616
1617       if (!_dbus_string_init (&mech))
1618         return FALSE;
1619
1620       if (!_dbus_string_init (&hex_response))
1621         {
1622           _dbus_string_free (&mech);
1623           return FALSE;
1624         }
1625       
1626       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
1627         goto failed;
1628
1629       _dbus_string_skip_blank (args, i, &i);
1630       if (!_dbus_string_copy (args, i, &hex_response, 0))
1631         goto failed;
1632      
1633       auth->mech = find_mech (&mech, auth->allowed_mechs);
1634       if (auth->mech != NULL)
1635         {
1636           _dbus_verbose ("%s: Trying mechanism %s\n",
1637                          DBUS_AUTH_NAME (auth),
1638                          auth->mech->mechanism);
1639           
1640           if (!process_data (auth, &hex_response,
1641                              auth->mech->server_data_func))
1642             goto failed;
1643         }
1644       else
1645         {
1646           /* Unsupported mechanism */
1647           _dbus_verbose ("%s: Unsupported mechanism %s\n",
1648                          DBUS_AUTH_NAME (auth),
1649                          _dbus_string_get_const_data (&mech));
1650           
1651           if (!send_rejected (auth))
1652             goto failed;
1653         }
1654
1655       _dbus_string_free (&mech);      
1656       _dbus_string_free (&hex_response);
1657
1658       return TRUE;
1659       
1660     failed:
1661       auth->mech = NULL;
1662       _dbus_string_free (&mech);
1663       _dbus_string_free (&hex_response);
1664       return FALSE;
1665     }
1666 }
1667
1668 static dbus_bool_t
1669 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
1670                                        DBusAuthCommand   command,
1671                                        const DBusString *args)
1672 {
1673   switch (command)
1674     {
1675     case DBUS_AUTH_COMMAND_AUTH:
1676       return handle_auth (auth, args);
1677
1678     case DBUS_AUTH_COMMAND_CANCEL:
1679     case DBUS_AUTH_COMMAND_DATA:
1680       return send_error (auth, "Not currently in an auth conversation");
1681
1682     case DBUS_AUTH_COMMAND_BEGIN:
1683       goto_state (auth, &common_state_need_disconnect);
1684       return TRUE;
1685
1686     case DBUS_AUTH_COMMAND_ERROR:
1687       return send_rejected (auth);
1688
1689     case DBUS_AUTH_COMMAND_REJECTED:
1690     case DBUS_AUTH_COMMAND_OK:
1691     case DBUS_AUTH_COMMAND_UNKNOWN:
1692     default:
1693       return send_error (auth, "Unknown command");
1694     }
1695 }
1696
1697 static dbus_bool_t
1698 handle_server_state_waiting_for_data  (DBusAuth         *auth,
1699                                        DBusAuthCommand   command,
1700                                        const DBusString *args)
1701 {
1702   switch (command)
1703     {
1704     case DBUS_AUTH_COMMAND_AUTH:
1705       return send_error (auth, "Sent AUTH while another AUTH in progress");
1706
1707     case DBUS_AUTH_COMMAND_CANCEL:
1708     case DBUS_AUTH_COMMAND_ERROR:
1709       return send_rejected (auth);
1710
1711     case DBUS_AUTH_COMMAND_DATA:
1712       return process_data (auth, args, auth->mech->server_data_func);
1713
1714     case DBUS_AUTH_COMMAND_BEGIN:
1715       goto_state (auth, &common_state_need_disconnect);
1716       return TRUE;
1717
1718     case DBUS_AUTH_COMMAND_REJECTED:
1719     case DBUS_AUTH_COMMAND_OK:
1720     case DBUS_AUTH_COMMAND_UNKNOWN:
1721     default:
1722       return send_error (auth, "Unknown command");
1723     }
1724 }
1725
1726 static dbus_bool_t
1727 handle_server_state_waiting_for_begin (DBusAuth         *auth,
1728                                        DBusAuthCommand   command,
1729                                        const DBusString *args)
1730 {
1731   switch (command)
1732     {
1733     case DBUS_AUTH_COMMAND_AUTH:
1734       return send_error (auth, "Sent AUTH while expecting BEGIN");
1735
1736     case DBUS_AUTH_COMMAND_DATA:
1737       return send_error (auth, "Sent DATA while expecting BEGIN");
1738
1739     case DBUS_AUTH_COMMAND_BEGIN:
1740       goto_state (auth, &common_state_authenticated);
1741       return TRUE;
1742
1743     case DBUS_AUTH_COMMAND_REJECTED:
1744     case DBUS_AUTH_COMMAND_OK:
1745     case DBUS_AUTH_COMMAND_UNKNOWN:
1746     default:
1747       return send_error (auth, "Unknown command");
1748
1749     case DBUS_AUTH_COMMAND_CANCEL:
1750     case DBUS_AUTH_COMMAND_ERROR:
1751       return send_rejected (auth);
1752     }
1753 }
1754
1755 /* return FALSE if no memory, TRUE if all OK */
1756 static dbus_bool_t
1757 get_word (const DBusString *str,
1758           int              *start,
1759           DBusString       *word)
1760 {
1761   int i;
1762
1763   _dbus_string_skip_blank (str, *start, start);
1764   _dbus_string_find_blank (str, *start, &i);
1765   
1766   if (i > *start)
1767     {
1768       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
1769         return FALSE;
1770       
1771       *start = i;
1772     }
1773
1774   return TRUE;
1775 }
1776
1777 static dbus_bool_t
1778 record_mechanisms (DBusAuth         *auth,
1779                    const DBusString *args)
1780 {
1781   int next;
1782   int len;
1783
1784   if (auth->already_got_mechanisms)
1785     return TRUE;
1786   
1787   len = _dbus_string_get_length (args);
1788   
1789   next = 0;
1790   while (next < len)
1791     {
1792       DBusString m;
1793       const DBusAuthMechanismHandler *mech;
1794       
1795       if (!_dbus_string_init (&m))
1796         goto nomem;
1797       
1798       if (!get_word (args, &next, &m))
1799         {
1800           _dbus_string_free (&m);
1801           goto nomem;
1802         }
1803
1804       mech = find_mech (&m, auth->allowed_mechs);
1805
1806       if (mech != NULL)
1807         {
1808           /* FIXME right now we try mechanisms in the order
1809            * the server lists them; should we do them in
1810            * some more deterministic order?
1811            *
1812            * Probably in all_mechanisms order, our order of
1813            * preference. Of course when the server is us,
1814            * it lists things in that order anyhow.
1815            */
1816
1817           if (mech != &all_mechanisms[0])
1818             {
1819               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
1820                              DBUS_AUTH_NAME (auth), mech->mechanism);
1821           
1822               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
1823                                       (void*) mech))
1824                 {
1825                   _dbus_string_free (&m);
1826                   goto nomem;
1827                 }
1828             }
1829           else
1830             {
1831               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
1832                              DBUS_AUTH_NAME (auth), mech->mechanism);
1833             }
1834         }
1835       else
1836         {
1837           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
1838                          DBUS_AUTH_NAME (auth),
1839                          _dbus_string_get_const_data (&m));
1840         }
1841
1842       _dbus_string_free (&m);
1843     }
1844   
1845   auth->already_got_mechanisms = TRUE;
1846   
1847   return TRUE;
1848
1849  nomem:
1850   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1851   
1852   return FALSE;
1853 }
1854
1855 static dbus_bool_t
1856 process_rejected (DBusAuth *auth, const DBusString *args)
1857 {
1858   const DBusAuthMechanismHandler *mech;
1859   DBusAuthClient *client;
1860
1861   client = DBUS_AUTH_CLIENT (auth);
1862
1863   if (!auth->already_got_mechanisms)
1864     {
1865       if (!record_mechanisms (auth, args))
1866         return FALSE;
1867     }
1868   
1869   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
1870     {
1871       mech = client->mechs_to_try->data;
1872
1873       if (!send_auth (auth, mech))
1874         return FALSE;
1875
1876       _dbus_list_pop_first (&client->mechs_to_try);
1877
1878       _dbus_verbose ("%s: Trying mechanism %s\n",
1879                      DBUS_AUTH_NAME (auth),
1880                      mech->mechanism);
1881     }
1882   else
1883     {
1884       /* Give up */
1885       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
1886                      DBUS_AUTH_NAME (auth));
1887       goto_state (auth, &common_state_need_disconnect);
1888     }
1889   
1890   return TRUE;
1891 }
1892
1893
1894 static dbus_bool_t
1895 handle_client_state_waiting_for_data (DBusAuth         *auth,
1896                                       DBusAuthCommand   command,
1897                                       const DBusString *args)
1898 {
1899   _dbus_assert (auth->mech != NULL);
1900  
1901   switch (command)
1902     {
1903     case DBUS_AUTH_COMMAND_DATA:
1904       return process_data (auth, args, auth->mech->client_data_func);
1905
1906     case DBUS_AUTH_COMMAND_REJECTED:
1907       return process_rejected (auth, args);
1908
1909     case DBUS_AUTH_COMMAND_OK:
1910       return send_begin (auth, args);
1911
1912     case DBUS_AUTH_COMMAND_ERROR:
1913       return send_cancel (auth);
1914
1915     case DBUS_AUTH_COMMAND_AUTH:
1916     case DBUS_AUTH_COMMAND_CANCEL:
1917     case DBUS_AUTH_COMMAND_BEGIN:
1918     case DBUS_AUTH_COMMAND_UNKNOWN:
1919     default:
1920       return send_error (auth, "Unknown command");
1921     }
1922 }
1923
1924 static dbus_bool_t
1925 handle_client_state_waiting_for_ok (DBusAuth         *auth,
1926                                     DBusAuthCommand   command,
1927                                     const DBusString *args)
1928 {
1929   switch (command)
1930     {
1931     case DBUS_AUTH_COMMAND_REJECTED:
1932       return process_rejected (auth, args);
1933
1934     case DBUS_AUTH_COMMAND_OK:
1935       return send_begin (auth, args);
1936
1937     case DBUS_AUTH_COMMAND_DATA:
1938     case DBUS_AUTH_COMMAND_ERROR:
1939       return send_cancel (auth);
1940
1941     case DBUS_AUTH_COMMAND_AUTH:
1942     case DBUS_AUTH_COMMAND_CANCEL:
1943     case DBUS_AUTH_COMMAND_BEGIN:
1944     case DBUS_AUTH_COMMAND_UNKNOWN:
1945     default:
1946       return send_error (auth, "Unknown command");
1947     }
1948 }
1949
1950 static dbus_bool_t
1951 handle_client_state_waiting_for_reject (DBusAuth         *auth,
1952                                         DBusAuthCommand   command,
1953                                         const DBusString *args)
1954 {
1955   switch (command)
1956     {
1957     case DBUS_AUTH_COMMAND_REJECTED:
1958       return process_rejected (auth, args);
1959       
1960     case DBUS_AUTH_COMMAND_AUTH:
1961     case DBUS_AUTH_COMMAND_CANCEL:
1962     case DBUS_AUTH_COMMAND_DATA:
1963     case DBUS_AUTH_COMMAND_BEGIN:
1964     case DBUS_AUTH_COMMAND_OK:
1965     case DBUS_AUTH_COMMAND_ERROR:
1966     case DBUS_AUTH_COMMAND_UNKNOWN:
1967     default:
1968       goto_state (auth, &common_state_need_disconnect);
1969       return TRUE;
1970     }
1971 }
1972
1973 /**
1974  * Mapping from command name to enum
1975  */
1976 typedef struct {
1977   const char *name;        /**< Name of the command */
1978   DBusAuthCommand command; /**< Corresponding enum */
1979 } DBusAuthCommandName;
1980
1981 static const DBusAuthCommandName auth_command_names[] = {
1982   { "AUTH",     DBUS_AUTH_COMMAND_AUTH },
1983   { "CANCEL",   DBUS_AUTH_COMMAND_CANCEL },
1984   { "DATA",     DBUS_AUTH_COMMAND_DATA },
1985   { "BEGIN",    DBUS_AUTH_COMMAND_BEGIN },
1986   { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
1987   { "OK",       DBUS_AUTH_COMMAND_OK },
1988   { "ERROR",    DBUS_AUTH_COMMAND_ERROR }
1989 };
1990
1991 static DBusAuthCommand
1992 lookup_command_from_name (DBusString *command)
1993 {
1994   int i;
1995
1996   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
1997     {
1998       if (_dbus_string_equal_c_str (command,
1999                                     auth_command_names[i].name))
2000         return auth_command_names[i].command;
2001     }
2002
2003   return DBUS_AUTH_COMMAND_UNKNOWN;
2004 }
2005
2006 static void
2007 goto_state (DBusAuth *auth,
2008             const DBusAuthStateData *state)
2009 {
2010   _dbus_verbose ("%s: going from state %s to state %s\n",
2011                  DBUS_AUTH_NAME (auth),
2012                  auth->state->name,
2013                  state->name);
2014
2015   auth->state = state;
2016 }
2017
2018 /* returns whether to call it again right away */
2019 static dbus_bool_t
2020 process_command (DBusAuth *auth)
2021 {
2022   DBusAuthCommand command;
2023   DBusString line;
2024   DBusString args;
2025   int eol;
2026   int i, j;
2027   dbus_bool_t retval;
2028
2029   /* _dbus_verbose ("%s:   trying process_command()\n"); */
2030   
2031   retval = FALSE;
2032   
2033   eol = 0;
2034   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
2035     return FALSE;
2036   
2037   if (!_dbus_string_init (&line))
2038     {
2039       auth->needed_memory = TRUE;
2040       return FALSE;
2041     }
2042
2043   if (!_dbus_string_init (&args))
2044     {
2045       _dbus_string_free (&line);
2046       auth->needed_memory = TRUE;
2047       return FALSE;
2048     }
2049   
2050   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
2051     goto out;
2052
2053   if (!_dbus_string_validate_ascii (&line, 0,
2054                                     _dbus_string_get_length (&line)))
2055     {
2056       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
2057                      DBUS_AUTH_NAME (auth));
2058       if (!send_error (auth, "Command contained non-ASCII"))
2059         goto out;
2060       else
2061         goto next_command;
2062     }
2063   
2064   _dbus_verbose ("%s: got command \"%s\"\n",
2065                  DBUS_AUTH_NAME (auth),
2066                  _dbus_string_get_const_data (&line));
2067   
2068   _dbus_string_find_blank (&line, 0, &i);
2069   _dbus_string_skip_blank (&line, i, &j);
2070
2071   if (j > i)
2072     _dbus_string_delete (&line, i, j - i);
2073   
2074   if (!_dbus_string_move (&line, i, &args, 0))
2075     goto out;
2076
2077   /* FIXME 1.0 we should probably validate that only the allowed
2078    * chars are in the command name
2079    */
2080   
2081   command = lookup_command_from_name (&line);
2082   if (!(* auth->state->handler) (auth, command, &args))
2083     goto out;
2084
2085  next_command:
2086   
2087   /* We've succeeded in processing the whole command so drop it out
2088    * of the incoming buffer and return TRUE to try another command.
2089    */
2090
2091   _dbus_string_delete (&auth->incoming, 0, eol);
2092   
2093   /* kill the \r\n */
2094   _dbus_string_delete (&auth->incoming, 0, 2);
2095
2096   retval = TRUE;
2097   
2098  out:
2099   _dbus_string_free (&args);
2100   _dbus_string_free (&line);
2101
2102   if (!retval)
2103     auth->needed_memory = TRUE;
2104   else
2105     auth->needed_memory = FALSE;
2106   
2107   return retval;
2108 }
2109
2110
2111 /** @} */
2112
2113 /**
2114  * @addtogroup DBusAuth
2115  * @{
2116  */
2117
2118 /**
2119  * Creates a new auth conversation object for the server side.
2120  * See doc/dbus-sasl-profile.txt for full details on what
2121  * this object does.
2122  *
2123  * @returns the new object or #NULL if no memory
2124  */
2125 DBusAuth*
2126 _dbus_auth_server_new (const DBusString *guid)
2127 {
2128   DBusAuth *auth;
2129   DBusAuthServer *server_auth;
2130   DBusString guid_copy;
2131
2132   if (!_dbus_string_init (&guid_copy))
2133     return NULL;
2134
2135   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
2136     {
2137       _dbus_string_free (&guid_copy);
2138       return NULL;
2139     }
2140
2141   auth = _dbus_auth_new (sizeof (DBusAuthServer));
2142   if (auth == NULL)
2143     {
2144       _dbus_string_free (&guid_copy);
2145       return NULL;
2146     }
2147   
2148   auth->side = auth_side_server;
2149   auth->state = &server_state_waiting_for_auth;
2150
2151   server_auth = DBUS_AUTH_SERVER (auth);
2152
2153   server_auth->guid = guid_copy;
2154   
2155   /* perhaps this should be per-mechanism with a lower
2156    * max
2157    */
2158   server_auth->failures = 0;
2159   server_auth->max_failures = 6;
2160   
2161   return auth;
2162 }
2163
2164 /**
2165  * Creates a new auth conversation object for the client side.
2166  * See doc/dbus-sasl-profile.txt for full details on what
2167  * this object does.
2168  *
2169  * @returns the new object or #NULL if no memory
2170  */
2171 DBusAuth*
2172 _dbus_auth_client_new (void)
2173 {
2174   DBusAuth *auth;
2175   DBusString guid_str;
2176
2177   if (!_dbus_string_init (&guid_str))
2178     return NULL;
2179
2180   auth = _dbus_auth_new (sizeof (DBusAuthClient));
2181   if (auth == NULL)
2182     {
2183       _dbus_string_free (&guid_str);
2184       return NULL;
2185     }
2186
2187   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
2188
2189   auth->side = auth_side_client;
2190   auth->state = &client_state_need_send_auth;
2191
2192   /* Start the auth conversation by sending AUTH for our default
2193    * mechanism */
2194   if (!send_auth (auth, &all_mechanisms[0]))
2195     {
2196       _dbus_auth_unref (auth);
2197       return NULL;
2198     }
2199   
2200   return auth;
2201 }
2202
2203 /**
2204  * Increments the refcount of an auth object.
2205  *
2206  * @param auth the auth conversation
2207  * @returns the auth conversation
2208  */
2209 DBusAuth *
2210 _dbus_auth_ref (DBusAuth *auth)
2211 {
2212   _dbus_assert (auth != NULL);
2213   
2214   auth->refcount += 1;
2215   
2216   return auth;
2217 }
2218
2219 /**
2220  * Decrements the refcount of an auth object.
2221  *
2222  * @param auth the auth conversation
2223  */
2224 void
2225 _dbus_auth_unref (DBusAuth *auth)
2226 {
2227   _dbus_assert (auth != NULL);
2228   _dbus_assert (auth->refcount > 0);
2229
2230   auth->refcount -= 1;
2231   if (auth->refcount == 0)
2232     {
2233       shutdown_mech (auth);
2234
2235       if (DBUS_AUTH_IS_CLIENT (auth))
2236         {
2237           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2238           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
2239         }
2240       else
2241         {
2242           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
2243
2244           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
2245         }
2246
2247       if (auth->keyring)
2248         _dbus_keyring_unref (auth->keyring);
2249
2250       _dbus_string_free (&auth->context);
2251       _dbus_string_free (&auth->challenge);
2252       _dbus_string_free (&auth->identity);
2253       _dbus_string_free (&auth->incoming);
2254       _dbus_string_free (&auth->outgoing);
2255
2256       dbus_free_string_array (auth->allowed_mechs);
2257
2258       _dbus_credentials_unref (auth->credentials);
2259       _dbus_credentials_unref (auth->authorized_identity);
2260       _dbus_credentials_unref (auth->desired_identity);
2261       
2262       dbus_free (auth);
2263     }
2264 }
2265
2266 /**
2267  * Sets an array of authentication mechanism names
2268  * that we are willing to use.
2269  *
2270  * @param auth the auth conversation
2271  * @param mechanisms #NULL-terminated array of mechanism names
2272  * @returns #FALSE if no memory
2273  */
2274 dbus_bool_t
2275 _dbus_auth_set_mechanisms (DBusAuth    *auth,
2276                            const char **mechanisms)
2277 {
2278   char **copy;
2279
2280   if (mechanisms != NULL)
2281     {
2282       copy = _dbus_dup_string_array (mechanisms);
2283       if (copy == NULL)
2284         return FALSE;
2285     }
2286   else
2287     copy = NULL;
2288   
2289   dbus_free_string_array (auth->allowed_mechs);
2290
2291   auth->allowed_mechs = copy;
2292
2293   return TRUE;
2294 }
2295
2296 /**
2297  * @param auth the auth conversation object
2298  * @returns #TRUE if we're in a final state
2299  */
2300 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
2301
2302 /**
2303  * Analyzes buffered input and moves the auth conversation forward,
2304  * returning the new state of the auth conversation.
2305  *
2306  * @param auth the auth conversation
2307  * @returns the new state
2308  */
2309 DBusAuthState
2310 _dbus_auth_do_work (DBusAuth *auth)
2311 {
2312   auth->needed_memory = FALSE;
2313
2314   /* Max amount we'll buffer up before deciding someone's on crack */
2315 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
2316
2317   do
2318     {
2319       if (DBUS_AUTH_IN_END_STATE (auth))
2320         break;
2321       
2322       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
2323           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
2324         {
2325           goto_state (auth, &common_state_need_disconnect);
2326           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
2327                          DBUS_AUTH_NAME (auth));
2328           break;
2329         }
2330     }
2331   while (process_command (auth));
2332
2333   if (auth->needed_memory)
2334     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
2335   else if (_dbus_string_get_length (&auth->outgoing) > 0)
2336     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
2337   else if (auth->state == &common_state_need_disconnect)
2338     return DBUS_AUTH_STATE_NEED_DISCONNECT;
2339   else if (auth->state == &common_state_authenticated)
2340     return DBUS_AUTH_STATE_AUTHENTICATED;
2341   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
2342 }
2343
2344 /**
2345  * Gets bytes that need to be sent to the peer we're conversing with.
2346  * After writing some bytes, _dbus_auth_bytes_sent() must be called
2347  * to notify the auth object that they were written.
2348  *
2349  * @param auth the auth conversation
2350  * @param str return location for a ref to the buffer to send
2351  * @returns #FALSE if nothing to send
2352  */
2353 dbus_bool_t
2354 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
2355                               const DBusString **str)
2356 {
2357   _dbus_assert (auth != NULL);
2358   _dbus_assert (str != NULL);
2359
2360   *str = NULL;
2361   
2362   if (_dbus_string_get_length (&auth->outgoing) == 0)
2363     return FALSE;
2364
2365   *str = &auth->outgoing;
2366
2367   return TRUE;
2368 }
2369
2370 /**
2371  * Notifies the auth conversation object that
2372  * the given number of bytes of the outgoing buffer
2373  * have been written out.
2374  *
2375  * @param auth the auth conversation
2376  * @param bytes_sent number of bytes written out
2377  */
2378 void
2379 _dbus_auth_bytes_sent (DBusAuth *auth,
2380                        int       bytes_sent)
2381 {
2382   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
2383                  DBUS_AUTH_NAME (auth),
2384                  bytes_sent,
2385                  _dbus_string_get_const_data (&auth->outgoing));
2386   
2387   _dbus_string_delete (&auth->outgoing,
2388                        0, bytes_sent);
2389 }
2390
2391 /**
2392  * Get a buffer to be used for reading bytes from the peer we're conversing
2393  * with. Bytes should be appended to this buffer.
2394  *
2395  * @param auth the auth conversation
2396  * @param buffer return location for buffer to append bytes to
2397  */
2398 void
2399 _dbus_auth_get_buffer (DBusAuth     *auth,
2400                        DBusString **buffer)
2401 {
2402   _dbus_assert (auth != NULL);
2403   _dbus_assert (!auth->buffer_outstanding);
2404   
2405   *buffer = &auth->incoming;
2406
2407   auth->buffer_outstanding = TRUE;
2408 }
2409
2410 /**
2411  * Returns a buffer with new data read into it.
2412  *
2413  * @param auth the auth conversation
2414  * @param buffer the buffer being returned
2415  * @param bytes_read number of new bytes added
2416  */
2417 void
2418 _dbus_auth_return_buffer (DBusAuth               *auth,
2419                           DBusString             *buffer,
2420                           int                     bytes_read)
2421 {
2422   _dbus_assert (buffer == &auth->incoming);
2423   _dbus_assert (auth->buffer_outstanding);
2424
2425   auth->buffer_outstanding = FALSE;
2426 }
2427
2428 /**
2429  * Returns leftover bytes that were not used as part of the auth
2430  * conversation.  These bytes will be part of the message stream
2431  * instead. This function may not be called until authentication has
2432  * succeeded.
2433  *
2434  * @param auth the auth conversation
2435  * @param str return location for pointer to string of unused bytes
2436  */
2437 void
2438 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
2439                              const DBusString **str)
2440 {
2441   if (!DBUS_AUTH_IN_END_STATE (auth))
2442     return;
2443
2444   *str = &auth->incoming;
2445 }
2446
2447
2448 /**
2449  * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
2450  * after we've gotten them and successfully moved them elsewhere.
2451  *
2452  * @param auth the auth conversation
2453  */
2454 void
2455 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
2456 {
2457   if (!DBUS_AUTH_IN_END_STATE (auth))
2458     return;
2459
2460   _dbus_string_set_length (&auth->incoming, 0);
2461 }
2462
2463 /**
2464  * Called post-authentication, indicates whether we need to encode
2465  * the message stream with _dbus_auth_encode_data() prior to
2466  * sending it to the peer.
2467  *
2468  * @param auth the auth conversation
2469  * @returns #TRUE if we need to encode the stream
2470  */
2471 dbus_bool_t
2472 _dbus_auth_needs_encoding (DBusAuth *auth)
2473 {
2474   if (auth->state != &common_state_authenticated)
2475     return FALSE;
2476   
2477   if (auth->mech != NULL)
2478     {
2479       if (DBUS_AUTH_IS_CLIENT (auth))
2480         return auth->mech->client_encode_func != NULL;
2481       else
2482         return auth->mech->server_encode_func != NULL;
2483     }
2484   else
2485     return FALSE;
2486 }
2487
2488 /**
2489  * Called post-authentication, encodes a block of bytes for sending to
2490  * the peer. If no encoding was negotiated, just copies the bytes
2491  * (you can avoid this by checking _dbus_auth_needs_encoding()).
2492  *
2493  * @param auth the auth conversation
2494  * @param plaintext the plain text data
2495  * @param encoded initialized string to where encoded data is appended
2496  * @returns #TRUE if we had enough memory and successfully encoded
2497  */
2498 dbus_bool_t
2499 _dbus_auth_encode_data (DBusAuth         *auth,
2500                         const DBusString *plaintext,
2501                         DBusString       *encoded)
2502 {
2503   _dbus_assert (plaintext != encoded);
2504   
2505   if (auth->state != &common_state_authenticated)
2506     return FALSE;
2507   
2508   if (_dbus_auth_needs_encoding (auth))
2509     {
2510       if (DBUS_AUTH_IS_CLIENT (auth))
2511         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
2512       else
2513         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
2514     }
2515   else
2516     {
2517       return _dbus_string_copy (plaintext, 0, encoded,
2518                                 _dbus_string_get_length (encoded));
2519     }
2520 }
2521
2522 /**
2523  * Called post-authentication, indicates whether we need to decode
2524  * the message stream with _dbus_auth_decode_data() after
2525  * receiving it from the peer.
2526  *
2527  * @param auth the auth conversation
2528  * @returns #TRUE if we need to encode the stream
2529  */
2530 dbus_bool_t
2531 _dbus_auth_needs_decoding (DBusAuth *auth)
2532 {
2533   if (auth->state != &common_state_authenticated)
2534     return FALSE;
2535     
2536   if (auth->mech != NULL)
2537     {
2538       if (DBUS_AUTH_IS_CLIENT (auth))
2539         return auth->mech->client_decode_func != NULL;
2540       else
2541         return auth->mech->server_decode_func != NULL;
2542     }
2543   else
2544     return FALSE;
2545 }
2546
2547
2548 /**
2549  * Called post-authentication, decodes a block of bytes received from
2550  * the peer. If no encoding was negotiated, just copies the bytes (you
2551  * can avoid this by checking _dbus_auth_needs_decoding()).
2552  *
2553  * @todo 1.0? We need to be able to distinguish "out of memory" error
2554  * from "the data is hosed" error.
2555  *
2556  * @param auth the auth conversation
2557  * @param encoded the encoded data
2558  * @param plaintext initialized string where decoded data is appended
2559  * @returns #TRUE if we had enough memory and successfully decoded
2560  */
2561 dbus_bool_t
2562 _dbus_auth_decode_data (DBusAuth         *auth,
2563                         const DBusString *encoded,
2564                         DBusString       *plaintext)
2565 {
2566   _dbus_assert (plaintext != encoded);
2567   
2568   if (auth->state != &common_state_authenticated)
2569     return FALSE;
2570   
2571   if (_dbus_auth_needs_decoding (auth))
2572     {
2573       if (DBUS_AUTH_IS_CLIENT (auth))
2574         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
2575       else
2576         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
2577     }
2578   else
2579     {
2580       return _dbus_string_copy (encoded, 0, plaintext,
2581                                 _dbus_string_get_length (plaintext));
2582     }
2583 }
2584
2585 /**
2586  * Sets credentials received via reliable means from the operating
2587  * system.
2588  *
2589  * @param auth the auth conversation
2590  * @param credentials the credentials received
2591  * @returns #FALSE on OOM
2592  */
2593 dbus_bool_t
2594 _dbus_auth_set_credentials (DBusAuth               *auth,
2595                             DBusCredentials        *credentials)
2596 {
2597   _dbus_credentials_clear (auth->credentials);
2598   return _dbus_credentials_add_credentials (auth->credentials,
2599                                             credentials);
2600 }
2601
2602 /**
2603  * Gets the identity we authorized the client as.  Apps may have
2604  * different policies as to what identities they allow.
2605  *
2606  * Returned credentials are not a copy and should not be modified
2607  *
2608  * @param auth the auth conversation
2609  * @returns the credentials we've authorized BY REFERENCE do not modify
2610  */
2611 DBusCredentials*
2612 _dbus_auth_get_identity (DBusAuth               *auth)
2613 {
2614   if (auth->state == &common_state_authenticated)
2615     {
2616       return auth->authorized_identity;
2617     }
2618   else
2619     {
2620       /* FIXME instead of this, keep an empty credential around that
2621        * doesn't require allocation or something
2622        */
2623       /* return empty credentials */
2624       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
2625       return auth->authorized_identity;
2626     }
2627 }
2628
2629 /**
2630  * Gets the GUID from the server if we've authenticated; gets
2631  * #NULL otherwise.
2632  * @param auth the auth object
2633  * @returns the GUID in ASCII hex format
2634  */
2635 const char*
2636 _dbus_auth_get_guid_from_server (DBusAuth *auth)
2637 {
2638   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
2639   
2640   if (auth->state == &common_state_authenticated)
2641     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2642   else
2643     return NULL;
2644 }
2645
2646 /**
2647  * Sets the "authentication context" which scopes cookies
2648  * with the DBUS_COOKIE_SHA1 auth mechanism for example.
2649  *
2650  * @param auth the auth conversation
2651  * @param context the context
2652  * @returns #FALSE if no memory
2653  */
2654 dbus_bool_t
2655 _dbus_auth_set_context (DBusAuth               *auth,
2656                         const DBusString       *context)
2657 {
2658   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
2659                                    &auth->context, 0, _dbus_string_get_length (context));
2660 }
2661
2662 /** @} */
2663
2664 /* tests in dbus-auth-util.c */