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