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