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