00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dbus-auth.h"
00024 #include "dbus-string.h"
00025 #include "dbus-list.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-keyring.h"
00028 #include "dbus-sha.h"
00029 #include "dbus-userdb.h"
00030
00071 typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth,
00072 DBusString *response);
00073
00078 typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth,
00079 const DBusString *data);
00080
00084 typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth,
00085 const DBusString *data,
00086 DBusString *encoded);
00087
00091 typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
00092 const DBusString *data,
00093 DBusString *decoded);
00094
00098 typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth);
00099
00103 typedef struct
00104 {
00105 const char *mechanism;
00106 DBusAuthDataFunction server_data_func;
00107 DBusAuthEncodeFunction server_encode_func;
00108 DBusAuthDecodeFunction server_decode_func;
00109 DBusAuthShutdownFunction server_shutdown_func;
00110 DBusInitialResponseFunction client_initial_response_func;
00111 DBusAuthDataFunction client_data_func;
00112 DBusAuthEncodeFunction client_encode_func;
00113 DBusAuthDecodeFunction client_decode_func;
00114 DBusAuthShutdownFunction client_shutdown_func;
00115 } DBusAuthMechanismHandler;
00116
00120 typedef enum {
00121 DBUS_AUTH_COMMAND_AUTH,
00122 DBUS_AUTH_COMMAND_CANCEL,
00123 DBUS_AUTH_COMMAND_DATA,
00124 DBUS_AUTH_COMMAND_BEGIN,
00125 DBUS_AUTH_COMMAND_REJECTED,
00126 DBUS_AUTH_COMMAND_OK,
00127 DBUS_AUTH_COMMAND_ERROR,
00128 DBUS_AUTH_COMMAND_UNKNOWN
00129 } DBusAuthCommand;
00130
00136 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth,
00137 DBusAuthCommand command,
00138 const DBusString *args);
00139
00143 typedef struct
00144 {
00145 const char *name;
00146 DBusAuthStateFunction handler;
00147 } DBusAuthStateData;
00148
00152 struct DBusAuth
00153 {
00154 int refcount;
00155 const char *side;
00157 DBusString incoming;
00158 DBusString outgoing;
00160 const DBusAuthStateData *state;
00162 const DBusAuthMechanismHandler *mech;
00164 DBusString identity;
00168 DBusCredentials credentials;
00172 DBusCredentials authorized_identity;
00174 DBusCredentials desired_identity;
00176 DBusString context;
00177 DBusKeyring *keyring;
00178 int cookie_id;
00179 DBusString challenge;
00181 char **allowed_mechs;
00185 unsigned int needed_memory : 1;
00188 unsigned int already_got_mechanisms : 1;
00189 unsigned int already_asked_for_initial_response : 1;
00190 unsigned int buffer_outstanding : 1;
00191 };
00192
00196 typedef struct
00197 {
00198 DBusAuth base;
00200 DBusList *mechs_to_try;
00202 } DBusAuthClient;
00203
00207 typedef struct
00208 {
00209 DBusAuth base;
00211 int failures;
00212 int max_failures;
00214 } DBusAuthServer;
00215
00216 static void goto_state (DBusAuth *auth,
00217 const DBusAuthStateData *new_state);
00218 static dbus_bool_t send_auth (DBusAuth *auth,
00219 const DBusAuthMechanismHandler *mech);
00220 static dbus_bool_t send_data (DBusAuth *auth,
00221 DBusString *data);
00222 static dbus_bool_t send_rejected (DBusAuth *auth);
00223 static dbus_bool_t send_error (DBusAuth *auth,
00224 const char *message);
00225 static dbus_bool_t send_ok (DBusAuth *auth);
00226 static dbus_bool_t send_begin (DBusAuth *auth);
00227 static dbus_bool_t send_cancel (DBusAuth *auth);
00228
00233 static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth,
00234 DBusAuthCommand command,
00235 const DBusString *args);
00236 static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth,
00237 DBusAuthCommand command,
00238 const DBusString *args);
00239 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth,
00240 DBusAuthCommand command,
00241 const DBusString *args);
00242
00243 static const DBusAuthStateData server_state_waiting_for_auth = {
00244 "WaitingForAuth", handle_server_state_waiting_for_auth
00245 };
00246 static const DBusAuthStateData server_state_waiting_for_data = {
00247 "WaitingForData", handle_server_state_waiting_for_data
00248 };
00249 static const DBusAuthStateData server_state_waiting_for_begin = {
00250 "WaitingForBegin", handle_server_state_waiting_for_begin
00251 };
00252
00257 static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth,
00258 DBusAuthCommand command,
00259 const DBusString *args);
00260 static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth,
00261 DBusAuthCommand command,
00262 const DBusString *args);
00263 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth,
00264 DBusAuthCommand command,
00265 const DBusString *args);
00266
00267 static const DBusAuthStateData client_state_need_send_auth = {
00268 "NeedSendAuth", NULL
00269 };
00270 static const DBusAuthStateData client_state_waiting_for_data = {
00271 "WaitingForData", handle_client_state_waiting_for_data
00272 };
00273 static const DBusAuthStateData client_state_waiting_for_ok = {
00274 "WaitingForOK", handle_client_state_waiting_for_ok
00275 };
00276 static const DBusAuthStateData client_state_waiting_for_reject = {
00277 "WaitingForReject", handle_client_state_waiting_for_reject
00278 };
00279
00284 static const DBusAuthStateData common_state_authenticated = {
00285 "Authenticated", NULL
00286 };
00287
00288 static const DBusAuthStateData common_state_need_disconnect = {
00289 "NeedDisconnect", NULL
00290 };
00291
00292 static const char auth_side_client[] = "client";
00293 static const char auth_side_server[] = "server";
00298 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00299
00303 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00304
00308 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
00309
00313 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
00314
00320 #define DBUS_AUTH_NAME(auth) ((auth)->side)
00321
00322 static DBusAuth*
00323 _dbus_auth_new (int size)
00324 {
00325 DBusAuth *auth;
00326
00327 auth = dbus_malloc0 (size);
00328 if (auth == NULL)
00329 return NULL;
00330
00331 auth->refcount = 1;
00332
00333 _dbus_credentials_clear (&auth->credentials);
00334 _dbus_credentials_clear (&auth->authorized_identity);
00335 _dbus_credentials_clear (&auth->desired_identity);
00336
00337 auth->keyring = NULL;
00338 auth->cookie_id = -1;
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 if (!_dbus_string_init (&auth->incoming))
00349 goto enomem_0;
00350
00351 if (!_dbus_string_init (&auth->outgoing))
00352 goto enomem_1;
00353
00354 if (!_dbus_string_init (&auth->identity))
00355 goto enomem_2;
00356
00357 if (!_dbus_string_init (&auth->context))
00358 goto enomem_3;
00359
00360 if (!_dbus_string_init (&auth->challenge))
00361 goto enomem_4;
00362
00363
00364 if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
00365 goto enomem_5;
00366
00367 return auth;
00368
00369 enomem_5:
00370 _dbus_string_free (&auth->challenge);
00371 enomem_4:
00372 _dbus_string_free (&auth->context);
00373 enomem_3:
00374 _dbus_string_free (&auth->identity);
00375 enomem_2:
00376 _dbus_string_free (&auth->outgoing);
00377 enomem_1:
00378 _dbus_string_free (&auth->incoming);
00379 enomem_0:
00380 dbus_free (auth);
00381 return NULL;
00382 }
00383
00384 static void
00385 shutdown_mech (DBusAuth *auth)
00386 {
00387
00388 auth->already_asked_for_initial_response = FALSE;
00389 _dbus_string_set_length (&auth->identity, 0);
00390
00391 _dbus_credentials_clear (&auth->authorized_identity);
00392 _dbus_credentials_clear (&auth->desired_identity);
00393
00394 if (auth->mech != NULL)
00395 {
00396 _dbus_verbose ("%s: Shutting down mechanism %s\n",
00397 DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00398
00399 if (DBUS_AUTH_IS_CLIENT (auth))
00400 (* auth->mech->client_shutdown_func) (auth);
00401 else
00402 (* auth->mech->server_shutdown_func) (auth);
00403
00404 auth->mech = NULL;
00405 }
00406 }
00407
00408
00409
00410
00411
00412 static dbus_bool_t
00413 sha1_compute_hash (DBusAuth *auth,
00414 int cookie_id,
00415 const DBusString *server_challenge,
00416 const DBusString *client_challenge,
00417 DBusString *hash)
00418 {
00419 DBusString cookie;
00420 DBusString to_hash;
00421 dbus_bool_t retval;
00422
00423 _dbus_assert (auth->keyring != NULL);
00424
00425 retval = FALSE;
00426
00427 if (!_dbus_string_init (&cookie))
00428 return FALSE;
00429
00430 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
00431 &cookie))
00432 goto out_0;
00433
00434 if (_dbus_string_get_length (&cookie) == 0)
00435 {
00436 retval = TRUE;
00437 goto out_0;
00438 }
00439
00440 if (!_dbus_string_init (&to_hash))
00441 goto out_0;
00442
00443 if (!_dbus_string_copy (server_challenge, 0,
00444 &to_hash, _dbus_string_get_length (&to_hash)))
00445 goto out_1;
00446
00447 if (!_dbus_string_append (&to_hash, ":"))
00448 goto out_1;
00449
00450 if (!_dbus_string_copy (client_challenge, 0,
00451 &to_hash, _dbus_string_get_length (&to_hash)))
00452 goto out_1;
00453
00454 if (!_dbus_string_append (&to_hash, ":"))
00455 goto out_1;
00456
00457 if (!_dbus_string_copy (&cookie, 0,
00458 &to_hash, _dbus_string_get_length (&to_hash)))
00459 goto out_1;
00460
00461 if (!_dbus_sha_compute (&to_hash, hash))
00462 goto out_1;
00463
00464 retval = TRUE;
00465
00466 out_1:
00467 _dbus_string_zero (&to_hash);
00468 _dbus_string_free (&to_hash);
00469 out_0:
00470 _dbus_string_zero (&cookie);
00471 _dbus_string_free (&cookie);
00472 return retval;
00473 }
00474
00479 #define N_CHALLENGE_BYTES (128/8)
00480
00481 static dbus_bool_t
00482 sha1_handle_first_client_response (DBusAuth *auth,
00483 const DBusString *data)
00484 {
00485
00486
00487
00488 DBusString tmp;
00489 DBusString tmp2;
00490 dbus_bool_t retval;
00491 DBusError error;
00492
00493 retval = FALSE;
00494
00495 _dbus_string_set_length (&auth->challenge, 0);
00496
00497 if (_dbus_string_get_length (data) > 0)
00498 {
00499 if (_dbus_string_get_length (&auth->identity) > 0)
00500 {
00501
00502 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00503 DBUS_AUTH_NAME (auth));
00504 return send_rejected (auth);
00505 }
00506 else
00507 {
00508
00509 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00510 return FALSE;
00511 }
00512 }
00513
00514 if (!_dbus_credentials_from_username (data, &auth->desired_identity))
00515 {
00516 _dbus_verbose ("%s: Did not get a valid username from client\n",
00517 DBUS_AUTH_NAME (auth));
00518 return send_rejected (auth);
00519 }
00520
00521 if (!_dbus_string_init (&tmp))
00522 return FALSE;
00523
00524 if (!_dbus_string_init (&tmp2))
00525 {
00526 _dbus_string_free (&tmp);
00527 return FALSE;
00528 }
00529
00530
00531
00532
00533
00534 if (auth->keyring &&
00535 !_dbus_keyring_is_for_user (auth->keyring,
00536 data))
00537 {
00538 _dbus_keyring_unref (auth->keyring);
00539 auth->keyring = NULL;
00540 }
00541
00542 if (auth->keyring == NULL)
00543 {
00544 DBusError error;
00545
00546 dbus_error_init (&error);
00547 auth->keyring = _dbus_keyring_new_homedir (data,
00548 &auth->context,
00549 &error);
00550
00551 if (auth->keyring == NULL)
00552 {
00553 if (dbus_error_has_name (&error,
00554 DBUS_ERROR_NO_MEMORY))
00555 {
00556 dbus_error_free (&error);
00557 goto out;
00558 }
00559 else
00560 {
00561 _DBUS_ASSERT_ERROR_IS_SET (&error);
00562 _dbus_verbose ("%s: Error loading keyring: %s\n",
00563 DBUS_AUTH_NAME (auth), error.message);
00564 if (send_rejected (auth))
00565 retval = TRUE;
00566 dbus_error_free (&error);
00567 goto out;
00568 }
00569 }
00570 else
00571 {
00572 _dbus_assert (!dbus_error_is_set (&error));
00573 }
00574 }
00575
00576 _dbus_assert (auth->keyring != NULL);
00577
00578 dbus_error_init (&error);
00579 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00580 if (auth->cookie_id < 0)
00581 {
00582 _DBUS_ASSERT_ERROR_IS_SET (&error);
00583 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00584 DBUS_AUTH_NAME (auth), error.message);
00585 if (send_rejected (auth))
00586 retval = TRUE;
00587 dbus_error_free (&error);
00588 goto out;
00589 }
00590 else
00591 {
00592 _dbus_assert (!dbus_error_is_set (&error));
00593 }
00594
00595 if (!_dbus_string_copy (&auth->context, 0,
00596 &tmp2, _dbus_string_get_length (&tmp2)))
00597 goto out;
00598
00599 if (!_dbus_string_append (&tmp2, " "))
00600 goto out;
00601
00602 if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00603 goto out;
00604
00605 if (!_dbus_string_append (&tmp2, " "))
00606 goto out;
00607
00608 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00609 goto out;
00610
00611 _dbus_string_set_length (&auth->challenge, 0);
00612 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00613 goto out;
00614
00615 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00616 _dbus_string_get_length (&tmp2)))
00617 goto out;
00618
00619 if (!send_data (auth, &tmp2))
00620 goto out;
00621
00622 goto_state (auth, &server_state_waiting_for_data);
00623 retval = TRUE;
00624
00625 out:
00626 _dbus_string_zero (&tmp);
00627 _dbus_string_free (&tmp);
00628 _dbus_string_zero (&tmp2);
00629 _dbus_string_free (&tmp2);
00630
00631 return retval;
00632 }
00633
00634 static dbus_bool_t
00635 sha1_handle_second_client_response (DBusAuth *auth,
00636 const DBusString *data)
00637 {
00638
00639
00640
00641
00642
00643 int i;
00644 DBusString client_challenge;
00645 DBusString client_hash;
00646 dbus_bool_t retval;
00647 DBusString correct_hash;
00648
00649 retval = FALSE;
00650
00651 if (!_dbus_string_find_blank (data, 0, &i))
00652 {
00653 _dbus_verbose ("%s: no space separator in client response\n",
00654 DBUS_AUTH_NAME (auth));
00655 return send_rejected (auth);
00656 }
00657
00658 if (!_dbus_string_init (&client_challenge))
00659 goto out_0;
00660
00661 if (!_dbus_string_init (&client_hash))
00662 goto out_1;
00663
00664 if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00665 0))
00666 goto out_2;
00667
00668 _dbus_string_skip_blank (data, i, &i);
00669
00670 if (!_dbus_string_copy_len (data, i,
00671 _dbus_string_get_length (data) - i,
00672 &client_hash,
00673 0))
00674 goto out_2;
00675
00676 if (_dbus_string_get_length (&client_challenge) == 0 ||
00677 _dbus_string_get_length (&client_hash) == 0)
00678 {
00679 _dbus_verbose ("%s: zero-length client challenge or hash\n",
00680 DBUS_AUTH_NAME (auth));
00681 if (send_rejected (auth))
00682 retval = TRUE;
00683 goto out_2;
00684 }
00685
00686 if (!_dbus_string_init (&correct_hash))
00687 goto out_2;
00688
00689 if (!sha1_compute_hash (auth, auth->cookie_id,
00690 &auth->challenge,
00691 &client_challenge,
00692 &correct_hash))
00693 goto out_3;
00694
00695
00696 if (_dbus_string_get_length (&correct_hash) == 0)
00697 {
00698 if (send_rejected (auth))
00699 retval = TRUE;
00700 goto out_3;
00701 }
00702
00703 if (!_dbus_string_equal (&client_hash, &correct_hash))
00704 {
00705 if (send_rejected (auth))
00706 retval = TRUE;
00707 goto out_3;
00708 }
00709
00710 if (!send_ok (auth))
00711 goto out_3;
00712
00713 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n",
00714 DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
00715
00716 auth->authorized_identity = auth->desired_identity;
00717 retval = TRUE;
00718
00719 out_3:
00720 _dbus_string_zero (&correct_hash);
00721 _dbus_string_free (&correct_hash);
00722 out_2:
00723 _dbus_string_zero (&client_hash);
00724 _dbus_string_free (&client_hash);
00725 out_1:
00726 _dbus_string_free (&client_challenge);
00727 out_0:
00728 return retval;
00729 }
00730
00731 static dbus_bool_t
00732 handle_server_data_cookie_sha1_mech (DBusAuth *auth,
00733 const DBusString *data)
00734 {
00735 if (auth->cookie_id < 0)
00736 return sha1_handle_first_client_response (auth, data);
00737 else
00738 return sha1_handle_second_client_response (auth, data);
00739 }
00740
00741 static void
00742 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00743 {
00744 auth->cookie_id = -1;
00745 _dbus_string_set_length (&auth->challenge, 0);
00746 }
00747
00748 static dbus_bool_t
00749 handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
00750 DBusString *response)
00751 {
00752 const DBusString *username;
00753 dbus_bool_t retval;
00754
00755 retval = FALSE;
00756
00757 if (!_dbus_username_from_current_process (&username))
00758 goto out_0;
00759
00760 if (!_dbus_string_hex_encode (username, 0,
00761 response,
00762 _dbus_string_get_length (response)))
00763 goto out_0;
00764
00765 retval = TRUE;
00766
00767 out_0:
00768 return retval;
00769 }
00770
00771 static dbus_bool_t
00772 handle_client_data_cookie_sha1_mech (DBusAuth *auth,
00773 const DBusString *data)
00774 {
00775
00776
00777
00778
00779 dbus_bool_t retval;
00780 DBusString context;
00781 DBusString cookie_id_str;
00782 DBusString server_challenge;
00783 DBusString client_challenge;
00784 DBusString correct_hash;
00785 DBusString tmp;
00786 int i, j;
00787 long val;
00788
00789 retval = FALSE;
00790
00791 if (!_dbus_string_find_blank (data, 0, &i))
00792 {
00793 if (send_error (auth,
00794 "Server did not send context/ID/challenge properly"))
00795 retval = TRUE;
00796 goto out_0;
00797 }
00798
00799 if (!_dbus_string_init (&context))
00800 goto out_0;
00801
00802 if (!_dbus_string_copy_len (data, 0, i,
00803 &context, 0))
00804 goto out_1;
00805
00806 _dbus_string_skip_blank (data, i, &i);
00807 if (!_dbus_string_find_blank (data, i, &j))
00808 {
00809 if (send_error (auth,
00810 "Server did not send context/ID/challenge properly"))
00811 retval = TRUE;
00812 goto out_1;
00813 }
00814
00815 if (!_dbus_string_init (&cookie_id_str))
00816 goto out_1;
00817
00818 if (!_dbus_string_copy_len (data, i, j - i,
00819 &cookie_id_str, 0))
00820 goto out_2;
00821
00822 if (!_dbus_string_init (&server_challenge))
00823 goto out_2;
00824
00825 i = j;
00826 _dbus_string_skip_blank (data, i, &i);
00827 j = _dbus_string_get_length (data);
00828
00829 if (!_dbus_string_copy_len (data, i, j - i,
00830 &server_challenge, 0))
00831 goto out_3;
00832
00833 if (!_dbus_keyring_validate_context (&context))
00834 {
00835 if (send_error (auth, "Server sent invalid cookie context"))
00836 retval = TRUE;
00837 goto out_3;
00838 }
00839
00840 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00841 {
00842 if (send_error (auth, "Could not parse cookie ID as an integer"))
00843 retval = TRUE;
00844 goto out_3;
00845 }
00846
00847 if (_dbus_string_get_length (&server_challenge) == 0)
00848 {
00849 if (send_error (auth, "Empty server challenge string"))
00850 retval = TRUE;
00851 goto out_3;
00852 }
00853
00854 if (auth->keyring == NULL)
00855 {
00856 DBusError error;
00857
00858 dbus_error_init (&error);
00859 auth->keyring = _dbus_keyring_new_homedir (NULL,
00860 &context,
00861 &error);
00862
00863 if (auth->keyring == NULL)
00864 {
00865 if (dbus_error_has_name (&error,
00866 DBUS_ERROR_NO_MEMORY))
00867 {
00868 dbus_error_free (&error);
00869 goto out_3;
00870 }
00871 else
00872 {
00873 _DBUS_ASSERT_ERROR_IS_SET (&error);
00874
00875 _dbus_verbose ("%s: Error loading keyring: %s\n",
00876 DBUS_AUTH_NAME (auth), error.message);
00877
00878 if (send_error (auth, "Could not load cookie file"))
00879 retval = TRUE;
00880
00881 dbus_error_free (&error);
00882 goto out_3;
00883 }
00884 }
00885 else
00886 {
00887 _dbus_assert (!dbus_error_is_set (&error));
00888 }
00889 }
00890
00891 _dbus_assert (auth->keyring != NULL);
00892
00893 if (!_dbus_string_init (&tmp))
00894 goto out_3;
00895
00896 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00897 goto out_4;
00898
00899 if (!_dbus_string_init (&client_challenge))
00900 goto out_4;
00901
00902 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00903 goto out_5;
00904
00905 if (!_dbus_string_init (&correct_hash))
00906 goto out_5;
00907
00908 if (!sha1_compute_hash (auth, val,
00909 &server_challenge,
00910 &client_challenge,
00911 &correct_hash))
00912 goto out_6;
00913
00914 if (_dbus_string_get_length (&correct_hash) == 0)
00915 {
00916
00917 if (send_error (auth, "Don't have the requested cookie ID"))
00918 retval = TRUE;
00919 goto out_6;
00920 }
00921
00922 _dbus_string_set_length (&tmp, 0);
00923
00924 if (!_dbus_string_copy (&client_challenge, 0, &tmp,
00925 _dbus_string_get_length (&tmp)))
00926 goto out_6;
00927
00928 if (!_dbus_string_append (&tmp, " "))
00929 goto out_6;
00930
00931 if (!_dbus_string_copy (&correct_hash, 0, &tmp,
00932 _dbus_string_get_length (&tmp)))
00933 goto out_6;
00934
00935 if (!send_data (auth, &tmp))
00936 goto out_6;
00937
00938 retval = TRUE;
00939
00940 out_6:
00941 _dbus_string_zero (&correct_hash);
00942 _dbus_string_free (&correct_hash);
00943 out_5:
00944 _dbus_string_free (&client_challenge);
00945 out_4:
00946 _dbus_string_zero (&tmp);
00947 _dbus_string_free (&tmp);
00948 out_3:
00949 _dbus_string_free (&server_challenge);
00950 out_2:
00951 _dbus_string_free (&cookie_id_str);
00952 out_1:
00953 _dbus_string_free (&context);
00954 out_0:
00955 return retval;
00956 }
00957
00958 static void
00959 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
00960 {
00961 auth->cookie_id = -1;
00962 _dbus_string_set_length (&auth->challenge, 0);
00963 }
00964
00965 static dbus_bool_t
00966 handle_server_data_external_mech (DBusAuth *auth,
00967 const DBusString *data)
00968 {
00969 if (auth->credentials.uid == DBUS_UID_UNSET)
00970 {
00971 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
00972 DBUS_AUTH_NAME (auth));
00973 return send_rejected (auth);
00974 }
00975
00976 if (_dbus_string_get_length (data) > 0)
00977 {
00978 if (_dbus_string_get_length (&auth->identity) > 0)
00979 {
00980
00981 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00982 DBUS_AUTH_NAME (auth));
00983 return send_rejected (auth);
00984 }
00985 else
00986 {
00987
00988 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00989 return FALSE;
00990 }
00991 }
00992
00993
00994 if (_dbus_string_get_length (&auth->identity) == 0 &&
00995 !auth->already_asked_for_initial_response)
00996 {
00997 if (send_data (auth, NULL))
00998 {
00999 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01000 DBUS_AUTH_NAME (auth));
01001 auth->already_asked_for_initial_response = TRUE;
01002 return TRUE;
01003 }
01004 else
01005 return FALSE;
01006 }
01007
01008 _dbus_credentials_clear (&auth->desired_identity);
01009
01010
01011
01012
01013
01014
01015 if (_dbus_string_get_length (&auth->identity) == 0)
01016 {
01017 auth->desired_identity.uid = auth->credentials.uid;
01018 }
01019 else
01020 {
01021 if (!_dbus_uid_from_string (&auth->identity,
01022 &auth->desired_identity.uid))
01023 {
01024 _dbus_verbose ("%s: could not get credentials from uid string\n",
01025 DBUS_AUTH_NAME (auth));
01026 return send_rejected (auth);
01027 }
01028 }
01029
01030 if (auth->desired_identity.uid == DBUS_UID_UNSET)
01031 {
01032 _dbus_verbose ("%s: desired user %s is no good\n",
01033 DBUS_AUTH_NAME (auth),
01034 _dbus_string_get_const_data (&auth->identity));
01035 return send_rejected (auth);
01036 }
01037
01038 if (_dbus_credentials_match (&auth->desired_identity,
01039 &auth->credentials))
01040 {
01041
01042 if (!send_ok (auth))
01043 return FALSE;
01044
01045 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
01046 " matching socket credentials UID "DBUS_UID_FORMAT"\n",
01047 DBUS_AUTH_NAME (auth),
01048 auth->desired_identity.uid,
01049 auth->credentials.uid);
01050
01051 auth->authorized_identity.uid = auth->desired_identity.uid;
01052
01053 return TRUE;
01054 }
01055 else
01056 {
01057 _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
01058 " gid="DBUS_GID_FORMAT
01059 " do not allow uid="DBUS_UID_FORMAT
01060 " gid="DBUS_GID_FORMAT"\n",
01061 DBUS_AUTH_NAME (auth),
01062 auth->credentials.uid, auth->credentials.gid,
01063 auth->desired_identity.uid, auth->desired_identity.gid);
01064 return send_rejected (auth);
01065 }
01066 }
01067
01068 static void
01069 handle_server_shutdown_external_mech (DBusAuth *auth)
01070 {
01071
01072 }
01073
01074 static dbus_bool_t
01075 handle_client_initial_response_external_mech (DBusAuth *auth,
01076 DBusString *response)
01077 {
01078
01079
01080
01081
01082
01083 DBusString plaintext;
01084
01085 if (!_dbus_string_init (&plaintext))
01086 return FALSE;
01087
01088 if (!_dbus_string_append_uint (&plaintext,
01089 _dbus_getuid ()))
01090 goto failed;
01091
01092 if (!_dbus_string_hex_encode (&plaintext, 0,
01093 response,
01094 _dbus_string_get_length (response)))
01095 goto failed;
01096
01097 _dbus_string_free (&plaintext);
01098
01099 return TRUE;
01100
01101 failed:
01102 _dbus_string_free (&plaintext);
01103 return FALSE;
01104 }
01105
01106 static dbus_bool_t
01107 handle_client_data_external_mech (DBusAuth *auth,
01108 const DBusString *data)
01109 {
01110
01111 return TRUE;
01112 }
01113
01114 static void
01115 handle_client_shutdown_external_mech (DBusAuth *auth)
01116 {
01117
01118 }
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129 static const DBusAuthMechanismHandler
01130 all_mechanisms[] = {
01131 { "EXTERNAL",
01132 handle_server_data_external_mech,
01133 NULL, NULL,
01134 handle_server_shutdown_external_mech,
01135 handle_client_initial_response_external_mech,
01136 handle_client_data_external_mech,
01137 NULL, NULL,
01138 handle_client_shutdown_external_mech },
01139 { "DBUS_COOKIE_SHA1",
01140 handle_server_data_cookie_sha1_mech,
01141 NULL, NULL,
01142 handle_server_shutdown_cookie_sha1_mech,
01143 handle_client_initial_response_cookie_sha1_mech,
01144 handle_client_data_cookie_sha1_mech,
01145 NULL, NULL,
01146 handle_client_shutdown_cookie_sha1_mech },
01147 { NULL, NULL }
01148 };
01149
01150 static const DBusAuthMechanismHandler*
01151 find_mech (const DBusString *name,
01152 char **allowed_mechs)
01153 {
01154 int i;
01155
01156 if (allowed_mechs != NULL &&
01157 !_dbus_string_array_contains ((const char**) allowed_mechs,
01158 _dbus_string_get_const_data (name)))
01159 return NULL;
01160
01161 i = 0;
01162 while (all_mechanisms[i].mechanism != NULL)
01163 {
01164 if (_dbus_string_equal_c_str (name,
01165 all_mechanisms[i].mechanism))
01166
01167 return &all_mechanisms[i];
01168
01169 ++i;
01170 }
01171
01172 return NULL;
01173 }
01174
01175 static dbus_bool_t
01176 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01177 {
01178 DBusString auth_command;
01179
01180 if (!_dbus_string_init (&auth_command))
01181 return FALSE;
01182
01183 if (!_dbus_string_append (&auth_command,
01184 "AUTH "))
01185 {
01186 _dbus_string_free (&auth_command);
01187 return FALSE;
01188 }
01189
01190 if (!_dbus_string_append (&auth_command,
01191 mech->mechanism))
01192 {
01193 _dbus_string_free (&auth_command);
01194 return FALSE;
01195 }
01196
01197 if (mech->client_initial_response_func != NULL)
01198 {
01199 if (!_dbus_string_append (&auth_command, " "))
01200 {
01201 _dbus_string_free (&auth_command);
01202 return FALSE;
01203 }
01204
01205 if (!(* mech->client_initial_response_func) (auth, &auth_command))
01206 {
01207 _dbus_string_free (&auth_command);
01208 return FALSE;
01209 }
01210 }
01211
01212 if (!_dbus_string_append (&auth_command,
01213 "\r\n"))
01214 {
01215 _dbus_string_free (&auth_command);
01216 return FALSE;
01217 }
01218
01219 if (!_dbus_string_copy (&auth_command, 0,
01220 &auth->outgoing,
01221 _dbus_string_get_length (&auth->outgoing)))
01222 {
01223 _dbus_string_free (&auth_command);
01224 return FALSE;
01225 }
01226
01227 _dbus_string_free (&auth_command);
01228 shutdown_mech (auth);
01229 auth->mech = mech;
01230 goto_state (auth, &client_state_waiting_for_data);
01231
01232 return TRUE;
01233 }
01234
01235 static dbus_bool_t
01236 send_data (DBusAuth *auth, DBusString *data)
01237 {
01238 int old_len;
01239
01240 if (data == NULL || _dbus_string_get_length (data) == 0)
01241 return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01242 else
01243 {
01244 old_len = _dbus_string_get_length (&auth->outgoing);
01245 if (!_dbus_string_append (&auth->outgoing, "DATA "))
01246 goto out;
01247
01248 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01249 _dbus_string_get_length (&auth->outgoing)))
01250 goto out;
01251
01252 if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01253 goto out;
01254
01255 return TRUE;
01256
01257 out:
01258 _dbus_string_set_length (&auth->outgoing, old_len);
01259
01260 return FALSE;
01261 }
01262 }
01263
01264 static dbus_bool_t
01265 send_rejected (DBusAuth *auth)
01266 {
01267 DBusString command;
01268 DBusAuthServer *server_auth;
01269 int i;
01270
01271 if (!_dbus_string_init (&command))
01272 return FALSE;
01273
01274 if (!_dbus_string_append (&command,
01275 "REJECTED"))
01276 goto nomem;
01277
01278 i = 0;
01279 while (all_mechanisms[i].mechanism != NULL)
01280 {
01281 if (!_dbus_string_append (&command,
01282 " "))
01283 goto nomem;
01284
01285 if (!_dbus_string_append (&command,
01286 all_mechanisms[i].mechanism))
01287 goto nomem;
01288
01289 ++i;
01290 }
01291
01292 if (!_dbus_string_append (&command, "\r\n"))
01293 goto nomem;
01294
01295 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01296 _dbus_string_get_length (&auth->outgoing)))
01297 goto nomem;
01298
01299 shutdown_mech (auth);
01300
01301 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01302 server_auth = DBUS_AUTH_SERVER (auth);
01303 server_auth->failures += 1;
01304
01305 if (server_auth->failures >= server_auth->max_failures)
01306 goto_state (auth, &common_state_need_disconnect);
01307 else
01308 goto_state (auth, &server_state_waiting_for_auth);
01309
01310 _dbus_string_free (&command);
01311
01312 return TRUE;
01313
01314 nomem:
01315 _dbus_string_free (&command);
01316 return FALSE;
01317 }
01318
01319 static dbus_bool_t
01320 send_error (DBusAuth *auth, const char *message)
01321 {
01322 return _dbus_string_append_printf (&auth->outgoing,
01323 "ERROR \"%s\"\r\n", message);
01324 }
01325
01326 static dbus_bool_t
01327 send_ok (DBusAuth *auth)
01328 {
01329 if (_dbus_string_append (&auth->outgoing, "OK\r\n"))
01330 {
01331 goto_state (auth, &server_state_waiting_for_begin);
01332 return TRUE;
01333 }
01334 else
01335 return FALSE;
01336 }
01337
01338 static dbus_bool_t
01339 send_begin (DBusAuth *auth)
01340 {
01341 if (_dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01342 {
01343 goto_state (auth, &common_state_authenticated);
01344 return TRUE;
01345 }
01346 else
01347 return FALSE;
01348 }
01349
01350 static dbus_bool_t
01351 send_cancel (DBusAuth *auth)
01352 {
01353 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01354 {
01355 goto_state (auth, &client_state_waiting_for_reject);
01356 return TRUE;
01357 }
01358 else
01359 return FALSE;
01360 }
01361
01362 static dbus_bool_t
01363 process_data (DBusAuth *auth,
01364 const DBusString *args,
01365 DBusAuthDataFunction data_func)
01366 {
01367 int end;
01368 DBusString decoded;
01369
01370 if (!_dbus_string_init (&decoded))
01371 return FALSE;
01372
01373 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01374 {
01375 _dbus_string_free (&decoded);
01376 return FALSE;
01377 }
01378
01379 if (_dbus_string_get_length (args) != end)
01380 {
01381 _dbus_string_free (&decoded);
01382 if (!send_error (auth, "Invalid hex encoding"))
01383 return FALSE;
01384
01385 return TRUE;
01386 }
01387
01388 #ifdef DBUS_ENABLE_VERBOSE_MODE
01389 if (_dbus_string_validate_ascii (&decoded, 0,
01390 _dbus_string_get_length (&decoded)))
01391 _dbus_verbose ("%s: data: '%s'\n",
01392 DBUS_AUTH_NAME (auth),
01393 _dbus_string_get_const_data (&decoded));
01394 #endif
01395
01396 if (!(* data_func) (auth, &decoded))
01397 {
01398 _dbus_string_free (&decoded);
01399 return FALSE;
01400 }
01401
01402 _dbus_string_free (&decoded);
01403 return TRUE;
01404 }
01405
01406 static dbus_bool_t
01407 handle_auth (DBusAuth *auth, const DBusString *args)
01408 {
01409 if (_dbus_string_get_length (args) == 0)
01410 {
01411
01412 if (!send_rejected (auth))
01413 return FALSE;
01414
01415 return TRUE;
01416 }
01417 else
01418 {
01419 int i;
01420 DBusString mech;
01421 DBusString hex_response;
01422
01423 _dbus_string_find_blank (args, 0, &i);
01424
01425 if (!_dbus_string_init (&mech))
01426 return FALSE;
01427
01428 if (!_dbus_string_init (&hex_response))
01429 {
01430 _dbus_string_free (&mech);
01431 return FALSE;
01432 }
01433
01434 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01435 goto failed;
01436
01437 _dbus_string_skip_blank (args, i, &i);
01438 if (!_dbus_string_copy (args, i, &hex_response, 0))
01439 goto failed;
01440
01441 auth->mech = find_mech (&mech, auth->allowed_mechs);
01442 if (auth->mech != NULL)
01443 {
01444 _dbus_verbose ("%s: Trying mechanism %s\n",
01445 DBUS_AUTH_NAME (auth),
01446 auth->mech->mechanism);
01447
01448 if (!process_data (auth, &hex_response,
01449 auth->mech->server_data_func))
01450 goto failed;
01451 }
01452 else
01453 {
01454
01455 _dbus_verbose ("%s: Unsupported mechanism %s\n",
01456 DBUS_AUTH_NAME (auth),
01457 _dbus_string_get_const_data (&mech));
01458
01459 if (!send_rejected (auth))
01460 goto failed;
01461 }
01462
01463 _dbus_string_free (&mech);
01464 _dbus_string_free (&hex_response);
01465
01466 return TRUE;
01467
01468 failed:
01469 auth->mech = NULL;
01470 _dbus_string_free (&mech);
01471 _dbus_string_free (&hex_response);
01472 return FALSE;
01473 }
01474 }
01475
01476 static dbus_bool_t
01477 handle_server_state_waiting_for_auth (DBusAuth *auth,
01478 DBusAuthCommand command,
01479 const DBusString *args)
01480 {
01481 switch (command)
01482 {
01483 case DBUS_AUTH_COMMAND_AUTH:
01484 return handle_auth (auth, args);
01485
01486 case DBUS_AUTH_COMMAND_CANCEL:
01487 case DBUS_AUTH_COMMAND_DATA:
01488 return send_error (auth, "Not currently in an auth conversation");
01489
01490 case DBUS_AUTH_COMMAND_BEGIN:
01491 goto_state (auth, &common_state_need_disconnect);
01492 return TRUE;
01493
01494 case DBUS_AUTH_COMMAND_ERROR:
01495 return send_rejected (auth);
01496
01497 case DBUS_AUTH_COMMAND_REJECTED:
01498 case DBUS_AUTH_COMMAND_OK:
01499 case DBUS_AUTH_COMMAND_UNKNOWN:
01500 default:
01501 return send_error (auth, "Unknown command");
01502 }
01503 }
01504
01505 static dbus_bool_t
01506 handle_server_state_waiting_for_data (DBusAuth *auth,
01507 DBusAuthCommand command,
01508 const DBusString *args)
01509 {
01510 switch (command)
01511 {
01512 case DBUS_AUTH_COMMAND_AUTH:
01513 return send_error (auth, "Sent AUTH while another AUTH in progress");
01514
01515 case DBUS_AUTH_COMMAND_CANCEL:
01516 case DBUS_AUTH_COMMAND_ERROR:
01517 return send_rejected (auth);
01518
01519 case DBUS_AUTH_COMMAND_DATA:
01520 return process_data (auth, args, auth->mech->server_data_func);
01521
01522 case DBUS_AUTH_COMMAND_BEGIN:
01523 goto_state (auth, &common_state_need_disconnect);
01524 return TRUE;
01525
01526 case DBUS_AUTH_COMMAND_REJECTED:
01527 case DBUS_AUTH_COMMAND_OK:
01528 case DBUS_AUTH_COMMAND_UNKNOWN:
01529 default:
01530 return send_error (auth, "Unknown command");
01531 }
01532 }
01533
01534 static dbus_bool_t
01535 handle_server_state_waiting_for_begin (DBusAuth *auth,
01536 DBusAuthCommand command,
01537 const DBusString *args)
01538 {
01539 switch (command)
01540 {
01541 case DBUS_AUTH_COMMAND_AUTH:
01542 return send_error (auth, "Sent AUTH while expecting BEGIN");
01543
01544 case DBUS_AUTH_COMMAND_DATA:
01545 return send_error (auth, "Sent DATA while expecting BEGIN");
01546
01547 case DBUS_AUTH_COMMAND_BEGIN:
01548 goto_state (auth, &common_state_authenticated);
01549 return TRUE;
01550
01551 case DBUS_AUTH_COMMAND_REJECTED:
01552 case DBUS_AUTH_COMMAND_OK:
01553 case DBUS_AUTH_COMMAND_UNKNOWN:
01554 default:
01555 return send_error (auth, "Unknown command");
01556
01557 case DBUS_AUTH_COMMAND_CANCEL:
01558 case DBUS_AUTH_COMMAND_ERROR:
01559 return send_rejected (auth);
01560 }
01561 }
01562
01563
01564 static dbus_bool_t
01565 get_word (const DBusString *str,
01566 int *start,
01567 DBusString *word)
01568 {
01569 int i;
01570
01571 _dbus_string_skip_blank (str, *start, start);
01572 _dbus_string_find_blank (str, *start, &i);
01573
01574 if (i > *start)
01575 {
01576 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01577 return FALSE;
01578
01579 *start = i;
01580 }
01581
01582 return TRUE;
01583 }
01584
01585 static dbus_bool_t
01586 record_mechanisms (DBusAuth *auth,
01587 const DBusString *args)
01588 {
01589 int next;
01590 int len;
01591
01592 if (auth->already_got_mechanisms)
01593 return TRUE;
01594
01595 len = _dbus_string_get_length (args);
01596
01597 next = 0;
01598 while (next < len)
01599 {
01600 DBusString m;
01601 const DBusAuthMechanismHandler *mech;
01602
01603 if (!_dbus_string_init (&m))
01604 goto nomem;
01605
01606 if (!get_word (args, &next, &m))
01607 {
01608 _dbus_string_free (&m);
01609 goto nomem;
01610 }
01611
01612 mech = find_mech (&m, auth->allowed_mechs);
01613
01614 if (mech != NULL)
01615 {
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01626 DBUS_AUTH_NAME (auth), mech->mechanism);
01627
01628 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01629 (void*) mech))
01630 {
01631 _dbus_string_free (&m);
01632 goto nomem;
01633 }
01634 }
01635 else
01636 {
01637 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01638 DBUS_AUTH_NAME (auth),
01639 _dbus_string_get_const_data (&m));
01640 }
01641
01642 _dbus_string_free (&m);
01643 }
01644
01645 auth->already_got_mechanisms = TRUE;
01646
01647 return TRUE;
01648
01649 nomem:
01650 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01651
01652 return FALSE;
01653 }
01654
01655 static dbus_bool_t
01656 process_rejected (DBusAuth *auth, const DBusString *args)
01657 {
01658 const DBusAuthMechanismHandler *mech;
01659 DBusAuthClient *client;
01660
01661 client = DBUS_AUTH_CLIENT (auth);
01662
01663 if (!auth->already_got_mechanisms)
01664 {
01665 if (!record_mechanisms (auth, args))
01666 return FALSE;
01667 }
01668
01669 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01670 {
01671 mech = client->mechs_to_try->data;
01672
01673 if (!send_auth (auth, mech))
01674 return FALSE;
01675
01676 _dbus_list_pop_first (&client->mechs_to_try);
01677
01678 _dbus_verbose ("%s: Trying mechanism %s\n",
01679 DBUS_AUTH_NAME (auth),
01680 mech->mechanism);
01681 }
01682 else
01683 {
01684
01685 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01686 DBUS_AUTH_NAME (auth));
01687 goto_state (auth, &common_state_need_disconnect);
01688 }
01689
01690 return TRUE;
01691 }
01692
01693
01694 static dbus_bool_t
01695 handle_client_state_waiting_for_data (DBusAuth *auth,
01696 DBusAuthCommand command,
01697 const DBusString *args)
01698 {
01699 _dbus_assert (auth->mech != NULL);
01700
01701 switch (command)
01702 {
01703 case DBUS_AUTH_COMMAND_DATA:
01704 return process_data (auth, args, auth->mech->client_data_func);
01705
01706 case DBUS_AUTH_COMMAND_REJECTED:
01707 return process_rejected (auth, args);
01708
01709 case DBUS_AUTH_COMMAND_OK:
01710 return send_begin (auth);
01711
01712 case DBUS_AUTH_COMMAND_ERROR:
01713 return send_cancel (auth);
01714
01715 case DBUS_AUTH_COMMAND_AUTH:
01716 case DBUS_AUTH_COMMAND_CANCEL:
01717 case DBUS_AUTH_COMMAND_BEGIN:
01718 case DBUS_AUTH_COMMAND_UNKNOWN:
01719 default:
01720 return send_error (auth, "Unknown command");
01721 }
01722 }
01723
01724 static dbus_bool_t
01725 handle_client_state_waiting_for_ok (DBusAuth *auth,
01726 DBusAuthCommand command,
01727 const DBusString *args)
01728 {
01729 switch (command)
01730 {
01731 case DBUS_AUTH_COMMAND_REJECTED:
01732 return process_rejected (auth, args);
01733
01734 case DBUS_AUTH_COMMAND_OK:
01735 return send_begin (auth);
01736
01737 case DBUS_AUTH_COMMAND_DATA:
01738 case DBUS_AUTH_COMMAND_ERROR:
01739 return send_cancel (auth);
01740
01741 case DBUS_AUTH_COMMAND_AUTH:
01742 case DBUS_AUTH_COMMAND_CANCEL:
01743 case DBUS_AUTH_COMMAND_BEGIN:
01744 case DBUS_AUTH_COMMAND_UNKNOWN:
01745 default:
01746 return send_error (auth, "Unknown command");
01747 }
01748 }
01749
01750 static dbus_bool_t
01751 handle_client_state_waiting_for_reject (DBusAuth *auth,
01752 DBusAuthCommand command,
01753 const DBusString *args)
01754 {
01755 switch (command)
01756 {
01757 case DBUS_AUTH_COMMAND_REJECTED:
01758 return process_rejected (auth, args);
01759
01760 case DBUS_AUTH_COMMAND_AUTH:
01761 case DBUS_AUTH_COMMAND_CANCEL:
01762 case DBUS_AUTH_COMMAND_DATA:
01763 case DBUS_AUTH_COMMAND_BEGIN:
01764 case DBUS_AUTH_COMMAND_OK:
01765 case DBUS_AUTH_COMMAND_ERROR:
01766 case DBUS_AUTH_COMMAND_UNKNOWN:
01767 default:
01768 goto_state (auth, &common_state_need_disconnect);
01769 return TRUE;
01770 }
01771 }
01772
01776 typedef struct {
01777 const char *name;
01778 DBusAuthCommand command;
01779 } DBusAuthCommandName;
01780
01781 static DBusAuthCommandName auth_command_names[] = {
01782 { "AUTH", DBUS_AUTH_COMMAND_AUTH },
01783 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
01784 { "DATA", DBUS_AUTH_COMMAND_DATA },
01785 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
01786 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
01787 { "OK", DBUS_AUTH_COMMAND_OK },
01788 { "ERROR", DBUS_AUTH_COMMAND_ERROR }
01789 };
01790
01791 static DBusAuthCommand
01792 lookup_command_from_name (DBusString *command)
01793 {
01794 int i;
01795
01796 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
01797 {
01798 if (_dbus_string_equal_c_str (command,
01799 auth_command_names[i].name))
01800 return auth_command_names[i].command;
01801 }
01802
01803 return DBUS_AUTH_COMMAND_UNKNOWN;
01804 }
01805
01806 static void
01807 goto_state (DBusAuth *auth, const DBusAuthStateData *state)
01808 {
01809 _dbus_verbose ("%s: going from state %s to state %s\n",
01810 DBUS_AUTH_NAME (auth),
01811 auth->state->name,
01812 state->name);
01813
01814 auth->state = state;
01815 }
01816
01817
01818 static dbus_bool_t
01819 process_command (DBusAuth *auth)
01820 {
01821 DBusAuthCommand command;
01822 DBusString line;
01823 DBusString args;
01824 int eol;
01825 int i, j;
01826 dbus_bool_t retval;
01827
01828
01829
01830 retval = FALSE;
01831
01832 eol = 0;
01833 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
01834 return FALSE;
01835
01836 if (!_dbus_string_init (&line))
01837 {
01838 auth->needed_memory = TRUE;
01839 return FALSE;
01840 }
01841
01842 if (!_dbus_string_init (&args))
01843 {
01844 _dbus_string_free (&line);
01845 auth->needed_memory = TRUE;
01846 return FALSE;
01847 }
01848
01849 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
01850 goto out;
01851
01852 if (!_dbus_string_validate_ascii (&line, 0,
01853 _dbus_string_get_length (&line)))
01854 {
01855 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
01856 DBUS_AUTH_NAME (auth));
01857 if (!send_error (auth, "Command contained non-ASCII"))
01858 goto out;
01859 else
01860 goto next_command;
01861 }
01862
01863 _dbus_verbose ("%s: got command \"%s\"\n",
01864 DBUS_AUTH_NAME (auth),
01865 _dbus_string_get_const_data (&line));
01866
01867 _dbus_string_find_blank (&line, 0, &i);
01868 _dbus_string_skip_blank (&line, i, &j);
01869
01870 if (j > i)
01871 _dbus_string_delete (&line, i, j - i);
01872
01873 if (!_dbus_string_move (&line, i, &args, 0))
01874 goto out;
01875
01876 command = lookup_command_from_name (&line);
01877 if (!(* auth->state->handler) (auth, command, &args))
01878 goto out;
01879
01880 next_command:
01881
01882
01883
01884
01885
01886 _dbus_string_delete (&auth->incoming, 0, eol);
01887
01888
01889 _dbus_string_delete (&auth->incoming, 0, 2);
01890
01891 retval = TRUE;
01892
01893 out:
01894 _dbus_string_free (&args);
01895 _dbus_string_free (&line);
01896
01897 if (!retval)
01898 auth->needed_memory = TRUE;
01899 else
01900 auth->needed_memory = FALSE;
01901
01902 return retval;
01903 }
01904
01905
01920 DBusAuth*
01921 _dbus_auth_server_new (void)
01922 {
01923 DBusAuth *auth;
01924 DBusAuthServer *server_auth;
01925
01926 auth = _dbus_auth_new (sizeof (DBusAuthServer));
01927 if (auth == NULL)
01928 return NULL;
01929
01930 auth->side = auth_side_server;
01931 auth->state = &server_state_waiting_for_auth;
01932
01933 server_auth = DBUS_AUTH_SERVER (auth);
01934
01935
01936
01937
01938 server_auth->failures = 0;
01939 server_auth->max_failures = 6;
01940
01941 return auth;
01942 }
01943
01951 DBusAuth*
01952 _dbus_auth_client_new (void)
01953 {
01954 DBusAuth *auth;
01955
01956 auth = _dbus_auth_new (sizeof (DBusAuthClient));
01957 if (auth == NULL)
01958 return NULL;
01959
01960 auth->side = auth_side_client;
01961 auth->state = &client_state_need_send_auth;
01962
01963
01964
01965 if (!send_auth (auth, &all_mechanisms[0]))
01966 {
01967 _dbus_auth_unref (auth);
01968 return NULL;
01969 }
01970
01971 return auth;
01972 }
01973
01980 DBusAuth *
01981 _dbus_auth_ref (DBusAuth *auth)
01982 {
01983 _dbus_assert (auth != NULL);
01984
01985 auth->refcount += 1;
01986
01987 return auth;
01988 }
01989
01995 void
01996 _dbus_auth_unref (DBusAuth *auth)
01997 {
01998 _dbus_assert (auth != NULL);
01999 _dbus_assert (auth->refcount > 0);
02000
02001 auth->refcount -= 1;
02002 if (auth->refcount == 0)
02003 {
02004 shutdown_mech (auth);
02005
02006 if (DBUS_AUTH_IS_CLIENT (auth))
02007 {
02008 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02009 }
02010
02011 if (auth->keyring)
02012 _dbus_keyring_unref (auth->keyring);
02013
02014 _dbus_string_free (&auth->context);
02015 _dbus_string_free (&auth->challenge);
02016 _dbus_string_free (&auth->identity);
02017 _dbus_string_free (&auth->incoming);
02018 _dbus_string_free (&auth->outgoing);
02019
02020 dbus_free_string_array (auth->allowed_mechs);
02021
02022 dbus_free (auth);
02023 }
02024 }
02025
02034 dbus_bool_t
02035 _dbus_auth_set_mechanisms (DBusAuth *auth,
02036 const char **mechanisms)
02037 {
02038 char **copy;
02039
02040 if (mechanisms != NULL)
02041 {
02042 copy = _dbus_dup_string_array (mechanisms);
02043 if (copy == NULL)
02044 return FALSE;
02045 }
02046 else
02047 copy = NULL;
02048
02049 dbus_free_string_array (auth->allowed_mechs);
02050
02051 auth->allowed_mechs = copy;
02052
02053 return TRUE;
02054 }
02055
02060 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02061
02069 DBusAuthState
02070 _dbus_auth_do_work (DBusAuth *auth)
02071 {
02072 auth->needed_memory = FALSE;
02073
02074
02075 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02076
02077 do
02078 {
02079 if (DBUS_AUTH_IN_END_STATE (auth))
02080 break;
02081
02082 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02083 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02084 {
02085 goto_state (auth, &common_state_need_disconnect);
02086 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02087 DBUS_AUTH_NAME (auth));
02088 break;
02089 }
02090 }
02091 while (process_command (auth));
02092
02093 if (auth->needed_memory)
02094 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02095 else if (_dbus_string_get_length (&auth->outgoing) > 0)
02096 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02097 else if (auth->state == &common_state_need_disconnect)
02098 return DBUS_AUTH_STATE_NEED_DISCONNECT;
02099 else if (auth->state == &common_state_authenticated)
02100 return DBUS_AUTH_STATE_AUTHENTICATED;
02101 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02102 }
02103
02113 dbus_bool_t
02114 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
02115 const DBusString **str)
02116 {
02117 _dbus_assert (auth != NULL);
02118 _dbus_assert (str != NULL);
02119
02120 *str = NULL;
02121
02122 if (_dbus_string_get_length (&auth->outgoing) == 0)
02123 return FALSE;
02124
02125 *str = &auth->outgoing;
02126
02127 return TRUE;
02128 }
02129
02138 void
02139 _dbus_auth_bytes_sent (DBusAuth *auth,
02140 int bytes_sent)
02141 {
02142 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02143 DBUS_AUTH_NAME (auth),
02144 bytes_sent,
02145 _dbus_string_get_const_data (&auth->outgoing));
02146
02147 _dbus_string_delete (&auth->outgoing,
02148 0, bytes_sent);
02149 }
02150
02158 void
02159 _dbus_auth_get_buffer (DBusAuth *auth,
02160 DBusString **buffer)
02161 {
02162 _dbus_assert (auth != NULL);
02163 _dbus_assert (!auth->buffer_outstanding);
02164
02165 *buffer = &auth->incoming;
02166
02167 auth->buffer_outstanding = TRUE;
02168 }
02169
02177 void
02178 _dbus_auth_return_buffer (DBusAuth *auth,
02179 DBusString *buffer,
02180 int bytes_read)
02181 {
02182 _dbus_assert (buffer == &auth->incoming);
02183 _dbus_assert (auth->buffer_outstanding);
02184
02185 auth->buffer_outstanding = FALSE;
02186 }
02187
02197 void
02198 _dbus_auth_get_unused_bytes (DBusAuth *auth,
02199 const DBusString **str)
02200 {
02201 if (!DBUS_AUTH_IN_END_STATE (auth))
02202 return;
02203
02204 *str = &auth->incoming;
02205 }
02206
02207
02214 void
02215 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02216 {
02217 if (!DBUS_AUTH_IN_END_STATE (auth))
02218 return;
02219
02220 _dbus_string_set_length (&auth->incoming, 0);
02221 }
02222
02231 dbus_bool_t
02232 _dbus_auth_needs_encoding (DBusAuth *auth)
02233 {
02234 if (auth->state != &common_state_authenticated)
02235 return FALSE;
02236
02237 if (auth->mech != NULL)
02238 {
02239 if (DBUS_AUTH_IS_CLIENT (auth))
02240 return auth->mech->client_encode_func != NULL;
02241 else
02242 return auth->mech->server_encode_func != NULL;
02243 }
02244 else
02245 return FALSE;
02246 }
02247
02258 dbus_bool_t
02259 _dbus_auth_encode_data (DBusAuth *auth,
02260 const DBusString *plaintext,
02261 DBusString *encoded)
02262 {
02263 _dbus_assert (plaintext != encoded);
02264
02265 if (auth->state != &common_state_authenticated)
02266 return FALSE;
02267
02268 if (_dbus_auth_needs_encoding (auth))
02269 {
02270 if (DBUS_AUTH_IS_CLIENT (auth))
02271 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02272 else
02273 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02274 }
02275 else
02276 {
02277 return _dbus_string_copy (plaintext, 0, encoded,
02278 _dbus_string_get_length (encoded));
02279 }
02280 }
02281
02290 dbus_bool_t
02291 _dbus_auth_needs_decoding (DBusAuth *auth)
02292 {
02293 if (auth->state != &common_state_authenticated)
02294 return FALSE;
02295
02296 if (auth->mech != NULL)
02297 {
02298 if (DBUS_AUTH_IS_CLIENT (auth))
02299 return auth->mech->client_decode_func != NULL;
02300 else
02301 return auth->mech->server_decode_func != NULL;
02302 }
02303 else
02304 return FALSE;
02305 }
02306
02307
02321 dbus_bool_t
02322 _dbus_auth_decode_data (DBusAuth *auth,
02323 const DBusString *encoded,
02324 DBusString *plaintext)
02325 {
02326 _dbus_assert (plaintext != encoded);
02327
02328 if (auth->state != &common_state_authenticated)
02329 return FALSE;
02330
02331 if (_dbus_auth_needs_decoding (auth))
02332 {
02333 if (DBUS_AUTH_IS_CLIENT (auth))
02334 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02335 else
02336 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02337 }
02338 else
02339 {
02340 return _dbus_string_copy (encoded, 0, plaintext,
02341 _dbus_string_get_length (plaintext));
02342 }
02343 }
02344
02352 void
02353 _dbus_auth_set_credentials (DBusAuth *auth,
02354 const DBusCredentials *credentials)
02355 {
02356 auth->credentials = *credentials;
02357 }
02358
02366 void
02367 _dbus_auth_get_identity (DBusAuth *auth,
02368 DBusCredentials *credentials)
02369 {
02370 if (auth->state == &common_state_authenticated)
02371 *credentials = auth->authorized_identity;
02372 else
02373 _dbus_credentials_clear (credentials);
02374 }
02375
02384 dbus_bool_t
02385 _dbus_auth_set_context (DBusAuth *auth,
02386 const DBusString *context)
02387 {
02388 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02389 &auth->context, 0, _dbus_string_get_length (context));
02390 }
02391
02394 #ifdef DBUS_BUILD_TESTS
02395 #include "dbus-test.h"
02396 #include "dbus-auth-script.h"
02397 #include <stdio.h>
02398
02399 static dbus_bool_t
02400 process_test_subdir (const DBusString *test_base_dir,
02401 const char *subdir)
02402 {
02403 DBusString test_directory;
02404 DBusString filename;
02405 DBusDirIter *dir;
02406 dbus_bool_t retval;
02407 DBusError error;
02408
02409 retval = FALSE;
02410 dir = NULL;
02411
02412 if (!_dbus_string_init (&test_directory))
02413 _dbus_assert_not_reached ("didn't allocate test_directory\n");
02414
02415 _dbus_string_init_const (&filename, subdir);
02416
02417 if (!_dbus_string_copy (test_base_dir, 0,
02418 &test_directory, 0))
02419 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
02420
02421 if (!_dbus_concat_dir_and_file (&test_directory, &filename))
02422 _dbus_assert_not_reached ("couldn't allocate full path");
02423
02424 _dbus_string_free (&filename);
02425 if (!_dbus_string_init (&filename))
02426 _dbus_assert_not_reached ("didn't allocate filename string\n");
02427
02428 dbus_error_init (&error);
02429 dir = _dbus_directory_open (&test_directory, &error);
02430 if (dir == NULL)
02431 {
02432 _dbus_warn ("Could not open %s: %s\n",
02433 _dbus_string_get_const_data (&test_directory),
02434 error.message);
02435 dbus_error_free (&error);
02436 goto failed;
02437 }
02438
02439 printf ("Testing %s:\n", subdir);
02440
02441 next:
02442 while (_dbus_directory_get_next_file (dir, &filename, &error))
02443 {
02444 DBusString full_path;
02445
02446 if (!_dbus_string_init (&full_path))
02447 _dbus_assert_not_reached ("couldn't init string");
02448
02449 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
02450 _dbus_assert_not_reached ("couldn't copy dir to full_path");
02451
02452 if (!_dbus_concat_dir_and_file (&full_path, &filename))
02453 _dbus_assert_not_reached ("couldn't concat file to dir");
02454
02455 if (!_dbus_string_ends_with_c_str (&filename, ".auth-script"))
02456 {
02457 _dbus_verbose ("Skipping non-.auth-script file %s\n",
02458 _dbus_string_get_const_data (&filename));
02459 _dbus_string_free (&full_path);
02460 goto next;
02461 }
02462
02463 printf (" %s\n", _dbus_string_get_const_data (&filename));
02464
02465 if (!_dbus_auth_script_run (&full_path))
02466 {
02467 _dbus_string_free (&full_path);
02468 goto failed;
02469 }
02470 else
02471 _dbus_string_free (&full_path);
02472 }
02473
02474 if (dbus_error_is_set (&error))
02475 {
02476 _dbus_warn ("Could not get next file in %s: %s\n",
02477 _dbus_string_get_const_data (&test_directory), error.message);
02478 dbus_error_free (&error);
02479 goto failed;
02480 }
02481
02482 retval = TRUE;
02483
02484 failed:
02485
02486 if (dir)
02487 _dbus_directory_close (dir);
02488 _dbus_string_free (&test_directory);
02489 _dbus_string_free (&filename);
02490
02491 return retval;
02492 }
02493
02494 static dbus_bool_t
02495 process_test_dirs (const char *test_data_dir)
02496 {
02497 DBusString test_directory;
02498 dbus_bool_t retval;
02499
02500 retval = FALSE;
02501
02502 _dbus_string_init_const (&test_directory, test_data_dir);
02503
02504 if (!process_test_subdir (&test_directory, "auth"))
02505 goto failed;
02506
02507 retval = TRUE;
02508
02509 failed:
02510
02511 _dbus_string_free (&test_directory);
02512
02513 return retval;
02514 }
02515
02516 dbus_bool_t
02517 _dbus_auth_test (const char *test_data_dir)
02518 {
02519
02520 if (test_data_dir == NULL)
02521 return TRUE;
02522
02523 if (!process_test_dirs (test_data_dir))
02524 return FALSE;
02525
02526 return TRUE;
02527 }
02528
02529 #endif