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