cmake/cross-compile.sh: use mktemp(1) to avoid a symlink attack in /tmp
[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 manage 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 process ID 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       /* also copy audit data from the socket credentials
1113        */
1114       if (!_dbus_credentials_add_credential (auth->authorized_identity,
1115                                              DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
1116                                              auth->credentials))
1117         return FALSE;
1118       
1119       if (!send_ok (auth))
1120         return FALSE;
1121
1122       _dbus_verbose ("%s: authenticated client based on socket credentials\n",
1123                      DBUS_AUTH_NAME (auth));
1124
1125       return TRUE;
1126     }
1127   else
1128     {
1129       _dbus_verbose ("%s: desired identity not found in socket credentials\n",
1130                      DBUS_AUTH_NAME (auth));
1131       return send_rejected (auth);
1132     }
1133 }
1134
1135 static void
1136 handle_server_shutdown_external_mech (DBusAuth *auth)
1137 {
1138
1139 }
1140
1141 static dbus_bool_t
1142 handle_client_initial_response_external_mech (DBusAuth         *auth,
1143                                               DBusString       *response)
1144 {
1145   /* We always append our UID as an initial response, so the server
1146    * doesn't have to send back an empty challenge to check whether we
1147    * want to specify an identity. i.e. this avoids a round trip that
1148    * the spec for the EXTERNAL mechanism otherwise requires.
1149    */
1150   DBusString plaintext;
1151
1152   if (!_dbus_string_init (&plaintext))
1153     return FALSE;
1154
1155   if (!_dbus_append_user_from_current_process (&plaintext))
1156     goto failed;
1157
1158   if (!_dbus_string_hex_encode (&plaintext, 0,
1159                                 response,
1160                                 _dbus_string_get_length (response)))
1161     goto failed;
1162
1163   _dbus_string_free (&plaintext);
1164   
1165   return TRUE;
1166
1167  failed:
1168   _dbus_string_free (&plaintext);
1169   return FALSE;  
1170 }
1171
1172 static dbus_bool_t
1173 handle_client_data_external_mech (DBusAuth         *auth,
1174                                   const DBusString *data)
1175 {
1176   
1177   return TRUE;
1178 }
1179
1180 static void
1181 handle_client_shutdown_external_mech (DBusAuth *auth)
1182 {
1183
1184 }
1185
1186 /*
1187  * ANONYMOUS mechanism
1188  */
1189
1190 static dbus_bool_t
1191 handle_server_data_anonymous_mech (DBusAuth         *auth,
1192                                    const DBusString *data)
1193 {  
1194   if (_dbus_string_get_length (data) > 0)
1195     {
1196       /* Client is allowed to send "trace" data, the only defined
1197        * meaning is that if it contains '@' it is an email address,
1198        * and otherwise it is anything else, and it's supposed to be
1199        * UTF-8
1200        */
1201       if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
1202         {
1203           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
1204                          DBUS_AUTH_NAME (auth));
1205
1206           {
1207             DBusString plaintext;
1208             DBusString encoded;
1209             _dbus_string_init_const (&plaintext, "D-Bus " DBUS_VERSION_STRING);
1210             _dbus_string_init (&encoded);
1211             _dbus_string_hex_encode (&plaintext, 0,
1212                                      &encoded,
1213                                      0);
1214               _dbus_verbose ("%s: try '%s'\n",
1215                              DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
1216           }
1217           return send_rejected (auth);
1218         }
1219       
1220       _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
1221                      DBUS_AUTH_NAME (auth),
1222                      _dbus_string_get_const_data (data));
1223     }
1224
1225   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
1226   _dbus_credentials_clear (auth->desired_identity);
1227
1228   /* Copy process ID from the socket credentials
1229    */
1230   if (!_dbus_credentials_add_credential (auth->authorized_identity,
1231                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
1232                                          auth->credentials))
1233     return FALSE;
1234   
1235   /* Anonymous is always allowed */
1236   if (!send_ok (auth))
1237     return FALSE;
1238
1239   _dbus_verbose ("%s: authenticated client as anonymous\n",
1240                  DBUS_AUTH_NAME (auth));
1241
1242   return TRUE;
1243 }
1244
1245 static void
1246 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
1247 {
1248   
1249 }
1250
1251 static dbus_bool_t
1252 handle_client_initial_response_anonymous_mech (DBusAuth         *auth,
1253                                                DBusString       *response)
1254 {
1255   /* Our initial response is a "trace" string which must be valid UTF-8
1256    * and must be an email address if it contains '@'.
1257    * We just send the dbus implementation info, like a user-agent or
1258    * something, because... why not. There's nothing guaranteed here
1259    * though, we could change it later.
1260    */
1261   DBusString plaintext;
1262
1263   if (!_dbus_string_init (&plaintext))
1264     return FALSE;
1265
1266   if (!_dbus_string_append (&plaintext,
1267                             "libdbus " DBUS_VERSION_STRING))
1268     goto failed;
1269
1270   if (!_dbus_string_hex_encode (&plaintext, 0,
1271                                 response,
1272                                 _dbus_string_get_length (response)))
1273     goto failed;
1274
1275   _dbus_string_free (&plaintext);
1276   
1277   return TRUE;
1278
1279  failed:
1280   _dbus_string_free (&plaintext);
1281   return FALSE;  
1282 }
1283
1284 static dbus_bool_t
1285 handle_client_data_anonymous_mech (DBusAuth         *auth,
1286                                   const DBusString *data)
1287 {
1288   
1289   return TRUE;
1290 }
1291
1292 static void
1293 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
1294 {
1295   
1296 }
1297
1298 /* Put mechanisms here in order of preference.
1299  * Right now we have:
1300  *
1301  * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
1302  * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
1303  * - ANONYMOUS checks nothing but doesn't auth the person as a user
1304  *
1305  * We might ideally add a mechanism to chain to Cyrus SASL so we can
1306  * use its mechanisms as well.
1307  * 
1308  */
1309 static const DBusAuthMechanismHandler
1310 all_mechanisms[] = {
1311   { "EXTERNAL",
1312     handle_server_data_external_mech,
1313     NULL, NULL,
1314     handle_server_shutdown_external_mech,
1315     handle_client_initial_response_external_mech,
1316     handle_client_data_external_mech,
1317     NULL, NULL,
1318     handle_client_shutdown_external_mech },
1319   { "DBUS_COOKIE_SHA1",
1320     handle_server_data_cookie_sha1_mech,
1321     NULL, NULL,
1322     handle_server_shutdown_cookie_sha1_mech,
1323     handle_client_initial_response_cookie_sha1_mech,
1324     handle_client_data_cookie_sha1_mech,
1325     NULL, NULL,
1326     handle_client_shutdown_cookie_sha1_mech },
1327   { "ANONYMOUS",
1328     handle_server_data_anonymous_mech,
1329     NULL, NULL,
1330     handle_server_shutdown_anonymous_mech,
1331     handle_client_initial_response_anonymous_mech,
1332     handle_client_data_anonymous_mech,
1333     NULL, NULL,
1334     handle_client_shutdown_anonymous_mech },  
1335   { NULL, NULL }
1336 };
1337
1338 static const DBusAuthMechanismHandler*
1339 find_mech (const DBusString  *name,
1340            char             **allowed_mechs)
1341 {
1342   int i;
1343   
1344   if (allowed_mechs != NULL &&
1345       !_dbus_string_array_contains ((const char**) allowed_mechs,
1346                                     _dbus_string_get_const_data (name)))
1347     return NULL;
1348   
1349   i = 0;
1350   while (all_mechanisms[i].mechanism != NULL)
1351     {      
1352       if (_dbus_string_equal_c_str (name,
1353                                     all_mechanisms[i].mechanism))
1354
1355         return &all_mechanisms[i];
1356       
1357       ++i;
1358     }
1359   
1360   return NULL;
1361 }
1362
1363 static dbus_bool_t
1364 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
1365 {
1366   DBusString auth_command;
1367
1368   if (!_dbus_string_init (&auth_command))
1369     return FALSE;
1370       
1371   if (!_dbus_string_append (&auth_command,
1372                             "AUTH "))
1373     {
1374       _dbus_string_free (&auth_command);
1375       return FALSE;
1376     }  
1377   
1378   if (!_dbus_string_append (&auth_command,
1379                             mech->mechanism))
1380     {
1381       _dbus_string_free (&auth_command);
1382       return FALSE;
1383     }
1384
1385   if (mech->client_initial_response_func != NULL)
1386     {
1387       if (!_dbus_string_append (&auth_command, " "))
1388         {
1389           _dbus_string_free (&auth_command);
1390           return FALSE;
1391         }
1392       
1393       if (!(* mech->client_initial_response_func) (auth, &auth_command))
1394         {
1395           _dbus_string_free (&auth_command);
1396           return FALSE;
1397         }
1398     }
1399   
1400   if (!_dbus_string_append (&auth_command,
1401                             "\r\n"))
1402     {
1403       _dbus_string_free (&auth_command);
1404       return FALSE;
1405     }
1406
1407   if (!_dbus_string_copy (&auth_command, 0,
1408                           &auth->outgoing,
1409                           _dbus_string_get_length (&auth->outgoing)))
1410     {
1411       _dbus_string_free (&auth_command);
1412       return FALSE;
1413     }
1414
1415   _dbus_string_free (&auth_command);
1416   shutdown_mech (auth);
1417   auth->mech = mech;      
1418   goto_state (auth, &client_state_waiting_for_data);
1419
1420   return TRUE;
1421 }
1422
1423 static dbus_bool_t
1424 send_data (DBusAuth *auth, DBusString *data)
1425 {
1426   int old_len;
1427
1428   if (data == NULL || _dbus_string_get_length (data) == 0)
1429     return _dbus_string_append (&auth->outgoing, "DATA\r\n");
1430   else
1431     {
1432       old_len = _dbus_string_get_length (&auth->outgoing);
1433       if (!_dbus_string_append (&auth->outgoing, "DATA "))
1434         goto out;
1435
1436       if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
1437                                     _dbus_string_get_length (&auth->outgoing)))
1438         goto out;
1439
1440       if (!_dbus_string_append (&auth->outgoing, "\r\n"))
1441         goto out;
1442
1443       return TRUE;
1444
1445     out:
1446       _dbus_string_set_length (&auth->outgoing, old_len);
1447
1448       return FALSE;
1449     }
1450 }
1451
1452 static dbus_bool_t
1453 send_rejected (DBusAuth *auth)
1454 {
1455   DBusString command;
1456   DBusAuthServer *server_auth;
1457   int i;
1458   
1459   if (!_dbus_string_init (&command))
1460     return FALSE;
1461   
1462   if (!_dbus_string_append (&command,
1463                             "REJECTED"))
1464     goto nomem;
1465
1466   i = 0;
1467   while (all_mechanisms[i].mechanism != NULL)
1468     {
1469       if (!_dbus_string_append (&command,
1470                                 " "))
1471         goto nomem;
1472
1473       if (!_dbus_string_append (&command,
1474                                 all_mechanisms[i].mechanism))
1475         goto nomem;
1476       
1477       ++i;
1478     }
1479   
1480   if (!_dbus_string_append (&command, "\r\n"))
1481     goto nomem;
1482
1483   if (!_dbus_string_copy (&command, 0, &auth->outgoing,
1484                           _dbus_string_get_length (&auth->outgoing)))
1485     goto nomem;
1486
1487   shutdown_mech (auth);
1488   
1489   _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
1490   server_auth = DBUS_AUTH_SERVER (auth);
1491   server_auth->failures += 1;
1492
1493   if (server_auth->failures >= server_auth->max_failures)
1494     goto_state (auth, &common_state_need_disconnect);
1495   else
1496     goto_state (auth, &server_state_waiting_for_auth);
1497
1498   _dbus_string_free (&command);
1499   
1500   return TRUE;
1501
1502  nomem:
1503   _dbus_string_free (&command);
1504   return FALSE;
1505 }
1506
1507 static dbus_bool_t
1508 send_error (DBusAuth *auth, const char *message)
1509 {
1510   return _dbus_string_append_printf (&auth->outgoing,
1511                                      "ERROR \"%s\"\r\n", message);
1512 }
1513
1514 static dbus_bool_t
1515 send_ok (DBusAuth *auth)
1516 {
1517   int orig_len;
1518
1519   orig_len = _dbus_string_get_length (&auth->outgoing);
1520   
1521   if (_dbus_string_append (&auth->outgoing, "OK ") &&
1522       _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
1523                          0,
1524                          &auth->outgoing,
1525                          _dbus_string_get_length (&auth->outgoing)) &&
1526       _dbus_string_append (&auth->outgoing, "\r\n"))
1527     {
1528       goto_state (auth, &server_state_waiting_for_begin);
1529       return TRUE;
1530     }
1531   else
1532     {
1533       _dbus_string_set_length (&auth->outgoing, orig_len);
1534       return FALSE;
1535     }
1536 }
1537
1538 static dbus_bool_t
1539 send_begin (DBusAuth         *auth)
1540 {
1541
1542   if (!_dbus_string_append (&auth->outgoing,
1543                             "BEGIN\r\n"))
1544     return FALSE;
1545
1546   goto_state (auth, &common_state_authenticated);
1547   return TRUE;
1548 }
1549
1550 static dbus_bool_t
1551 process_ok(DBusAuth *auth,
1552           const DBusString *args_from_ok) {
1553
1554   int end_of_hex;
1555   
1556   /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
1557   _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
1558
1559   /* We decode the hex string to binary, using guid_from_server as scratch... */
1560   
1561   end_of_hex = 0;
1562   if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
1563                                 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
1564     return FALSE;
1565
1566   /* now clear out the scratch */
1567   _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1568   
1569   if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
1570       end_of_hex == 0)
1571     {
1572       _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
1573                      end_of_hex, _dbus_string_get_length (args_from_ok));
1574       goto_state (auth, &common_state_need_disconnect);
1575       return TRUE;
1576     }
1577
1578   if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
1579       _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1580       return FALSE;
1581   }
1582
1583   _dbus_verbose ("Got GUID '%s' from the server\n",
1584                  _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
1585
1586   if (auth->unix_fd_possible)
1587     return send_negotiate_unix_fd(auth);
1588
1589   _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
1590   return send_begin (auth);
1591 }
1592
1593 static dbus_bool_t
1594 send_cancel (DBusAuth *auth)
1595 {
1596   if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
1597     {
1598       goto_state (auth, &client_state_waiting_for_reject);
1599       return TRUE;
1600     }
1601   else
1602     return FALSE;
1603 }
1604
1605 static dbus_bool_t
1606 process_data (DBusAuth             *auth,
1607               const DBusString     *args,
1608               DBusAuthDataFunction  data_func)
1609 {
1610   int end;
1611   DBusString decoded;
1612
1613   if (!_dbus_string_init (&decoded))
1614     return FALSE;
1615
1616   if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
1617     {
1618       _dbus_string_free (&decoded);
1619       return FALSE;
1620     }
1621
1622   if (_dbus_string_get_length (args) != end)
1623     {
1624       _dbus_string_free (&decoded);
1625       if (!send_error (auth, "Invalid hex encoding"))
1626         return FALSE;
1627
1628       return TRUE;
1629     }
1630
1631 #ifdef DBUS_ENABLE_VERBOSE_MODE
1632   if (_dbus_string_validate_ascii (&decoded, 0,
1633                                    _dbus_string_get_length (&decoded)))
1634     _dbus_verbose ("%s: data: '%s'\n",
1635                    DBUS_AUTH_NAME (auth),
1636                    _dbus_string_get_const_data (&decoded));
1637 #endif
1638       
1639   if (!(* data_func) (auth, &decoded))
1640     {
1641       _dbus_string_free (&decoded);
1642       return FALSE;
1643     }
1644
1645   _dbus_string_free (&decoded);
1646   return TRUE;
1647 }
1648
1649 static dbus_bool_t
1650 send_negotiate_unix_fd (DBusAuth *auth)
1651 {
1652   if (!_dbus_string_append (&auth->outgoing,
1653                             "NEGOTIATE_UNIX_FD\r\n"))
1654     return FALSE;
1655
1656   goto_state (auth, &client_state_waiting_for_agree_unix_fd);
1657   return TRUE;
1658 }
1659
1660 static dbus_bool_t
1661 send_agree_unix_fd (DBusAuth *auth)
1662 {
1663   _dbus_assert(auth->unix_fd_possible);
1664
1665   auth->unix_fd_negotiated = TRUE;
1666   _dbus_verbose("Agreed to UNIX FD passing\n");
1667
1668   if (!_dbus_string_append (&auth->outgoing,
1669                             "AGREE_UNIX_FD\r\n"))
1670     return FALSE;
1671
1672   goto_state (auth, &server_state_waiting_for_begin);
1673   return TRUE;
1674 }
1675
1676 static dbus_bool_t
1677 handle_auth (DBusAuth *auth, const DBusString *args)
1678 {
1679   if (_dbus_string_get_length (args) == 0)
1680     {
1681       /* No args to the auth, send mechanisms */
1682       if (!send_rejected (auth))
1683         return FALSE;
1684
1685       return TRUE;
1686     }
1687   else
1688     {
1689       int i;
1690       DBusString mech;
1691       DBusString hex_response;
1692       
1693       _dbus_string_find_blank (args, 0, &i);
1694
1695       if (!_dbus_string_init (&mech))
1696         return FALSE;
1697
1698       if (!_dbus_string_init (&hex_response))
1699         {
1700           _dbus_string_free (&mech);
1701           return FALSE;
1702         }
1703       
1704       if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
1705         goto failed;
1706
1707       _dbus_string_skip_blank (args, i, &i);
1708       if (!_dbus_string_copy (args, i, &hex_response, 0))
1709         goto failed;
1710      
1711       auth->mech = find_mech (&mech, auth->allowed_mechs);
1712       if (auth->mech != NULL)
1713         {
1714           _dbus_verbose ("%s: Trying mechanism %s\n",
1715                          DBUS_AUTH_NAME (auth),
1716                          auth->mech->mechanism);
1717           
1718           if (!process_data (auth, &hex_response,
1719                              auth->mech->server_data_func))
1720             goto failed;
1721         }
1722       else
1723         {
1724           /* Unsupported mechanism */
1725           _dbus_verbose ("%s: Unsupported mechanism %s\n",
1726                          DBUS_AUTH_NAME (auth),
1727                          _dbus_string_get_const_data (&mech));
1728           
1729           if (!send_rejected (auth))
1730             goto failed;
1731         }
1732
1733       _dbus_string_free (&mech);      
1734       _dbus_string_free (&hex_response);
1735
1736       return TRUE;
1737       
1738     failed:
1739       auth->mech = NULL;
1740       _dbus_string_free (&mech);
1741       _dbus_string_free (&hex_response);
1742       return FALSE;
1743     }
1744 }
1745
1746 static dbus_bool_t
1747 handle_server_state_waiting_for_auth  (DBusAuth         *auth,
1748                                        DBusAuthCommand   command,
1749                                        const DBusString *args)
1750 {
1751   switch (command)
1752     {
1753     case DBUS_AUTH_COMMAND_AUTH:
1754       return handle_auth (auth, args);
1755
1756     case DBUS_AUTH_COMMAND_CANCEL:
1757     case DBUS_AUTH_COMMAND_DATA:
1758       return send_error (auth, "Not currently in an auth conversation");
1759
1760     case DBUS_AUTH_COMMAND_BEGIN:
1761       goto_state (auth, &common_state_need_disconnect);
1762       return TRUE;
1763
1764     case DBUS_AUTH_COMMAND_ERROR:
1765       return send_rejected (auth);
1766
1767     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1768       return send_error (auth, "Need to authenticate first");
1769
1770     case DBUS_AUTH_COMMAND_REJECTED:
1771     case DBUS_AUTH_COMMAND_OK:
1772     case DBUS_AUTH_COMMAND_UNKNOWN:
1773     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1774     default:
1775       return send_error (auth, "Unknown command");
1776     }
1777 }
1778
1779 static dbus_bool_t
1780 handle_server_state_waiting_for_data  (DBusAuth         *auth,
1781                                        DBusAuthCommand   command,
1782                                        const DBusString *args)
1783 {
1784   switch (command)
1785     {
1786     case DBUS_AUTH_COMMAND_AUTH:
1787       return send_error (auth, "Sent AUTH while another AUTH in progress");
1788
1789     case DBUS_AUTH_COMMAND_CANCEL:
1790     case DBUS_AUTH_COMMAND_ERROR:
1791       return send_rejected (auth);
1792
1793     case DBUS_AUTH_COMMAND_DATA:
1794       return process_data (auth, args, auth->mech->server_data_func);
1795
1796     case DBUS_AUTH_COMMAND_BEGIN:
1797       goto_state (auth, &common_state_need_disconnect);
1798       return TRUE;
1799
1800     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1801       return send_error (auth, "Need to authenticate first");
1802
1803     case DBUS_AUTH_COMMAND_REJECTED:
1804     case DBUS_AUTH_COMMAND_OK:
1805     case DBUS_AUTH_COMMAND_UNKNOWN:
1806     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1807     default:
1808       return send_error (auth, "Unknown command");
1809     }
1810 }
1811
1812 static dbus_bool_t
1813 handle_server_state_waiting_for_begin (DBusAuth         *auth,
1814                                        DBusAuthCommand   command,
1815                                        const DBusString *args)
1816 {
1817   switch (command)
1818     {
1819     case DBUS_AUTH_COMMAND_AUTH:
1820       return send_error (auth, "Sent AUTH while expecting BEGIN");
1821
1822     case DBUS_AUTH_COMMAND_DATA:
1823       return send_error (auth, "Sent DATA while expecting BEGIN");
1824
1825     case DBUS_AUTH_COMMAND_BEGIN:
1826       goto_state (auth, &common_state_authenticated);
1827       return TRUE;
1828
1829     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1830       if (auth->unix_fd_possible)
1831         return send_agree_unix_fd(auth);
1832       else
1833         return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
1834
1835     case DBUS_AUTH_COMMAND_REJECTED:
1836     case DBUS_AUTH_COMMAND_OK:
1837     case DBUS_AUTH_COMMAND_UNKNOWN:
1838     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1839     default:
1840       return send_error (auth, "Unknown command");
1841
1842     case DBUS_AUTH_COMMAND_CANCEL:
1843     case DBUS_AUTH_COMMAND_ERROR:
1844       return send_rejected (auth);
1845     }
1846 }
1847
1848 /* return FALSE if no memory, TRUE if all OK */
1849 static dbus_bool_t
1850 get_word (const DBusString *str,
1851           int              *start,
1852           DBusString       *word)
1853 {
1854   int i;
1855
1856   _dbus_string_skip_blank (str, *start, start);
1857   _dbus_string_find_blank (str, *start, &i);
1858   
1859   if (i > *start)
1860     {
1861       if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
1862         return FALSE;
1863       
1864       *start = i;
1865     }
1866
1867   return TRUE;
1868 }
1869
1870 static dbus_bool_t
1871 record_mechanisms (DBusAuth         *auth,
1872                    const DBusString *args)
1873 {
1874   int next;
1875   int len;
1876
1877   if (auth->already_got_mechanisms)
1878     return TRUE;
1879   
1880   len = _dbus_string_get_length (args);
1881   
1882   next = 0;
1883   while (next < len)
1884     {
1885       DBusString m;
1886       const DBusAuthMechanismHandler *mech;
1887       
1888       if (!_dbus_string_init (&m))
1889         goto nomem;
1890       
1891       if (!get_word (args, &next, &m))
1892         {
1893           _dbus_string_free (&m);
1894           goto nomem;
1895         }
1896
1897       mech = find_mech (&m, auth->allowed_mechs);
1898
1899       if (mech != NULL)
1900         {
1901           /* FIXME right now we try mechanisms in the order
1902            * the server lists them; should we do them in
1903            * some more deterministic order?
1904            *
1905            * Probably in all_mechanisms order, our order of
1906            * preference. Of course when the server is us,
1907            * it lists things in that order anyhow.
1908            */
1909
1910           if (mech != &all_mechanisms[0])
1911             {
1912               _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
1913                              DBUS_AUTH_NAME (auth), mech->mechanism);
1914           
1915               if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
1916                                       (void*) mech))
1917                 {
1918                   _dbus_string_free (&m);
1919                   goto nomem;
1920                 }
1921             }
1922           else
1923             {
1924               _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
1925                              DBUS_AUTH_NAME (auth), mech->mechanism);
1926             }
1927         }
1928       else
1929         {
1930           _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
1931                          DBUS_AUTH_NAME (auth),
1932                          _dbus_string_get_const_data (&m));
1933         }
1934
1935       _dbus_string_free (&m);
1936     }
1937   
1938   auth->already_got_mechanisms = TRUE;
1939   
1940   return TRUE;
1941
1942  nomem:
1943   _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
1944   
1945   return FALSE;
1946 }
1947
1948 static dbus_bool_t
1949 process_rejected (DBusAuth *auth, const DBusString *args)
1950 {
1951   const DBusAuthMechanismHandler *mech;
1952   DBusAuthClient *client;
1953
1954   client = DBUS_AUTH_CLIENT (auth);
1955
1956   if (!auth->already_got_mechanisms)
1957     {
1958       if (!record_mechanisms (auth, args))
1959         return FALSE;
1960     }
1961   
1962   if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
1963     {
1964       mech = client->mechs_to_try->data;
1965
1966       if (!send_auth (auth, mech))
1967         return FALSE;
1968
1969       _dbus_list_pop_first (&client->mechs_to_try);
1970
1971       _dbus_verbose ("%s: Trying mechanism %s\n",
1972                      DBUS_AUTH_NAME (auth),
1973                      mech->mechanism);
1974     }
1975   else
1976     {
1977       /* Give up */
1978       _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
1979                      DBUS_AUTH_NAME (auth));
1980       goto_state (auth, &common_state_need_disconnect);
1981     }
1982   
1983   return TRUE;
1984 }
1985
1986
1987 static dbus_bool_t
1988 handle_client_state_waiting_for_data (DBusAuth         *auth,
1989                                       DBusAuthCommand   command,
1990                                       const DBusString *args)
1991 {
1992   _dbus_assert (auth->mech != NULL);
1993  
1994   switch (command)
1995     {
1996     case DBUS_AUTH_COMMAND_DATA:
1997       return process_data (auth, args, auth->mech->client_data_func);
1998
1999     case DBUS_AUTH_COMMAND_REJECTED:
2000       return process_rejected (auth, args);
2001
2002     case DBUS_AUTH_COMMAND_OK:
2003       return process_ok(auth, args);
2004
2005     case DBUS_AUTH_COMMAND_ERROR:
2006       return send_cancel (auth);
2007
2008     case DBUS_AUTH_COMMAND_AUTH:
2009     case DBUS_AUTH_COMMAND_CANCEL:
2010     case DBUS_AUTH_COMMAND_BEGIN:
2011     case DBUS_AUTH_COMMAND_UNKNOWN:
2012     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2013     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2014     default:
2015       return send_error (auth, "Unknown command");
2016     }
2017 }
2018
2019 static dbus_bool_t
2020 handle_client_state_waiting_for_ok (DBusAuth         *auth,
2021                                     DBusAuthCommand   command,
2022                                     const DBusString *args)
2023 {
2024   switch (command)
2025     {
2026     case DBUS_AUTH_COMMAND_REJECTED:
2027       return process_rejected (auth, args);
2028
2029     case DBUS_AUTH_COMMAND_OK:
2030       return process_ok(auth, args);
2031
2032     case DBUS_AUTH_COMMAND_DATA:
2033     case DBUS_AUTH_COMMAND_ERROR:
2034       return send_cancel (auth);
2035
2036     case DBUS_AUTH_COMMAND_AUTH:
2037     case DBUS_AUTH_COMMAND_CANCEL:
2038     case DBUS_AUTH_COMMAND_BEGIN:
2039     case DBUS_AUTH_COMMAND_UNKNOWN:
2040     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2041     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2042     default:
2043       return send_error (auth, "Unknown command");
2044     }
2045 }
2046
2047 static dbus_bool_t
2048 handle_client_state_waiting_for_reject (DBusAuth         *auth,
2049                                         DBusAuthCommand   command,
2050                                         const DBusString *args)
2051 {
2052   switch (command)
2053     {
2054     case DBUS_AUTH_COMMAND_REJECTED:
2055       return process_rejected (auth, args);
2056       
2057     case DBUS_AUTH_COMMAND_AUTH:
2058     case DBUS_AUTH_COMMAND_CANCEL:
2059     case DBUS_AUTH_COMMAND_DATA:
2060     case DBUS_AUTH_COMMAND_BEGIN:
2061     case DBUS_AUTH_COMMAND_OK:
2062     case DBUS_AUTH_COMMAND_ERROR:
2063     case DBUS_AUTH_COMMAND_UNKNOWN:
2064     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2065     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2066     default:
2067       goto_state (auth, &common_state_need_disconnect);
2068       return TRUE;
2069     }
2070 }
2071
2072 static dbus_bool_t
2073 handle_client_state_waiting_for_agree_unix_fd(DBusAuth         *auth,
2074                                               DBusAuthCommand   command,
2075                                               const DBusString *args)
2076 {
2077   switch (command)
2078     {
2079     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2080       _dbus_assert(auth->unix_fd_possible);
2081       auth->unix_fd_negotiated = TRUE;
2082       _dbus_verbose("Sucessfully negotiated UNIX FD passing\n");
2083       return send_begin (auth);
2084
2085     case DBUS_AUTH_COMMAND_ERROR:
2086       _dbus_assert(auth->unix_fd_possible);
2087       auth->unix_fd_negotiated = FALSE;
2088       _dbus_verbose("Failed to negotiate UNIX FD passing\n");
2089       return send_begin (auth);
2090
2091     case DBUS_AUTH_COMMAND_OK:
2092     case DBUS_AUTH_COMMAND_DATA:
2093     case DBUS_AUTH_COMMAND_REJECTED:
2094     case DBUS_AUTH_COMMAND_AUTH:
2095     case DBUS_AUTH_COMMAND_CANCEL:
2096     case DBUS_AUTH_COMMAND_BEGIN:
2097     case DBUS_AUTH_COMMAND_UNKNOWN:
2098     case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2099     default:
2100       return send_error (auth, "Unknown command");
2101     }
2102 }
2103
2104 /**
2105  * Mapping from command name to enum
2106  */
2107 typedef struct {
2108   const char *name;        /**< Name of the command */
2109   DBusAuthCommand command; /**< Corresponding enum */
2110 } DBusAuthCommandName;
2111
2112 static const DBusAuthCommandName auth_command_names[] = {
2113   { "AUTH",              DBUS_AUTH_COMMAND_AUTH },
2114   { "CANCEL",            DBUS_AUTH_COMMAND_CANCEL },
2115   { "DATA",              DBUS_AUTH_COMMAND_DATA },
2116   { "BEGIN",             DBUS_AUTH_COMMAND_BEGIN },
2117   { "REJECTED",          DBUS_AUTH_COMMAND_REJECTED },
2118   { "OK",                DBUS_AUTH_COMMAND_OK },
2119   { "ERROR",             DBUS_AUTH_COMMAND_ERROR },
2120   { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
2121   { "AGREE_UNIX_FD",     DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
2122 };
2123
2124 static DBusAuthCommand
2125 lookup_command_from_name (DBusString *command)
2126 {
2127   int i;
2128
2129   for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
2130     {
2131       if (_dbus_string_equal_c_str (command,
2132                                     auth_command_names[i].name))
2133         return auth_command_names[i].command;
2134     }
2135
2136   return DBUS_AUTH_COMMAND_UNKNOWN;
2137 }
2138
2139 static void
2140 goto_state (DBusAuth *auth,
2141             const DBusAuthStateData *state)
2142 {
2143   _dbus_verbose ("%s: going from state %s to state %s\n",
2144                  DBUS_AUTH_NAME (auth),
2145                  auth->state->name,
2146                  state->name);
2147
2148   auth->state = state;
2149 }
2150
2151 /* returns whether to call it again right away */
2152 static dbus_bool_t
2153 process_command (DBusAuth *auth)
2154 {
2155   DBusAuthCommand command;
2156   DBusString line;
2157   DBusString args;
2158   int eol;
2159   int i, j;
2160   dbus_bool_t retval;
2161
2162   /* _dbus_verbose ("%s:   trying process_command()\n"); */
2163   
2164   retval = FALSE;
2165   
2166   eol = 0;
2167   if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
2168     return FALSE;
2169   
2170   if (!_dbus_string_init (&line))
2171     {
2172       auth->needed_memory = TRUE;
2173       return FALSE;
2174     }
2175
2176   if (!_dbus_string_init (&args))
2177     {
2178       _dbus_string_free (&line);
2179       auth->needed_memory = TRUE;
2180       return FALSE;
2181     }
2182   
2183   if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
2184     goto out;
2185
2186   if (!_dbus_string_validate_ascii (&line, 0,
2187                                     _dbus_string_get_length (&line)))
2188     {
2189       _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
2190                      DBUS_AUTH_NAME (auth));
2191       if (!send_error (auth, "Command contained non-ASCII"))
2192         goto out;
2193       else
2194         goto next_command;
2195     }
2196   
2197   _dbus_verbose ("%s: got command \"%s\"\n",
2198                  DBUS_AUTH_NAME (auth),
2199                  _dbus_string_get_const_data (&line));
2200   
2201   _dbus_string_find_blank (&line, 0, &i);
2202   _dbus_string_skip_blank (&line, i, &j);
2203
2204   if (j > i)
2205     _dbus_string_delete (&line, i, j - i);
2206   
2207   if (!_dbus_string_move (&line, i, &args, 0))
2208     goto out;
2209
2210   /* FIXME 1.0 we should probably validate that only the allowed
2211    * chars are in the command name
2212    */
2213   
2214   command = lookup_command_from_name (&line);
2215   if (!(* auth->state->handler) (auth, command, &args))
2216     goto out;
2217
2218  next_command:
2219   
2220   /* We've succeeded in processing the whole command so drop it out
2221    * of the incoming buffer and return TRUE to try another command.
2222    */
2223
2224   _dbus_string_delete (&auth->incoming, 0, eol);
2225   
2226   /* kill the \r\n */
2227   _dbus_string_delete (&auth->incoming, 0, 2);
2228
2229   retval = TRUE;
2230   
2231  out:
2232   _dbus_string_free (&args);
2233   _dbus_string_free (&line);
2234
2235   if (!retval)
2236     auth->needed_memory = TRUE;
2237   else
2238     auth->needed_memory = FALSE;
2239   
2240   return retval;
2241 }
2242
2243
2244 /** @} */
2245
2246 /**
2247  * @addtogroup DBusAuth
2248  * @{
2249  */
2250
2251 /**
2252  * Creates a new auth conversation object for the server side.
2253  * See doc/dbus-sasl-profile.txt for full details on what
2254  * this object does.
2255  *
2256  * @returns the new object or #NULL if no memory
2257  */
2258 DBusAuth*
2259 _dbus_auth_server_new (const DBusString *guid)
2260 {
2261   DBusAuth *auth;
2262   DBusAuthServer *server_auth;
2263   DBusString guid_copy;
2264
2265   if (!_dbus_string_init (&guid_copy))
2266     return NULL;
2267
2268   if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
2269     {
2270       _dbus_string_free (&guid_copy);
2271       return NULL;
2272     }
2273
2274   auth = _dbus_auth_new (sizeof (DBusAuthServer));
2275   if (auth == NULL)
2276     {
2277       _dbus_string_free (&guid_copy);
2278       return NULL;
2279     }
2280   
2281   auth->side = auth_side_server;
2282   auth->state = &server_state_waiting_for_auth;
2283
2284   server_auth = DBUS_AUTH_SERVER (auth);
2285
2286   server_auth->guid = guid_copy;
2287   
2288   /* perhaps this should be per-mechanism with a lower
2289    * max
2290    */
2291   server_auth->failures = 0;
2292   server_auth->max_failures = 6;
2293   
2294   return auth;
2295 }
2296
2297 /**
2298  * Creates a new auth conversation object for the client side.
2299  * See doc/dbus-sasl-profile.txt for full details on what
2300  * this object does.
2301  *
2302  * @returns the new object or #NULL if no memory
2303  */
2304 DBusAuth*
2305 _dbus_auth_client_new (void)
2306 {
2307   DBusAuth *auth;
2308   DBusString guid_str;
2309
2310   if (!_dbus_string_init (&guid_str))
2311     return NULL;
2312
2313   auth = _dbus_auth_new (sizeof (DBusAuthClient));
2314   if (auth == NULL)
2315     {
2316       _dbus_string_free (&guid_str);
2317       return NULL;
2318     }
2319
2320   DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
2321
2322   auth->side = auth_side_client;
2323   auth->state = &client_state_need_send_auth;
2324
2325   /* Start the auth conversation by sending AUTH for our default
2326    * mechanism */
2327   if (!send_auth (auth, &all_mechanisms[0]))
2328     {
2329       _dbus_auth_unref (auth);
2330       return NULL;
2331     }
2332   
2333   return auth;
2334 }
2335
2336 /**
2337  * Increments the refcount of an auth object.
2338  *
2339  * @param auth the auth conversation
2340  * @returns the auth conversation
2341  */
2342 DBusAuth *
2343 _dbus_auth_ref (DBusAuth *auth)
2344 {
2345   _dbus_assert (auth != NULL);
2346   
2347   auth->refcount += 1;
2348   
2349   return auth;
2350 }
2351
2352 /**
2353  * Decrements the refcount of an auth object.
2354  *
2355  * @param auth the auth conversation
2356  */
2357 void
2358 _dbus_auth_unref (DBusAuth *auth)
2359 {
2360   _dbus_assert (auth != NULL);
2361   _dbus_assert (auth->refcount > 0);
2362
2363   auth->refcount -= 1;
2364   if (auth->refcount == 0)
2365     {
2366       shutdown_mech (auth);
2367
2368       if (DBUS_AUTH_IS_CLIENT (auth))
2369         {
2370           _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2371           _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
2372         }
2373       else
2374         {
2375           _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
2376
2377           _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
2378         }
2379
2380       if (auth->keyring)
2381         _dbus_keyring_unref (auth->keyring);
2382
2383       _dbus_string_free (&auth->context);
2384       _dbus_string_free (&auth->challenge);
2385       _dbus_string_free (&auth->identity);
2386       _dbus_string_free (&auth->incoming);
2387       _dbus_string_free (&auth->outgoing);
2388
2389       dbus_free_string_array (auth->allowed_mechs);
2390
2391       _dbus_credentials_unref (auth->credentials);
2392       _dbus_credentials_unref (auth->authorized_identity);
2393       _dbus_credentials_unref (auth->desired_identity);
2394       
2395       dbus_free (auth);
2396     }
2397 }
2398
2399 /**
2400  * Sets an array of authentication mechanism names
2401  * that we are willing to use.
2402  *
2403  * @param auth the auth conversation
2404  * @param mechanisms #NULL-terminated array of mechanism names
2405  * @returns #FALSE if no memory
2406  */
2407 dbus_bool_t
2408 _dbus_auth_set_mechanisms (DBusAuth    *auth,
2409                            const char **mechanisms)
2410 {
2411   char **copy;
2412
2413   if (mechanisms != NULL)
2414     {
2415       copy = _dbus_dup_string_array (mechanisms);
2416       if (copy == NULL)
2417         return FALSE;
2418     }
2419   else
2420     copy = NULL;
2421   
2422   dbus_free_string_array (auth->allowed_mechs);
2423
2424   auth->allowed_mechs = copy;
2425
2426   return TRUE;
2427 }
2428
2429 /**
2430  * @param auth the auth conversation object
2431  * @returns #TRUE if we're in a final state
2432  */
2433 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
2434
2435 /**
2436  * Analyzes buffered input and moves the auth conversation forward,
2437  * returning the new state of the auth conversation.
2438  *
2439  * @param auth the auth conversation
2440  * @returns the new state
2441  */
2442 DBusAuthState
2443 _dbus_auth_do_work (DBusAuth *auth)
2444 {
2445   auth->needed_memory = FALSE;
2446
2447   /* Max amount we'll buffer up before deciding someone's on crack */
2448 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
2449
2450   do
2451     {
2452       if (DBUS_AUTH_IN_END_STATE (auth))
2453         break;
2454       
2455       if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
2456           _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
2457         {
2458           goto_state (auth, &common_state_need_disconnect);
2459           _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
2460                          DBUS_AUTH_NAME (auth));
2461           break;
2462         }
2463     }
2464   while (process_command (auth));
2465
2466   if (auth->needed_memory)
2467     return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
2468   else if (_dbus_string_get_length (&auth->outgoing) > 0)
2469     return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
2470   else if (auth->state == &common_state_need_disconnect)
2471     return DBUS_AUTH_STATE_NEED_DISCONNECT;
2472   else if (auth->state == &common_state_authenticated)
2473     return DBUS_AUTH_STATE_AUTHENTICATED;
2474   else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
2475 }
2476
2477 /**
2478  * Gets bytes that need to be sent to the peer we're conversing with.
2479  * After writing some bytes, _dbus_auth_bytes_sent() must be called
2480  * to notify the auth object that they were written.
2481  *
2482  * @param auth the auth conversation
2483  * @param str return location for a ref to the buffer to send
2484  * @returns #FALSE if nothing to send
2485  */
2486 dbus_bool_t
2487 _dbus_auth_get_bytes_to_send (DBusAuth          *auth,
2488                               const DBusString **str)
2489 {
2490   _dbus_assert (auth != NULL);
2491   _dbus_assert (str != NULL);
2492
2493   *str = NULL;
2494   
2495   if (_dbus_string_get_length (&auth->outgoing) == 0)
2496     return FALSE;
2497
2498   *str = &auth->outgoing;
2499
2500   return TRUE;
2501 }
2502
2503 /**
2504  * Notifies the auth conversation object that
2505  * the given number of bytes of the outgoing buffer
2506  * have been written out.
2507  *
2508  * @param auth the auth conversation
2509  * @param bytes_sent number of bytes written out
2510  */
2511 void
2512 _dbus_auth_bytes_sent (DBusAuth *auth,
2513                        int       bytes_sent)
2514 {
2515   _dbus_verbose ("%s: Sent %d bytes of: %s\n",
2516                  DBUS_AUTH_NAME (auth),
2517                  bytes_sent,
2518                  _dbus_string_get_const_data (&auth->outgoing));
2519   
2520   _dbus_string_delete (&auth->outgoing,
2521                        0, bytes_sent);
2522 }
2523
2524 /**
2525  * Get a buffer to be used for reading bytes from the peer we're conversing
2526  * with. Bytes should be appended to this buffer.
2527  *
2528  * @param auth the auth conversation
2529  * @param buffer return location for buffer to append bytes to
2530  */
2531 void
2532 _dbus_auth_get_buffer (DBusAuth     *auth,
2533                        DBusString **buffer)
2534 {
2535   _dbus_assert (auth != NULL);
2536   _dbus_assert (!auth->buffer_outstanding);
2537   
2538   *buffer = &auth->incoming;
2539
2540   auth->buffer_outstanding = TRUE;
2541 }
2542
2543 /**
2544  * Returns a buffer with new data read into it.
2545  *
2546  * @param auth the auth conversation
2547  * @param buffer the buffer being returned
2548  * @param bytes_read number of new bytes added
2549  */
2550 void
2551 _dbus_auth_return_buffer (DBusAuth               *auth,
2552                           DBusString             *buffer,
2553                           int                     bytes_read)
2554 {
2555   _dbus_assert (buffer == &auth->incoming);
2556   _dbus_assert (auth->buffer_outstanding);
2557
2558   auth->buffer_outstanding = FALSE;
2559 }
2560
2561 /**
2562  * Returns leftover bytes that were not used as part of the auth
2563  * conversation.  These bytes will be part of the message stream
2564  * instead. This function may not be called until authentication has
2565  * succeeded.
2566  *
2567  * @param auth the auth conversation
2568  * @param str return location for pointer to string of unused bytes
2569  */
2570 void
2571 _dbus_auth_get_unused_bytes (DBusAuth           *auth,
2572                              const DBusString **str)
2573 {
2574   if (!DBUS_AUTH_IN_END_STATE (auth))
2575     return;
2576
2577   *str = &auth->incoming;
2578 }
2579
2580
2581 /**
2582  * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes()
2583  * after we've gotten them and successfully moved them elsewhere.
2584  *
2585  * @param auth the auth conversation
2586  */
2587 void
2588 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
2589 {
2590   if (!DBUS_AUTH_IN_END_STATE (auth))
2591     return;
2592
2593   _dbus_string_set_length (&auth->incoming, 0);
2594 }
2595
2596 /**
2597  * Called post-authentication, indicates whether we need to encode
2598  * the message stream with _dbus_auth_encode_data() prior to
2599  * sending it to the peer.
2600  *
2601  * @param auth the auth conversation
2602  * @returns #TRUE if we need to encode the stream
2603  */
2604 dbus_bool_t
2605 _dbus_auth_needs_encoding (DBusAuth *auth)
2606 {
2607   if (auth->state != &common_state_authenticated)
2608     return FALSE;
2609   
2610   if (auth->mech != NULL)
2611     {
2612       if (DBUS_AUTH_IS_CLIENT (auth))
2613         return auth->mech->client_encode_func != NULL;
2614       else
2615         return auth->mech->server_encode_func != NULL;
2616     }
2617   else
2618     return FALSE;
2619 }
2620
2621 /**
2622  * Called post-authentication, encodes a block of bytes for sending to
2623  * the peer. If no encoding was negotiated, just copies the bytes
2624  * (you can avoid this by checking _dbus_auth_needs_encoding()).
2625  *
2626  * @param auth the auth conversation
2627  * @param plaintext the plain text data
2628  * @param encoded initialized string to where encoded data is appended
2629  * @returns #TRUE if we had enough memory and successfully encoded
2630  */
2631 dbus_bool_t
2632 _dbus_auth_encode_data (DBusAuth         *auth,
2633                         const DBusString *plaintext,
2634                         DBusString       *encoded)
2635 {
2636   _dbus_assert (plaintext != encoded);
2637   
2638   if (auth->state != &common_state_authenticated)
2639     return FALSE;
2640   
2641   if (_dbus_auth_needs_encoding (auth))
2642     {
2643       if (DBUS_AUTH_IS_CLIENT (auth))
2644         return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
2645       else
2646         return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
2647     }
2648   else
2649     {
2650       return _dbus_string_copy (plaintext, 0, encoded,
2651                                 _dbus_string_get_length (encoded));
2652     }
2653 }
2654
2655 /**
2656  * Called post-authentication, indicates whether we need to decode
2657  * the message stream with _dbus_auth_decode_data() after
2658  * receiving it from the peer.
2659  *
2660  * @param auth the auth conversation
2661  * @returns #TRUE if we need to encode the stream
2662  */
2663 dbus_bool_t
2664 _dbus_auth_needs_decoding (DBusAuth *auth)
2665 {
2666   if (auth->state != &common_state_authenticated)
2667     return FALSE;
2668     
2669   if (auth->mech != NULL)
2670     {
2671       if (DBUS_AUTH_IS_CLIENT (auth))
2672         return auth->mech->client_decode_func != NULL;
2673       else
2674         return auth->mech->server_decode_func != NULL;
2675     }
2676   else
2677     return FALSE;
2678 }
2679
2680
2681 /**
2682  * Called post-authentication, decodes a block of bytes received from
2683  * the peer. If no encoding was negotiated, just copies the bytes (you
2684  * can avoid this by checking _dbus_auth_needs_decoding()).
2685  *
2686  * @todo 1.0? We need to be able to distinguish "out of memory" error
2687  * from "the data is hosed" error.
2688  *
2689  * @param auth the auth conversation
2690  * @param encoded the encoded data
2691  * @param plaintext initialized string where decoded data is appended
2692  * @returns #TRUE if we had enough memory and successfully decoded
2693  */
2694 dbus_bool_t
2695 _dbus_auth_decode_data (DBusAuth         *auth,
2696                         const DBusString *encoded,
2697                         DBusString       *plaintext)
2698 {
2699   _dbus_assert (plaintext != encoded);
2700   
2701   if (auth->state != &common_state_authenticated)
2702     return FALSE;
2703   
2704   if (_dbus_auth_needs_decoding (auth))
2705     {
2706       if (DBUS_AUTH_IS_CLIENT (auth))
2707         return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
2708       else
2709         return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
2710     }
2711   else
2712     {
2713       return _dbus_string_copy (encoded, 0, plaintext,
2714                                 _dbus_string_get_length (plaintext));
2715     }
2716 }
2717
2718 /**
2719  * Sets credentials received via reliable means from the operating
2720  * system.
2721  *
2722  * @param auth the auth conversation
2723  * @param credentials the credentials received
2724  * @returns #FALSE on OOM
2725  */
2726 dbus_bool_t
2727 _dbus_auth_set_credentials (DBusAuth               *auth,
2728                             DBusCredentials        *credentials)
2729 {
2730   _dbus_credentials_clear (auth->credentials);
2731   return _dbus_credentials_add_credentials (auth->credentials,
2732                                             credentials);
2733 }
2734
2735 /**
2736  * Gets the identity we authorized the client as.  Apps may have
2737  * different policies as to what identities they allow.
2738  *
2739  * Returned credentials are not a copy and should not be modified
2740  *
2741  * @param auth the auth conversation
2742  * @returns the credentials we've authorized BY REFERENCE do not modify
2743  */
2744 DBusCredentials*
2745 _dbus_auth_get_identity (DBusAuth               *auth)
2746 {
2747   if (auth->state == &common_state_authenticated)
2748     {
2749       return auth->authorized_identity;
2750     }
2751   else
2752     {
2753       /* FIXME instead of this, keep an empty credential around that
2754        * doesn't require allocation or something
2755        */
2756       /* return empty credentials */
2757       _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
2758       return auth->authorized_identity;
2759     }
2760 }
2761
2762 /**
2763  * Gets the GUID from the server if we've authenticated; gets
2764  * #NULL otherwise.
2765  * @param auth the auth object
2766  * @returns the GUID in ASCII hex format
2767  */
2768 const char*
2769 _dbus_auth_get_guid_from_server (DBusAuth *auth)
2770 {
2771   _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
2772   
2773   if (auth->state == &common_state_authenticated)
2774     return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2775   else
2776     return NULL;
2777 }
2778
2779 /**
2780  * Sets the "authentication context" which scopes cookies
2781  * with the DBUS_COOKIE_SHA1 auth mechanism for example.
2782  *
2783  * @param auth the auth conversation
2784  * @param context the context
2785  * @returns #FALSE if no memory
2786  */
2787 dbus_bool_t
2788 _dbus_auth_set_context (DBusAuth               *auth,
2789                         const DBusString       *context)
2790 {
2791   return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
2792                                    &auth->context, 0, _dbus_string_get_length (context));
2793 }
2794
2795 /**
2796  * Sets whether unix fd passing is potentially on the transport and
2797  * hence shall be negotiated.
2798  *
2799  * @param auth the auth conversation
2800  * @param b TRUE when unix fd passing shall be negotiated, otherwise FALSE
2801  */
2802 void
2803 _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b)
2804 {
2805   auth->unix_fd_possible = b;
2806 }
2807
2808 /**
2809  * Queries whether unix fd passing was sucessfully negotiated.
2810  *
2811  * @param auth the auth conversion
2812  * @returns #TRUE when unix fd passing was negotiated.
2813  */
2814 dbus_bool_t
2815 _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
2816 {
2817   return auth->unix_fd_negotiated;
2818 }
2819
2820 /** @} */
2821
2822 /* tests in dbus-auth-util.c */