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