D-Bus 1.15.8
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 (and PID FD) from the socket credentials if it's there
807 */
809 DBUS_CREDENTIAL_UNIX_PROCESS_FD,
810 auth->credentials))
811 goto out_3;
813 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
814 auth->credentials))
815 goto out_3;
816
817 if (!send_ok (auth))
818 goto out_3;
819
820 _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n",
821 DBUS_AUTH_NAME (auth));
822
823 retval = TRUE;
824
825 out_3:
826 _dbus_string_zero (&correct_hash);
827 _dbus_string_free (&correct_hash);
828 out_2:
829 _dbus_string_zero (&client_hash);
830 _dbus_string_free (&client_hash);
831 out_1:
832 _dbus_string_free (&client_challenge);
833 out_0:
834 return retval;
835}
836
837static dbus_bool_t
838handle_server_data_cookie_sha1_mech (DBusAuth *auth,
839 const DBusString *data)
840{
841 if (auth->cookie_id < 0)
842 return sha1_handle_first_client_response (auth, data);
843 else
844 return sha1_handle_second_client_response (auth, data);
845}
846
847static void
848handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
849{
850 auth->cookie_id = -1;
852}
853
854static dbus_bool_t
855handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
856 DBusString *response)
857{
858 DBusString username;
859 dbus_bool_t retval;
860
861 retval = FALSE;
862
863 if (!_dbus_string_init (&username))
864 return FALSE;
865
867 goto out_0;
868
869 if (!_dbus_string_hex_encode (&username, 0,
870 response,
871 _dbus_string_get_length (response)))
872 goto out_0;
873
874 retval = TRUE;
875
876 out_0:
877 _dbus_string_free (&username);
878
879 return retval;
880}
881
882static dbus_bool_t
883handle_client_data_cookie_sha1_mech (DBusAuth *auth,
884 const DBusString *data)
885{
886 /* The data we get from the server should be the cookie context
887 * name, the cookie ID, and the server challenge, separated by
888 * spaces. We send back our challenge string and the correct hash.
889 */
890 dbus_bool_t retval = FALSE;
891 DBusString context;
892 DBusString cookie_id_str;
893 DBusString server_challenge;
894 DBusString client_challenge;
895 DBusString correct_hash;
896 DBusString tmp;
897 int i, j;
898 long val;
900
901 if (!_dbus_string_find_blank (data, 0, &i))
902 {
903 if (send_error (auth,
904 "Server did not send context/ID/challenge properly"))
905 retval = TRUE;
906 goto out_0;
907 }
908
909 if (!_dbus_string_init (&context))
910 goto out_0;
911
912 if (!_dbus_string_copy_len (data, 0, i,
913 &context, 0))
914 goto out_1;
915
916 _dbus_string_skip_blank (data, i, &i);
917 if (!_dbus_string_find_blank (data, i, &j))
918 {
919 if (send_error (auth,
920 "Server did not send context/ID/challenge properly"))
921 retval = TRUE;
922 goto out_1;
923 }
924
925 if (!_dbus_string_init (&cookie_id_str))
926 goto out_1;
927
928 if (!_dbus_string_copy_len (data, i, j - i,
929 &cookie_id_str, 0))
930 goto out_2;
931
932 if (!_dbus_string_init (&server_challenge))
933 goto out_2;
934
935 i = j;
936 _dbus_string_skip_blank (data, i, &i);
937 j = _dbus_string_get_length (data);
938
939 if (!_dbus_string_copy_len (data, i, j - i,
940 &server_challenge, 0))
941 goto out_3;
942
943 if (!_dbus_keyring_validate_context (&context))
944 {
945 if (send_error (auth, "Server sent invalid cookie context"))
946 retval = TRUE;
947 goto out_3;
948 }
949
950 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
951 {
952 if (send_error (auth, "Could not parse cookie ID as an integer"))
953 retval = TRUE;
954 goto out_3;
955 }
956
957 if (_dbus_string_get_length (&server_challenge) == 0)
958 {
959 if (send_error (auth, "Empty server challenge string"))
960 retval = TRUE;
961 goto out_3;
962 }
963
964 if (auth->keyring == NULL)
965 {
967 &context,
968 &error);
969
970 if (auth->keyring == NULL)
971 {
972 if (dbus_error_has_name (&error,
974 {
975 dbus_error_free (&error);
976 goto out_3;
977 }
978 else
979 {
980 _DBUS_ASSERT_ERROR_IS_SET (&error);
981
982 _dbus_verbose ("%s: Error loading keyring: %s\n",
983 DBUS_AUTH_NAME (auth), error.message);
984
985 if (send_error (auth, "Could not load cookie file"))
986 retval = TRUE; /* retval is only about mem */
987
988 dbus_error_free (&error);
989 goto out_3;
990 }
991 }
992 else
993 {
995 }
996 }
997
998 _dbus_assert (auth->keyring != NULL);
999
1000 if (!_dbus_string_init (&tmp))
1001 goto out_3;
1002
1004 {
1006 {
1007 dbus_error_free (&error);
1008 goto out_4;
1009 }
1010 else
1011 {
1012 _DBUS_ASSERT_ERROR_IS_SET (&error);
1013
1014 _dbus_verbose ("%s: Failed to generate challenge: %s\n",
1015 DBUS_AUTH_NAME (auth), error.message);
1016
1017 if (send_error (auth, "Failed to generate challenge"))
1018 retval = TRUE; /* retval is only about mem */
1019
1020 dbus_error_free (&error);
1021 goto out_4;
1022 }
1023 }
1024
1025 if (!_dbus_string_init (&client_challenge))
1026 goto out_4;
1027
1028 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
1029 goto out_5;
1030
1031 if (!_dbus_string_init (&correct_hash))
1032 goto out_5;
1033
1034 if (!sha1_compute_hash (auth, val,
1035 &server_challenge,
1036 &client_challenge,
1037 &correct_hash))
1038 goto out_6;
1039
1040 if (_dbus_string_get_length (&correct_hash) == 0)
1041 {
1042 /* couldn't find the cookie ID or something */
1043 if (send_error (auth, "Don't have the requested cookie ID"))
1044 retval = TRUE;
1045 goto out_6;
1046 }
1047
1048 _dbus_string_set_length (&tmp, 0);
1049
1050 if (!_dbus_string_copy (&client_challenge, 0, &tmp,
1052 goto out_6;
1053
1054 if (!_dbus_string_append (&tmp, " "))
1055 goto out_6;
1056
1057 if (!_dbus_string_copy (&correct_hash, 0, &tmp,
1059 goto out_6;
1060
1061 if (!send_data (auth, &tmp))
1062 goto out_6;
1063
1064 retval = TRUE;
1065
1066 out_6:
1067 _dbus_string_zero (&correct_hash);
1068 _dbus_string_free (&correct_hash);
1069 out_5:
1070 _dbus_string_free (&client_challenge);
1071 out_4:
1072 _dbus_string_zero (&tmp);
1073 _dbus_string_free (&tmp);
1074 out_3:
1075 _dbus_string_free (&server_challenge);
1076 out_2:
1077 _dbus_string_free (&cookie_id_str);
1078 out_1:
1079 _dbus_string_free (&context);
1080 out_0:
1081 return retval;
1082}
1083
1084static void
1085handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
1086{
1087 auth->cookie_id = -1;
1089}
1090
1091/*
1092 * EXTERNAL mechanism
1093 */
1094
1095static dbus_bool_t
1096handle_server_data_external_mech (DBusAuth *auth,
1097 const DBusString *data)
1098{
1100 {
1101 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
1102 DBUS_AUTH_NAME (auth));
1103 return send_rejected (auth);
1104 }
1105
1106 if (_dbus_string_get_length (data) > 0)
1107 {
1108 if (_dbus_string_get_length (&auth->identity) > 0)
1109 {
1110 /* Tried to send two auth identities, wtf */
1111 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
1112 DBUS_AUTH_NAME (auth));
1113 return send_rejected (auth);
1114 }
1115 else
1116 {
1117 /* this is our auth identity */
1118 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
1119 return FALSE;
1120 }
1121 }
1122
1123 /* Poke client for an auth identity, if none given */
1124 if (_dbus_string_get_length (&auth->identity) == 0 &&
1126 {
1127 if (send_data (auth, NULL))
1128 {
1129 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
1130 DBUS_AUTH_NAME (auth));
1132 goto_state (auth, &server_state_waiting_for_data);
1133 return TRUE;
1134 }
1135 else
1136 return FALSE;
1137 }
1138
1140
1141 /* If auth->identity is still empty here, then client
1142 * responded with an empty string after we poked it for
1143 * an initial response. This means to try to auth the
1144 * identity provided in the credentials.
1145 */
1146 if (_dbus_string_get_length (&auth->identity) == 0)
1147 {
1149 auth->credentials))
1150 {
1151 return FALSE; /* OOM */
1152 }
1153 }
1154 else
1155 {
1156 DBusError error = DBUS_ERROR_INIT;
1157
1159 &auth->identity,
1160 DBUS_CREDENTIALS_ADD_FLAGS_NONE,
1161 &error))
1162 {
1164 {
1165 dbus_error_free (&error);
1166 return FALSE;
1167 }
1168
1169 _dbus_verbose ("%s: could not get credentials from uid string: %s\n",
1170 DBUS_AUTH_NAME (auth), error.message);
1171 dbus_error_free (&error);
1172 return send_rejected (auth);
1173 }
1174 }
1175
1177 {
1178 _dbus_verbose ("%s: desired user %s is no good\n",
1179 DBUS_AUTH_NAME (auth),
1181 return send_rejected (auth);
1182 }
1183
1185 auth->desired_identity))
1186 {
1187 /* client has authenticated */
1189 auth->desired_identity))
1190 return FALSE;
1191
1192 /* also copy misc process info from the socket credentials
1193 */
1195 DBUS_CREDENTIAL_UNIX_PROCESS_FD,
1196 auth->credentials))
1197 return FALSE;
1198
1200 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
1201 auth->credentials))
1202 return FALSE;
1203
1205 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
1206 auth->credentials))
1207 return FALSE;
1208
1210 DBUS_CREDENTIAL_UNIX_GROUP_IDS,
1211 auth->credentials))
1212 return FALSE;
1213
1215 DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
1216 auth->credentials))
1217 return FALSE;
1218
1219 if (!send_ok (auth))
1220 return FALSE;
1221
1222 _dbus_verbose ("%s: authenticated client based on socket credentials\n",
1223 DBUS_AUTH_NAME (auth));
1224
1225 return TRUE;
1226 }
1227 else
1228 {
1229 _dbus_verbose ("%s: desired identity not found in socket credentials\n",
1230 DBUS_AUTH_NAME (auth));
1231 return send_rejected (auth);
1232 }
1233}
1234
1235static void
1236handle_server_shutdown_external_mech (DBusAuth *auth)
1237{
1238
1239}
1240
1241static dbus_bool_t
1242handle_client_initial_response_external_mech (DBusAuth *auth,
1243 DBusString *response)
1244{
1245 /* We always append our UID as an initial response, so the server
1246 * doesn't have to send back an empty challenge to check whether we
1247 * want to specify an identity. i.e. this avoids a round trip that
1248 * the spec for the EXTERNAL mechanism otherwise requires.
1249 */
1250 DBusString plaintext;
1251
1252 if (!_dbus_string_init (&plaintext))
1253 return FALSE;
1254
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
1272static dbus_bool_t
1273handle_client_data_external_mech (DBusAuth *auth,
1274 const DBusString *data)
1275{
1276
1277 return TRUE;
1278}
1279
1280static void
1281handle_client_shutdown_external_mech (DBusAuth *auth)
1282{
1283
1284}
1285
1286/*
1287 * ANONYMOUS mechanism
1288 */
1289
1290static dbus_bool_t
1291handle_server_data_anonymous_mech (DBusAuth *auth,
1292 const DBusString *data)
1293{
1294 if (_dbus_string_get_length (data) > 0)
1295 {
1296 /* Client is allowed to send "trace" data, the only defined
1297 * meaning is that if it contains '@' it is an email address,
1298 * and otherwise it is anything else, and it's supposed to be
1299 * UTF-8
1300 */
1302 {
1303 _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
1304 DBUS_AUTH_NAME (auth));
1305 return send_rejected (auth);
1306 }
1307
1308 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
1309 DBUS_AUTH_NAME (auth),
1311 }
1312
1313 /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
1315
1316 /* Copy process ID (and PID FD) from the socket credentials
1317 */
1319 DBUS_CREDENTIAL_UNIX_PROCESS_FD,
1320 auth->credentials))
1321 return FALSE;
1322
1324 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
1325 auth->credentials))
1326 return FALSE;
1327
1328 /* Anonymous is always allowed */
1329 if (!send_ok (auth))
1330 return FALSE;
1331
1332 _dbus_verbose ("%s: authenticated client as anonymous\n",
1333 DBUS_AUTH_NAME (auth));
1334
1335 return TRUE;
1336}
1337
1338static void
1339handle_server_shutdown_anonymous_mech (DBusAuth *auth)
1340{
1341
1342}
1343
1344static dbus_bool_t
1345handle_client_initial_response_anonymous_mech (DBusAuth *auth,
1346 DBusString *response)
1347{
1348 /* Our initial response is a "trace" string which must be valid UTF-8
1349 * and must be an email address if it contains '@'.
1350 * We just send the dbus implementation info, like a user-agent or
1351 * something, because... why not. There's nothing guaranteed here
1352 * though, we could change it later.
1353 */
1354 DBusString plaintext;
1355
1356 if (!_dbus_string_init (&plaintext))
1357 return FALSE;
1358
1359 if (!_dbus_string_append (&plaintext,
1360 "libdbus " DBUS_VERSION_STRING))
1361 goto failed;
1362
1363 if (!_dbus_string_hex_encode (&plaintext, 0,
1364 response,
1365 _dbus_string_get_length (response)))
1366 goto failed;
1367
1368 _dbus_string_free (&plaintext);
1369
1370 return TRUE;
1371
1372 failed:
1373 _dbus_string_free (&plaintext);
1374 return FALSE;
1375}
1376
1377static dbus_bool_t
1378handle_client_data_anonymous_mech (DBusAuth *auth,
1379 const DBusString *data)
1380{
1381
1382 return TRUE;
1383}
1384
1385static void
1386handle_client_shutdown_anonymous_mech (DBusAuth *auth)
1387{
1388
1389}
1390
1391/* Put mechanisms here in order of preference.
1392 * Right now we have:
1393 *
1394 * - EXTERNAL checks socket credentials (or in the future, other info from the OS)
1395 * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE
1396 * - ANONYMOUS checks nothing but doesn't auth the person as a user
1397 *
1398 * We might ideally add a mechanism to chain to Cyrus SASL so we can
1399 * use its mechanisms as well.
1400 *
1401 */
1402static const DBusAuthMechanismHandler
1403all_mechanisms[] = {
1404 { "EXTERNAL",
1405 handle_server_data_external_mech,
1406 NULL, NULL,
1407 handle_server_shutdown_external_mech,
1408 handle_client_initial_response_external_mech,
1409 handle_client_data_external_mech,
1410 NULL, NULL,
1411 handle_client_shutdown_external_mech },
1412 { "DBUS_COOKIE_SHA1",
1413 handle_server_data_cookie_sha1_mech,
1414 NULL, NULL,
1415 handle_server_shutdown_cookie_sha1_mech,
1416 handle_client_initial_response_cookie_sha1_mech,
1417 handle_client_data_cookie_sha1_mech,
1418 NULL, NULL,
1419 handle_client_shutdown_cookie_sha1_mech },
1420 { "ANONYMOUS",
1421 handle_server_data_anonymous_mech,
1422 NULL, NULL,
1423 handle_server_shutdown_anonymous_mech,
1424 handle_client_initial_response_anonymous_mech,
1425 handle_client_data_anonymous_mech,
1426 NULL, NULL,
1427 handle_client_shutdown_anonymous_mech },
1428 { NULL, NULL }
1429};
1430
1431static const DBusAuthMechanismHandler*
1432find_mech (const DBusString *name,
1433 char **allowed_mechs)
1434{
1435 int i;
1436
1437 if (allowed_mechs != NULL &&
1438 !_dbus_string_array_contains ((const char**) allowed_mechs,
1440 return NULL;
1441
1442 i = 0;
1443 while (all_mechanisms[i].mechanism != NULL)
1444 {
1445 if (_dbus_string_equal_c_str (name,
1446 all_mechanisms[i].mechanism))
1447
1448 return &all_mechanisms[i];
1449
1450 ++i;
1451 }
1452
1453 return NULL;
1454}
1455
1456static dbus_bool_t
1457send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
1458{
1459 DBusString auth_command;
1460
1461 if (!_dbus_string_init (&auth_command))
1462 return FALSE;
1463
1464 if (!_dbus_string_append (&auth_command,
1465 "AUTH "))
1466 {
1467 _dbus_string_free (&auth_command);
1468 return FALSE;
1469 }
1470
1471 if (!_dbus_string_append (&auth_command,
1472 mech->mechanism))
1473 {
1474 _dbus_string_free (&auth_command);
1475 return FALSE;
1476 }
1477
1479 {
1480 if (!_dbus_string_append (&auth_command, " "))
1481 {
1482 _dbus_string_free (&auth_command);
1483 return FALSE;
1484 }
1485
1486 if (!(* mech->client_initial_response_func) (auth, &auth_command))
1487 {
1488 _dbus_string_free (&auth_command);
1489 return FALSE;
1490 }
1491 }
1492
1493 if (!_dbus_string_append (&auth_command,
1494 "\r\n"))
1495 {
1496 _dbus_string_free (&auth_command);
1497 return FALSE;
1498 }
1499
1500 if (!_dbus_string_copy (&auth_command, 0,
1501 &auth->outgoing,
1503 {
1504 _dbus_string_free (&auth_command);
1505 return FALSE;
1506 }
1507
1508 _dbus_string_free (&auth_command);
1509 shutdown_mech (auth);
1510 auth->mech = mech;
1511 goto_state (auth, &client_state_waiting_for_data);
1512
1513 return TRUE;
1514}
1515
1516static dbus_bool_t
1517send_data (DBusAuth *auth, DBusString *data)
1518{
1519 int old_len;
1520
1521 if (data == NULL || _dbus_string_get_length (data) == 0)
1522 return _dbus_string_append (&auth->outgoing, "DATA\r\n");
1523 else
1524 {
1525 old_len = _dbus_string_get_length (&auth->outgoing);
1526 if (!_dbus_string_append (&auth->outgoing, "DATA "))
1527 goto out;
1528
1529 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
1531 goto out;
1532
1533 if (!_dbus_string_append (&auth->outgoing, "\r\n"))
1534 goto out;
1535
1536 return TRUE;
1537
1538 out:
1539 _dbus_string_set_length (&auth->outgoing, old_len);
1540
1541 return FALSE;
1542 }
1543}
1544
1545static dbus_bool_t
1546send_rejected (DBusAuth *auth)
1547{
1548 DBusString command;
1549 DBusAuthServer *server_auth;
1550 int i;
1551
1552 if (!_dbus_string_init (&command))
1553 return FALSE;
1554
1555 if (!_dbus_string_append (&command,
1556 "REJECTED"))
1557 goto nomem;
1558
1559 for (i = 0; all_mechanisms[i].mechanism != NULL; i++)
1560 {
1561 /* skip mechanisms that aren't allowed */
1562 if (auth->allowed_mechs != NULL &&
1563 !_dbus_string_array_contains ((const char**)auth->allowed_mechs,
1564 all_mechanisms[i].mechanism))
1565 continue;
1566
1567 if (!_dbus_string_append (&command,
1568 " "))
1569 goto nomem;
1570
1571 if (!_dbus_string_append (&command,
1572 all_mechanisms[i].mechanism))
1573 goto nomem;
1574 }
1575
1576 if (!_dbus_string_append (&command, "\r\n"))
1577 goto nomem;
1578
1579 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
1581 goto nomem;
1582
1583 shutdown_mech (auth);
1584
1586 server_auth = DBUS_AUTH_SERVER (auth);
1587 server_auth->failures += 1;
1588
1589 if (server_auth->failures >= server_auth->max_failures)
1590 goto_state (auth, &common_state_need_disconnect);
1591 else
1592 goto_state (auth, &server_state_waiting_for_auth);
1593
1594 _dbus_string_free (&command);
1595
1596 return TRUE;
1597
1598 nomem:
1599 _dbus_string_free (&command);
1600 return FALSE;
1601}
1602
1603static dbus_bool_t
1604send_error (DBusAuth *auth, const char *message)
1605{
1606 return _dbus_string_append_printf (&auth->outgoing,
1607 "ERROR \"%s\"\r\n", message);
1608}
1609
1610static dbus_bool_t
1611send_ok (DBusAuth *auth)
1612{
1613 int orig_len;
1614
1615 orig_len = _dbus_string_get_length (&auth->outgoing);
1616
1617 if (_dbus_string_append (&auth->outgoing, "OK ") &&
1618 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
1619 0,
1620 &auth->outgoing,
1622 _dbus_string_append (&auth->outgoing, "\r\n"))
1623 {
1624 goto_state (auth, &server_state_waiting_for_begin);
1625 return TRUE;
1626 }
1627 else
1628 {
1629 _dbus_string_set_length (&auth->outgoing, orig_len);
1630 return FALSE;
1631 }
1632}
1633
1634static dbus_bool_t
1635send_begin (DBusAuth *auth)
1636{
1637
1638 if (!_dbus_string_append (&auth->outgoing,
1639 "BEGIN\r\n"))
1640 return FALSE;
1641
1642 goto_state (auth, &common_state_authenticated);
1643 return TRUE;
1644}
1645
1646static dbus_bool_t
1647process_ok(DBusAuth *auth,
1648 const DBusString *args_from_ok) {
1649
1650 int end_of_hex;
1651
1652 /* "args_from_ok" should be the GUID, whitespace already pulled off the front */
1653 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
1654
1655 /* We decode the hex string to binary, using guid_from_server as scratch... */
1656
1657 end_of_hex = 0;
1658 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
1659 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
1660 return FALSE;
1661
1662 /* now clear out the scratch */
1663 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1664
1665 if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
1666 end_of_hex == 0)
1667 {
1668 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
1669 end_of_hex, _dbus_string_get_length (args_from_ok));
1670 goto_state (auth, &common_state_need_disconnect);
1671 return TRUE;
1672 }
1673
1674 if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) {
1675 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1676 return FALSE;
1677 }
1678
1679 _dbus_verbose ("Got GUID '%s' from the server\n",
1680 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
1681
1682 if (auth->unix_fd_possible)
1683 {
1684 if (!send_negotiate_unix_fd (auth))
1685 {
1686 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1687 return FALSE;
1688 }
1689
1690 return TRUE;
1691 }
1692
1693 _dbus_verbose("Not negotiating unix fd passing, since not possible\n");
1694
1695 if (!send_begin (auth))
1696 {
1697 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
1698 return FALSE;
1699 }
1700
1701 return TRUE;
1702}
1703
1704static dbus_bool_t
1705send_cancel (DBusAuth *auth)
1706{
1707 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
1708 {
1709 goto_state (auth, &client_state_waiting_for_reject);
1710 return TRUE;
1711 }
1712 else
1713 return FALSE;
1714}
1715
1716static dbus_bool_t
1717process_data (DBusAuth *auth,
1718 const DBusString *args,
1719 DBusAuthDataFunction data_func)
1720{
1721 int end;
1722 DBusString decoded;
1723
1724 if (!_dbus_string_init (&decoded))
1725 return FALSE;
1726
1727 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
1728 {
1729 _dbus_string_free (&decoded);
1730 return FALSE;
1731 }
1732
1733 if (_dbus_string_get_length (args) != end)
1734 {
1735 _dbus_string_free (&decoded);
1736 if (!send_error (auth, "Invalid hex encoding"))
1737 return FALSE;
1738
1739 return TRUE;
1740 }
1741
1742#ifdef DBUS_ENABLE_VERBOSE_MODE
1743 if (_dbus_string_validate_ascii (&decoded, 0,
1744 _dbus_string_get_length (&decoded)))
1745 _dbus_verbose ("%s: data: '%s'\n",
1746 DBUS_AUTH_NAME (auth),
1747 _dbus_string_get_const_data (&decoded));
1748#endif
1749
1750 if (!(* data_func) (auth, &decoded))
1751 {
1752 _dbus_string_free (&decoded);
1753 return FALSE;
1754 }
1755
1756 _dbus_string_free (&decoded);
1757 return TRUE;
1758}
1759
1760static dbus_bool_t
1761send_negotiate_unix_fd (DBusAuth *auth)
1762{
1763 if (!_dbus_string_append (&auth->outgoing,
1764 "NEGOTIATE_UNIX_FD\r\n"))
1765 return FALSE;
1766
1767 goto_state (auth, &client_state_waiting_for_agree_unix_fd);
1768 return TRUE;
1769}
1770
1771static dbus_bool_t
1772send_agree_unix_fd (DBusAuth *auth)
1773{
1775
1776 auth->unix_fd_negotiated = TRUE;
1777 _dbus_verbose("Agreed to UNIX FD passing\n");
1778
1779 if (!_dbus_string_append (&auth->outgoing,
1780 "AGREE_UNIX_FD\r\n"))
1781 return FALSE;
1782
1783 goto_state (auth, &server_state_waiting_for_begin);
1784 return TRUE;
1785}
1786
1787static dbus_bool_t
1788handle_auth (DBusAuth *auth, const DBusString *args)
1789{
1790 if (_dbus_string_get_length (args) == 0)
1791 {
1792 /* No args to the auth, send mechanisms */
1793 if (!send_rejected (auth))
1794 return FALSE;
1795
1796 return TRUE;
1797 }
1798 else
1799 {
1800 int i;
1801 DBusString mech;
1802 DBusString hex_response;
1803
1804 _dbus_string_find_blank (args, 0, &i);
1805
1806 if (!_dbus_string_init (&mech))
1807 return FALSE;
1808
1809 if (!_dbus_string_init (&hex_response))
1810 {
1811 _dbus_string_free (&mech);
1812 return FALSE;
1813 }
1814
1815 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
1816 goto failed;
1817
1818 _dbus_string_skip_blank (args, i, &i);
1819 if (!_dbus_string_copy (args, i, &hex_response, 0))
1820 goto failed;
1821
1822 auth->mech = find_mech (&mech, auth->allowed_mechs);
1823 if (auth->mech != NULL)
1824 {
1825 _dbus_verbose ("%s: Trying mechanism %s\n",
1826 DBUS_AUTH_NAME (auth),
1827 auth->mech->mechanism);
1828
1829 if (!process_data (auth, &hex_response,
1830 auth->mech->server_data_func))
1831 goto failed;
1832 }
1833 else
1834 {
1835 /* Unsupported mechanism */
1836 _dbus_verbose ("%s: Unsupported mechanism %s\n",
1837 DBUS_AUTH_NAME (auth),
1839
1840 if (!send_rejected (auth))
1841 goto failed;
1842 }
1843
1844 _dbus_string_free (&mech);
1845 _dbus_string_free (&hex_response);
1846
1847 return TRUE;
1848
1849 failed:
1850 auth->mech = NULL;
1851 _dbus_string_free (&mech);
1852 _dbus_string_free (&hex_response);
1853 return FALSE;
1854 }
1855}
1856
1857static dbus_bool_t
1858handle_server_state_waiting_for_auth (DBusAuth *auth,
1859 DBusAuthCommand command,
1860 const DBusString *args)
1861{
1862 switch (command)
1863 {
1864 case DBUS_AUTH_COMMAND_AUTH:
1865 return handle_auth (auth, args);
1866
1867 case DBUS_AUTH_COMMAND_CANCEL:
1868 case DBUS_AUTH_COMMAND_DATA:
1869 return send_error (auth, "Not currently in an auth conversation");
1870
1871 case DBUS_AUTH_COMMAND_BEGIN:
1872 goto_state (auth, &common_state_need_disconnect);
1873 return TRUE;
1874
1875 case DBUS_AUTH_COMMAND_ERROR:
1876 return send_rejected (auth);
1877
1878 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1879 return send_error (auth, "Need to authenticate first");
1880
1881 case DBUS_AUTH_COMMAND_REJECTED:
1882 case DBUS_AUTH_COMMAND_OK:
1883 case DBUS_AUTH_COMMAND_UNKNOWN:
1884 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1885 default:
1886 return send_error (auth, "Unknown command");
1887 }
1888}
1889
1890static dbus_bool_t
1891handle_server_state_waiting_for_data (DBusAuth *auth,
1892 DBusAuthCommand command,
1893 const DBusString *args)
1894{
1895 switch (command)
1896 {
1897 case DBUS_AUTH_COMMAND_AUTH:
1898 return send_error (auth, "Sent AUTH while another AUTH in progress");
1899
1900 case DBUS_AUTH_COMMAND_CANCEL:
1901 case DBUS_AUTH_COMMAND_ERROR:
1902 return send_rejected (auth);
1903
1904 case DBUS_AUTH_COMMAND_DATA:
1905 return process_data (auth, args, auth->mech->server_data_func);
1906
1907 case DBUS_AUTH_COMMAND_BEGIN:
1908 goto_state (auth, &common_state_need_disconnect);
1909 return TRUE;
1910
1911 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1912 return send_error (auth, "Need to authenticate first");
1913
1914 case DBUS_AUTH_COMMAND_REJECTED:
1915 case DBUS_AUTH_COMMAND_OK:
1916 case DBUS_AUTH_COMMAND_UNKNOWN:
1917 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1918 default:
1919 return send_error (auth, "Unknown command");
1920 }
1921}
1922
1923static dbus_bool_t
1924handle_server_state_waiting_for_begin (DBusAuth *auth,
1925 DBusAuthCommand command,
1926 const DBusString *args)
1927{
1928 switch (command)
1929 {
1930 case DBUS_AUTH_COMMAND_AUTH:
1931 return send_error (auth, "Sent AUTH while expecting BEGIN");
1932
1933 case DBUS_AUTH_COMMAND_DATA:
1934 return send_error (auth, "Sent DATA while expecting BEGIN");
1935
1936 case DBUS_AUTH_COMMAND_BEGIN:
1937 goto_state (auth, &common_state_authenticated);
1938 return TRUE;
1939
1940 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
1941 if (auth->unix_fd_possible)
1942 return send_agree_unix_fd(auth);
1943 else
1944 return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible");
1945
1946 case DBUS_AUTH_COMMAND_REJECTED:
1947 case DBUS_AUTH_COMMAND_OK:
1948 case DBUS_AUTH_COMMAND_UNKNOWN:
1949 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
1950 default:
1951 return send_error (auth, "Unknown command");
1952
1953 case DBUS_AUTH_COMMAND_CANCEL:
1954 case DBUS_AUTH_COMMAND_ERROR:
1955 return send_rejected (auth);
1956 }
1957}
1958
1959/* return FALSE if no memory, TRUE if all OK */
1960static dbus_bool_t
1961get_word (const DBusString *str,
1962 int *start,
1963 DBusString *word)
1964{
1965 int i;
1966
1967 _dbus_string_skip_blank (str, *start, start);
1968 _dbus_string_find_blank (str, *start, &i);
1969
1970 if (i > *start)
1971 {
1972 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
1973 return FALSE;
1974
1975 *start = i;
1976 }
1977
1978 return TRUE;
1979}
1980
1981static dbus_bool_t
1982record_mechanisms (DBusAuth *auth,
1983 const DBusString *args)
1984{
1985 int next;
1986 int len;
1987
1988 if (auth->already_got_mechanisms)
1989 return TRUE;
1990
1991 len = _dbus_string_get_length (args);
1992
1993 next = 0;
1994 while (next < len)
1995 {
1996 DBusString m;
1997 const DBusAuthMechanismHandler *mech;
1998
1999 if (!_dbus_string_init (&m))
2000 goto nomem;
2001
2002 if (!get_word (args, &next, &m))
2003 {
2004 _dbus_string_free (&m);
2005 goto nomem;
2006 }
2007
2008 mech = find_mech (&m, auth->allowed_mechs);
2009
2010 if (mech != NULL)
2011 {
2012 /* FIXME right now we try mechanisms in the order
2013 * the server lists them; should we do them in
2014 * some more deterministic order?
2015 *
2016 * Probably in all_mechanisms order, our order of
2017 * preference. Of course when the server is us,
2018 * it lists things in that order anyhow.
2019 */
2020
2021 if (mech != &all_mechanisms[0])
2022 {
2023 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
2024 DBUS_AUTH_NAME (auth), mech->mechanism);
2025
2026 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
2027 (void*) mech))
2028 {
2029 _dbus_string_free (&m);
2030 goto nomem;
2031 }
2032 }
2033 else
2034 {
2035 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
2036 DBUS_AUTH_NAME (auth), mech->mechanism);
2037 }
2038 }
2039 else
2040 {
2041 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
2042 DBUS_AUTH_NAME (auth),
2044 }
2045
2046 _dbus_string_free (&m);
2047 }
2048
2050
2051 return TRUE;
2052
2053 nomem:
2054 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
2055
2056 return FALSE;
2057}
2058
2059static dbus_bool_t
2060process_rejected (DBusAuth *auth, const DBusString *args)
2061{
2062 const DBusAuthMechanismHandler *mech;
2063 DBusAuthClient *client;
2064
2065 client = DBUS_AUTH_CLIENT (auth);
2066
2067 if (!auth->already_got_mechanisms)
2068 {
2069 if (!record_mechanisms (auth, args))
2070 return FALSE;
2071 }
2072
2073 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
2074 {
2075 mech = client->mechs_to_try->data;
2076
2077 if (!send_auth (auth, mech))
2078 return FALSE;
2079
2081
2082 _dbus_verbose ("%s: Trying mechanism %s\n",
2083 DBUS_AUTH_NAME (auth),
2084 mech->mechanism);
2085 }
2086 else
2087 {
2088 /* Give up */
2089 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
2090 DBUS_AUTH_NAME (auth));
2091 goto_state (auth, &common_state_need_disconnect);
2092 }
2093
2094 return TRUE;
2095}
2096
2097
2098static dbus_bool_t
2099handle_client_state_waiting_for_data (DBusAuth *auth,
2100 DBusAuthCommand command,
2101 const DBusString *args)
2102{
2103 _dbus_assert (auth->mech != NULL);
2104
2105 switch (command)
2106 {
2107 case DBUS_AUTH_COMMAND_DATA:
2108 return process_data (auth, args, auth->mech->client_data_func);
2109
2110 case DBUS_AUTH_COMMAND_REJECTED:
2111 return process_rejected (auth, args);
2112
2113 case DBUS_AUTH_COMMAND_OK:
2114 return process_ok(auth, args);
2115
2116 case DBUS_AUTH_COMMAND_ERROR:
2117 return send_cancel (auth);
2118
2119 case DBUS_AUTH_COMMAND_AUTH:
2120 case DBUS_AUTH_COMMAND_CANCEL:
2121 case DBUS_AUTH_COMMAND_BEGIN:
2122 case DBUS_AUTH_COMMAND_UNKNOWN:
2123 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2124 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2125 default:
2126 return send_error (auth, "Unknown command");
2127 }
2128}
2129
2130static dbus_bool_t
2131handle_client_state_waiting_for_ok (DBusAuth *auth,
2132 DBusAuthCommand command,
2133 const DBusString *args)
2134{
2135 switch (command)
2136 {
2137 case DBUS_AUTH_COMMAND_REJECTED:
2138 return process_rejected (auth, args);
2139
2140 case DBUS_AUTH_COMMAND_OK:
2141 return process_ok(auth, args);
2142
2143 case DBUS_AUTH_COMMAND_DATA:
2144 case DBUS_AUTH_COMMAND_ERROR:
2145 return send_cancel (auth);
2146
2147 case DBUS_AUTH_COMMAND_AUTH:
2148 case DBUS_AUTH_COMMAND_CANCEL:
2149 case DBUS_AUTH_COMMAND_BEGIN:
2150 case DBUS_AUTH_COMMAND_UNKNOWN:
2151 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2152 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2153 default:
2154 return send_error (auth, "Unknown command");
2155 }
2156}
2157
2158static dbus_bool_t
2159handle_client_state_waiting_for_reject (DBusAuth *auth,
2160 DBusAuthCommand command,
2161 const DBusString *args)
2162{
2163 switch (command)
2164 {
2165 case DBUS_AUTH_COMMAND_REJECTED:
2166 return process_rejected (auth, args);
2167
2168 case DBUS_AUTH_COMMAND_AUTH:
2169 case DBUS_AUTH_COMMAND_CANCEL:
2170 case DBUS_AUTH_COMMAND_DATA:
2171 case DBUS_AUTH_COMMAND_BEGIN:
2172 case DBUS_AUTH_COMMAND_OK:
2173 case DBUS_AUTH_COMMAND_ERROR:
2174 case DBUS_AUTH_COMMAND_UNKNOWN:
2175 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2176 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2177 default:
2178 goto_state (auth, &common_state_need_disconnect);
2179 return TRUE;
2180 }
2181}
2182
2183static dbus_bool_t
2184handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth,
2185 DBusAuthCommand command,
2186 const DBusString *args)
2187{
2188 switch (command)
2189 {
2190 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
2192 auth->unix_fd_negotiated = TRUE;
2193 _dbus_verbose("Successfully negotiated UNIX FD passing\n");
2194 return send_begin (auth);
2195
2196 case DBUS_AUTH_COMMAND_ERROR:
2198 auth->unix_fd_negotiated = FALSE;
2199 _dbus_verbose("Failed to negotiate UNIX FD passing\n");
2200 return send_begin (auth);
2201
2202 case DBUS_AUTH_COMMAND_OK:
2203 case DBUS_AUTH_COMMAND_DATA:
2204 case DBUS_AUTH_COMMAND_REJECTED:
2205 case DBUS_AUTH_COMMAND_AUTH:
2206 case DBUS_AUTH_COMMAND_CANCEL:
2207 case DBUS_AUTH_COMMAND_BEGIN:
2208 case DBUS_AUTH_COMMAND_UNKNOWN:
2209 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD:
2210 default:
2211 return send_error (auth, "Unknown command");
2212 }
2213}
2214
2218typedef struct {
2219 const char *name;
2222
2223static const DBusAuthCommandName auth_command_names[] = {
2224 { "AUTH", DBUS_AUTH_COMMAND_AUTH },
2225 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
2226 { "DATA", DBUS_AUTH_COMMAND_DATA },
2227 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
2228 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
2229 { "OK", DBUS_AUTH_COMMAND_OK },
2230 { "ERROR", DBUS_AUTH_COMMAND_ERROR },
2231 { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD },
2232 { "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD }
2233};
2234
2235static DBusAuthCommand
2236lookup_command_from_name (DBusString *command)
2237{
2238 int i;
2239
2240 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
2241 {
2242 if (_dbus_string_equal_c_str (command,
2243 auth_command_names[i].name))
2244 return auth_command_names[i].command;
2245 }
2246
2247 return DBUS_AUTH_COMMAND_UNKNOWN;
2248}
2249
2250static void
2251goto_state (DBusAuth *auth,
2252 const DBusAuthStateData *state)
2253{
2254 _dbus_verbose ("%s: going from state %s to state %s\n",
2255 DBUS_AUTH_NAME (auth),
2256 auth->state->name,
2257 state->name);
2258
2259 auth->state = state;
2260}
2261
2262/* returns whether to call it again right away */
2263static dbus_bool_t
2264process_command (DBusAuth *auth)
2265{
2266 DBusAuthCommand command;
2267 DBusString line;
2268 DBusString args;
2269 int eol;
2270 int i, j;
2271 dbus_bool_t retval;
2272
2273 /* _dbus_verbose ("%s: trying process_command()\n"); */
2274
2275 retval = FALSE;
2276
2277 eol = 0;
2278 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
2279 return FALSE;
2280
2281 if (!_dbus_string_init (&line))
2282 {
2283 auth->needed_memory = TRUE;
2284 return FALSE;
2285 }
2286
2287 if (!_dbus_string_init (&args))
2288 {
2289 _dbus_string_free (&line);
2290 auth->needed_memory = TRUE;
2291 return FALSE;
2292 }
2293
2294 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
2295 goto out;
2296
2297 if (!_dbus_string_validate_ascii (&line, 0,
2298 _dbus_string_get_length (&line)))
2299 {
2300 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
2301 DBUS_AUTH_NAME (auth));
2302 if (!send_error (auth, "Command contained non-ASCII"))
2303 goto out;
2304 else
2305 goto next_command;
2306 }
2307
2308 _dbus_verbose ("%s: got command \"%s\"\n",
2309 DBUS_AUTH_NAME (auth),
2311
2312 _dbus_string_find_blank (&line, 0, &i);
2313 _dbus_string_skip_blank (&line, i, &j);
2314
2315 if (j > i)
2316 _dbus_string_delete (&line, i, j - i);
2317
2318 if (!_dbus_string_move (&line, i, &args, 0))
2319 goto out;
2320
2321 /* FIXME 1.0 we should probably validate that only the allowed
2322 * chars are in the command name
2323 */
2324
2325 command = lookup_command_from_name (&line);
2326 if (!(* auth->state->handler) (auth, command, &args))
2327 goto out;
2328
2329 next_command:
2330
2331 /* We've succeeded in processing the whole command so drop it out
2332 * of the incoming buffer and return TRUE to try another command.
2333 */
2334
2335 _dbus_string_delete (&auth->incoming, 0, eol);
2336
2337 /* kill the \r\n */
2338 _dbus_string_delete (&auth->incoming, 0, 2);
2339
2340 retval = TRUE;
2341
2342 out:
2343 _dbus_string_free (&args);
2344 _dbus_string_free (&line);
2345
2346 if (!retval)
2347 auth->needed_memory = TRUE;
2348 else
2349 auth->needed_memory = FALSE;
2350
2351 return retval;
2352}
2353
2354
2369DBusAuth*
2371{
2372 DBusAuth *auth;
2373 DBusAuthServer *server_auth;
2374 DBusString guid_copy;
2375
2376 if (!_dbus_string_init (&guid_copy))
2377 return NULL;
2378
2379 if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
2380 {
2381 _dbus_string_free (&guid_copy);
2382 return NULL;
2383 }
2384
2385 auth = _dbus_auth_new (sizeof (DBusAuthServer));
2386 if (auth == NULL)
2387 {
2388 _dbus_string_free (&guid_copy);
2389 return NULL;
2390 }
2391
2392 auth->side = auth_side_server;
2393 auth->state = &server_state_waiting_for_auth;
2394
2395 server_auth = DBUS_AUTH_SERVER (auth);
2396
2397 server_auth->guid = guid_copy;
2398
2399 /* perhaps this should be per-mechanism with a lower
2400 * max
2401 */
2402 server_auth->failures = 0;
2403 server_auth->max_failures = 6;
2404
2405 return auth;
2406}
2407
2415DBusAuth*
2417{
2418 DBusAuth *auth;
2419 DBusString guid_str;
2420
2421 if (!_dbus_string_init (&guid_str))
2422 return NULL;
2423
2424 auth = _dbus_auth_new (sizeof (DBusAuthClient));
2425 if (auth == NULL)
2426 {
2427 _dbus_string_free (&guid_str);
2428 return NULL;
2429 }
2430
2431 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
2432
2433 auth->side = auth_side_client;
2434 auth->state = &client_state_need_send_auth;
2435
2436 /* Start the auth conversation by sending AUTH for our default
2437 * mechanism */
2438 if (!send_auth (auth, &all_mechanisms[0]))
2439 {
2440 _dbus_auth_unref (auth);
2441 return NULL;
2442 }
2443
2444 return auth;
2445}
2446
2453DBusAuth *
2455{
2456 _dbus_assert (auth != NULL);
2457
2458 auth->refcount += 1;
2459
2460 return auth;
2461}
2462
2468void
2470{
2471 _dbus_assert (auth != NULL);
2472 _dbus_assert (auth->refcount > 0);
2473
2474 auth->refcount -= 1;
2475 if (auth->refcount == 0)
2476 {
2477 shutdown_mech (auth);
2478
2479 if (DBUS_AUTH_IS_CLIENT (auth))
2480 {
2481 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2482 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
2483 }
2484 else
2485 {
2487
2488 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
2489 }
2490
2491 if (auth->keyring)
2493
2494 _dbus_string_free (&auth->context);
2496 _dbus_string_free (&auth->identity);
2497 _dbus_string_free (&auth->incoming);
2498 _dbus_string_free (&auth->outgoing);
2499
2501
2505
2506 dbus_free (auth);
2507 }
2508}
2509
2520 const char **mechanisms)
2521{
2522 char **copy;
2523
2524 if (mechanisms != NULL)
2525 {
2526 copy = _dbus_dup_string_array (mechanisms);
2527 if (copy == NULL)
2528 return FALSE;
2529 }
2530 else
2531 copy = NULL;
2532
2534
2535 auth->allowed_mechs = copy;
2536
2537 return TRUE;
2538}
2539
2544#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
2545
2553DBusAuthState
2555{
2556 auth->needed_memory = FALSE;
2557
2558 /* Max amount we'll buffer up before deciding someone's on crack */
2559#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
2560
2561 do
2562 {
2563 if (DBUS_AUTH_IN_END_STATE (auth))
2564 break;
2565
2566 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
2567 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
2568 {
2569 goto_state (auth, &common_state_need_disconnect);
2570 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
2571 DBUS_AUTH_NAME (auth));
2572 break;
2573 }
2574 }
2575 while (process_command (auth));
2576
2577 if (auth->needed_memory)
2578 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
2579 else if (_dbus_string_get_length (&auth->outgoing) > 0)
2580 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
2581 else if (auth->state == &common_state_need_disconnect)
2582 return DBUS_AUTH_STATE_NEED_DISCONNECT;
2583 else if (auth->state == &common_state_authenticated)
2584 return DBUS_AUTH_STATE_AUTHENTICATED;
2585 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
2586}
2587
2599 const DBusString **str)
2600{
2601 _dbus_assert (auth != NULL);
2602 _dbus_assert (str != NULL);
2603
2604 *str = NULL;
2605
2606 if (_dbus_string_get_length (&auth->outgoing) == 0)
2607 return FALSE;
2608
2609 *str = &auth->outgoing;
2610
2611 return TRUE;
2612}
2613
2622void
2624 int bytes_sent)
2625{
2626 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
2627 DBUS_AUTH_NAME (auth),
2628 bytes_sent,
2630
2632 0, bytes_sent);
2633}
2634
2642void
2644 DBusString **buffer)
2645{
2646 _dbus_assert (auth != NULL);
2648
2649 *buffer = &auth->incoming;
2650
2651 auth->buffer_outstanding = TRUE;
2652}
2653
2660void
2662 DBusString *buffer)
2663{
2664 _dbus_assert (buffer == &auth->incoming);
2666
2667 auth->buffer_outstanding = FALSE;
2668}
2669
2679void
2681 const DBusString **str)
2682{
2683 if (!DBUS_AUTH_IN_END_STATE (auth))
2684 return;
2685
2686 *str = &auth->incoming;
2687}
2688
2689
2696void
2698{
2699 if (!DBUS_AUTH_IN_END_STATE (auth))
2700 return;
2701
2703}
2704
2715{
2716 if (auth->state != &common_state_authenticated)
2717 return FALSE;
2718
2719 if (auth->mech != NULL)
2720 {
2721 if (DBUS_AUTH_IS_CLIENT (auth))
2722 return auth->mech->client_encode_func != NULL;
2723 else
2724 return auth->mech->server_encode_func != NULL;
2725 }
2726 else
2727 return FALSE;
2728}
2729
2742 const DBusString *plaintext,
2743 DBusString *encoded)
2744{
2745 _dbus_assert (plaintext != encoded);
2746
2747 if (auth->state != &common_state_authenticated)
2748 return FALSE;
2749
2750 if (_dbus_auth_needs_encoding (auth))
2751 {
2752 if (DBUS_AUTH_IS_CLIENT (auth))
2753 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
2754 else
2755 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
2756 }
2757 else
2758 {
2759 return _dbus_string_copy (plaintext, 0, encoded,
2760 _dbus_string_get_length (encoded));
2761 }
2762}
2763
2774{
2775 if (auth->state != &common_state_authenticated)
2776 return FALSE;
2777
2778 if (auth->mech != NULL)
2779 {
2780 if (DBUS_AUTH_IS_CLIENT (auth))
2781 return auth->mech->client_decode_func != NULL;
2782 else
2783 return auth->mech->server_decode_func != NULL;
2784 }
2785 else
2786 return FALSE;
2787}
2788
2789
2805 const DBusString *encoded,
2806 DBusString *plaintext)
2807{
2808 _dbus_assert (plaintext != encoded);
2809
2810 if (auth->state != &common_state_authenticated)
2811 return FALSE;
2812
2813 if (_dbus_auth_needs_decoding (auth))
2814 {
2815 if (DBUS_AUTH_IS_CLIENT (auth))
2816 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
2817 else
2818 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
2819 }
2820 else
2821 {
2822 return _dbus_string_copy (encoded, 0, plaintext,
2823 _dbus_string_get_length (plaintext));
2824 }
2825}
2826
2837 DBusCredentials *credentials)
2838{
2841 credentials);
2842}
2843
2855{
2856 if (auth->state == &common_state_authenticated)
2857 {
2858 return auth->authorized_identity;
2859 }
2860 else
2861 {
2862 /* FIXME instead of this, keep an empty credential around that
2863 * doesn't require allocation or something
2864 */
2865 /* return empty credentials */
2867 return auth->authorized_identity;
2868 }
2869}
2870
2877const char*
2879{
2881
2882 if (auth->state == &common_state_authenticated)
2883 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
2884 else
2885 return NULL;
2886}
2887
2898 const DBusString *context)
2899{
2900 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
2901 &auth->context, 0, _dbus_string_get_length (context));
2902}
2903
2911void
2913{
2914 auth->unix_fd_possible = b;
2915}
2916
2925{
2926 return auth->unix_fd_negotiated;
2927}
2928
2937{
2938 _dbus_assert (name != NULL);
2939
2940 return find_mech (name, NULL) != NULL;
2941}
2942
2951{
2952 unsigned int i;
2953 _dbus_assert (buffer != NULL);
2954
2955 for (i = 0; all_mechanisms[i].mechanism != NULL; i++)
2956 {
2957 if (i > 0)
2958 {
2959 if (!_dbus_string_append (buffer, ", "))
2960 return FALSE;
2961 }
2962 if (!_dbus_string_append (buffer, all_mechanisms[i].mechanism))
2963 return FALSE;
2964 }
2965 return TRUE;
2966}
2967
2970/* 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:2554
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:2741
dbus_bool_t _dbus_auth_dump_supported_mechanisms(DBusString *buffer)
Return a human-readable string containing all supported auth mechanisms.
Definition: dbus-auth.c:2950
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:2714
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:2836
dbus_bool_t _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth)
Queries whether unix fd passing was successfully negotiated.
Definition: dbus-auth.c:2924
DBusAuth * _dbus_auth_ref(DBusAuth *auth)
Increments the refcount of an auth object.
Definition: dbus-auth.c:2454
dbus_bool_t _dbus_auth_is_supported_mechanism(DBusString *name)
Queries whether the given auth mechanism is supported.
Definition: dbus-auth.c:2936
DBusCredentials * _dbus_auth_get_identity(DBusAuth *auth)
Gets the identity we authorized the client as.
Definition: dbus-auth.c:2854
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:2598
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:2804
void _dbus_auth_unref(DBusAuth *auth)
Decrements the refcount of an auth object.
Definition: dbus-auth.c:2469
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:2912
void _dbus_auth_return_buffer(DBusAuth *auth, DBusString *buffer)
Returns a buffer with new data read into it.
Definition: dbus-auth.c:2661
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:2519
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:2697
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:2878
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:2643
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:2773
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:2897
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:2623
#define DBUS_AUTH_IN_END_STATE(auth)
Definition: dbus-auth.c:2544
DBusAuth * _dbus_auth_client_new(void)
Creates a new auth conversation object for the client side.
Definition: dbus-auth.c:2416
DBusAuth * _dbus_auth_server_new(const DBusString *guid)
Creates a new auth conversation object for the server side.
Definition: dbus-auth.c:2370
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:2680
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:2218
DBusAuthCommand command
Corresponding enum.
Definition: dbus-auth.c:2220
const char * name
Name of the command.
Definition: dbus-auth.c:2219
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