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-protocol.h"
00030 #include "dbus-userdb.h"
00031
00068 typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth,
00069 DBusString *response);
00070
00075 typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth,
00076 const DBusString *data);
00077
00081 typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth,
00082 const DBusString *data,
00083 DBusString *encoded);
00084
00088 typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
00089 const DBusString *data,
00090 DBusString *decoded);
00091
00095 typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth);
00096
00100 typedef struct
00101 {
00102 const char *mechanism;
00103 DBusAuthDataFunction server_data_func;
00104 DBusAuthEncodeFunction server_encode_func;
00105 DBusAuthDecodeFunction server_decode_func;
00106 DBusAuthShutdownFunction server_shutdown_func;
00107 DBusInitialResponseFunction client_initial_response_func;
00108 DBusAuthDataFunction client_data_func;
00109 DBusAuthEncodeFunction client_encode_func;
00110 DBusAuthDecodeFunction client_decode_func;
00111 DBusAuthShutdownFunction client_shutdown_func;
00112 } DBusAuthMechanismHandler;
00113
00117 typedef enum {
00118 DBUS_AUTH_COMMAND_AUTH,
00119 DBUS_AUTH_COMMAND_CANCEL,
00120 DBUS_AUTH_COMMAND_DATA,
00121 DBUS_AUTH_COMMAND_BEGIN,
00122 DBUS_AUTH_COMMAND_REJECTED,
00123 DBUS_AUTH_COMMAND_OK,
00124 DBUS_AUTH_COMMAND_ERROR,
00125 DBUS_AUTH_COMMAND_UNKNOWN
00126 } DBusAuthCommand;
00127
00133 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth,
00134 DBusAuthCommand command,
00135 const DBusString *args);
00136
00140 typedef struct
00141 {
00142 const char *name;
00143 DBusAuthStateFunction handler;
00144 } DBusAuthStateData;
00145
00149 struct DBusAuth
00150 {
00151 int refcount;
00152 const char *side;
00154 DBusString incoming;
00155 DBusString outgoing;
00157 const DBusAuthStateData *state;
00159 const DBusAuthMechanismHandler *mech;
00161 DBusString identity;
00165 DBusCredentials credentials;
00169 DBusCredentials authorized_identity;
00171 DBusCredentials desired_identity;
00173 DBusString context;
00174 DBusKeyring *keyring;
00175 int cookie_id;
00176 DBusString challenge;
00178 char **allowed_mechs;
00182 unsigned int needed_memory : 1;
00185 unsigned int already_got_mechanisms : 1;
00186 unsigned int already_asked_for_initial_response : 1;
00187 unsigned int buffer_outstanding : 1;
00188 };
00189
00193 typedef struct
00194 {
00195 DBusAuth base;
00197 DBusList *mechs_to_try;
00199 DBusString guid_from_server;
00201 } DBusAuthClient;
00202
00206 typedef struct
00207 {
00208 DBusAuth base;
00210 int failures;
00211 int max_failures;
00213 DBusString guid;
00215 } DBusAuthServer;
00216
00217 static void goto_state (DBusAuth *auth,
00218 const DBusAuthStateData *new_state);
00219 static dbus_bool_t send_auth (DBusAuth *auth,
00220 const DBusAuthMechanismHandler *mech);
00221 static dbus_bool_t send_data (DBusAuth *auth,
00222 DBusString *data);
00223 static dbus_bool_t send_rejected (DBusAuth *auth);
00224 static dbus_bool_t send_error (DBusAuth *auth,
00225 const char *message);
00226 static dbus_bool_t send_ok (DBusAuth *auth);
00227 static dbus_bool_t send_begin (DBusAuth *auth,
00228 const DBusString *args_from_ok);
00229 static dbus_bool_t send_cancel (DBusAuth *auth);
00230
00235 static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth,
00236 DBusAuthCommand command,
00237 const DBusString *args);
00238 static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth,
00239 DBusAuthCommand command,
00240 const DBusString *args);
00241 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth,
00242 DBusAuthCommand command,
00243 const DBusString *args);
00244
00245 static const DBusAuthStateData server_state_waiting_for_auth = {
00246 "WaitingForAuth", handle_server_state_waiting_for_auth
00247 };
00248 static const DBusAuthStateData server_state_waiting_for_data = {
00249 "WaitingForData", handle_server_state_waiting_for_data
00250 };
00251 static const DBusAuthStateData server_state_waiting_for_begin = {
00252 "WaitingForBegin", handle_server_state_waiting_for_begin
00253 };
00254
00259 static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth,
00260 DBusAuthCommand command,
00261 const DBusString *args);
00262 static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth,
00263 DBusAuthCommand command,
00264 const DBusString *args);
00265 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth,
00266 DBusAuthCommand command,
00267 const DBusString *args);
00268
00269 static const DBusAuthStateData client_state_need_send_auth = {
00270 "NeedSendAuth", NULL
00271 };
00272 static const DBusAuthStateData client_state_waiting_for_data = {
00273 "WaitingForData", handle_client_state_waiting_for_data
00274 };
00275 static const DBusAuthStateData client_state_waiting_for_ok = {
00276 "WaitingForOK", handle_client_state_waiting_for_ok
00277 };
00278 static const DBusAuthStateData client_state_waiting_for_reject = {
00279 "WaitingForReject", handle_client_state_waiting_for_reject
00280 };
00281
00286 static const DBusAuthStateData common_state_authenticated = {
00287 "Authenticated", NULL
00288 };
00289
00290 static const DBusAuthStateData common_state_need_disconnect = {
00291 "NeedDisconnect", NULL
00292 };
00293
00294 static const char auth_side_client[] = "client";
00295 static const char auth_side_server[] = "server";
00300 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00301
00305 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00306
00310 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
00311
00315 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
00316
00322 #define DBUS_AUTH_NAME(auth) ((auth)->side)
00323
00324 static DBusAuth*
00325 _dbus_auth_new (int size)
00326 {
00327 DBusAuth *auth;
00328
00329 auth = dbus_malloc0 (size);
00330 if (auth == NULL)
00331 return NULL;
00332
00333 auth->refcount = 1;
00334
00335 _dbus_credentials_clear (&auth->credentials);
00336 _dbus_credentials_clear (&auth->authorized_identity);
00337 _dbus_credentials_clear (&auth->desired_identity);
00338
00339 auth->keyring = NULL;
00340 auth->cookie_id = -1;
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 if (!_dbus_string_init (&auth->incoming))
00351 goto enomem_0;
00352
00353 if (!_dbus_string_init (&auth->outgoing))
00354 goto enomem_1;
00355
00356 if (!_dbus_string_init (&auth->identity))
00357 goto enomem_2;
00358
00359 if (!_dbus_string_init (&auth->context))
00360 goto enomem_3;
00361
00362 if (!_dbus_string_init (&auth->challenge))
00363 goto enomem_4;
00364
00365
00366 if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
00367 goto enomem_5;
00368
00369 return auth;
00370
00371 enomem_5:
00372 _dbus_string_free (&auth->challenge);
00373 enomem_4:
00374 _dbus_string_free (&auth->context);
00375 enomem_3:
00376 _dbus_string_free (&auth->identity);
00377 enomem_2:
00378 _dbus_string_free (&auth->outgoing);
00379 enomem_1:
00380 _dbus_string_free (&auth->incoming);
00381 enomem_0:
00382 dbus_free (auth);
00383 return NULL;
00384 }
00385
00386 static void
00387 shutdown_mech (DBusAuth *auth)
00388 {
00389
00390 auth->already_asked_for_initial_response = FALSE;
00391 _dbus_string_set_length (&auth->identity, 0);
00392
00393 _dbus_credentials_clear (&auth->authorized_identity);
00394 _dbus_credentials_clear (&auth->desired_identity);
00395
00396 if (auth->mech != NULL)
00397 {
00398 _dbus_verbose ("%s: Shutting down mechanism %s\n",
00399 DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00400
00401 if (DBUS_AUTH_IS_CLIENT (auth))
00402 (* auth->mech->client_shutdown_func) (auth);
00403 else
00404 (* auth->mech->server_shutdown_func) (auth);
00405
00406 auth->mech = NULL;
00407 }
00408 }
00409
00410
00411
00412
00413
00414 static dbus_bool_t
00415 sha1_compute_hash (DBusAuth *auth,
00416 int cookie_id,
00417 const DBusString *server_challenge,
00418 const DBusString *client_challenge,
00419 DBusString *hash)
00420 {
00421 DBusString cookie;
00422 DBusString to_hash;
00423 dbus_bool_t retval;
00424
00425 _dbus_assert (auth->keyring != NULL);
00426
00427 retval = FALSE;
00428
00429 if (!_dbus_string_init (&cookie))
00430 return FALSE;
00431
00432 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
00433 &cookie))
00434 goto out_0;
00435
00436 if (_dbus_string_get_length (&cookie) == 0)
00437 {
00438 retval = TRUE;
00439 goto out_0;
00440 }
00441
00442 if (!_dbus_string_init (&to_hash))
00443 goto out_0;
00444
00445 if (!_dbus_string_copy (server_challenge, 0,
00446 &to_hash, _dbus_string_get_length (&to_hash)))
00447 goto out_1;
00448
00449 if (!_dbus_string_append (&to_hash, ":"))
00450 goto out_1;
00451
00452 if (!_dbus_string_copy (client_challenge, 0,
00453 &to_hash, _dbus_string_get_length (&to_hash)))
00454 goto out_1;
00455
00456 if (!_dbus_string_append (&to_hash, ":"))
00457 goto out_1;
00458
00459 if (!_dbus_string_copy (&cookie, 0,
00460 &to_hash, _dbus_string_get_length (&to_hash)))
00461 goto out_1;
00462
00463 if (!_dbus_sha_compute (&to_hash, hash))
00464 goto out_1;
00465
00466 retval = TRUE;
00467
00468 out_1:
00469 _dbus_string_zero (&to_hash);
00470 _dbus_string_free (&to_hash);
00471 out_0:
00472 _dbus_string_zero (&cookie);
00473 _dbus_string_free (&cookie);
00474 return retval;
00475 }
00476
00481 #define N_CHALLENGE_BYTES (128/8)
00482
00483 static dbus_bool_t
00484 sha1_handle_first_client_response (DBusAuth *auth,
00485 const DBusString *data)
00486 {
00487
00488
00489
00490 DBusString tmp;
00491 DBusString tmp2;
00492 dbus_bool_t retval;
00493 DBusError error;
00494
00495 retval = FALSE;
00496
00497 _dbus_string_set_length (&auth->challenge, 0);
00498
00499 if (_dbus_string_get_length (data) > 0)
00500 {
00501 if (_dbus_string_get_length (&auth->identity) > 0)
00502 {
00503
00504 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00505 DBUS_AUTH_NAME (auth));
00506 return send_rejected (auth);
00507 }
00508 else
00509 {
00510
00511 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00512 return FALSE;
00513 }
00514 }
00515
00516 if (!_dbus_credentials_from_username (data, &auth->desired_identity))
00517 {
00518 _dbus_verbose ("%s: Did not get a valid username from client\n",
00519 DBUS_AUTH_NAME (auth));
00520 return send_rejected (auth);
00521 }
00522
00523 if (!_dbus_string_init (&tmp))
00524 return FALSE;
00525
00526 if (!_dbus_string_init (&tmp2))
00527 {
00528 _dbus_string_free (&tmp);
00529 return FALSE;
00530 }
00531
00532
00533
00534
00535
00536 if (auth->keyring &&
00537 !_dbus_keyring_is_for_user (auth->keyring,
00538 data))
00539 {
00540 _dbus_keyring_unref (auth->keyring);
00541 auth->keyring = NULL;
00542 }
00543
00544 if (auth->keyring == NULL)
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_parse_uid (&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.pid = auth->credentials.pid;
01052 auth->authorized_identity.uid = auth->desired_identity.uid;
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 int orig_len;
01330
01331 orig_len = _dbus_string_get_length (&auth->outgoing);
01332
01333 if (_dbus_string_append (&auth->outgoing, "OK ") &&
01334 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01335 0,
01336 &auth->outgoing,
01337 _dbus_string_get_length (&auth->outgoing)) &&
01338 _dbus_string_append (&auth->outgoing, "\r\n"))
01339 {
01340 goto_state (auth, &server_state_waiting_for_begin);
01341 return TRUE;
01342 }
01343 else
01344 {
01345 _dbus_string_set_length (&auth->outgoing, orig_len);
01346 return FALSE;
01347 }
01348 }
01349
01350 static dbus_bool_t
01351 send_begin (DBusAuth *auth,
01352 const DBusString *args_from_ok)
01353 {
01354 int end_of_hex;
01355
01356
01357 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01358
01359
01360
01361 end_of_hex = 0;
01362 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01363 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01364 return FALSE;
01365
01366
01367 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01368
01369 if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01370 end_of_hex == 0)
01371 {
01372 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01373 end_of_hex, _dbus_string_get_length (args_from_ok));
01374 goto_state (auth, &common_state_need_disconnect);
01375 return TRUE;
01376 }
01377
01378 if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01379 _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01380 {
01381 _dbus_verbose ("Got GUID '%s' from the server\n",
01382 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01383
01384 goto_state (auth, &common_state_authenticated);
01385 return TRUE;
01386 }
01387 else
01388 {
01389 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01390 return FALSE;
01391 }
01392 }
01393
01394 static dbus_bool_t
01395 send_cancel (DBusAuth *auth)
01396 {
01397 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01398 {
01399 goto_state (auth, &client_state_waiting_for_reject);
01400 return TRUE;
01401 }
01402 else
01403 return FALSE;
01404 }
01405
01406 static dbus_bool_t
01407 process_data (DBusAuth *auth,
01408 const DBusString *args,
01409 DBusAuthDataFunction data_func)
01410 {
01411 int end;
01412 DBusString decoded;
01413
01414 if (!_dbus_string_init (&decoded))
01415 return FALSE;
01416
01417 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01418 {
01419 _dbus_string_free (&decoded);
01420 return FALSE;
01421 }
01422
01423 if (_dbus_string_get_length (args) != end)
01424 {
01425 _dbus_string_free (&decoded);
01426 if (!send_error (auth, "Invalid hex encoding"))
01427 return FALSE;
01428
01429 return TRUE;
01430 }
01431
01432 #ifdef DBUS_ENABLE_VERBOSE_MODE
01433 if (_dbus_string_validate_ascii (&decoded, 0,
01434 _dbus_string_get_length (&decoded)))
01435 _dbus_verbose ("%s: data: '%s'\n",
01436 DBUS_AUTH_NAME (auth),
01437 _dbus_string_get_const_data (&decoded));
01438 #endif
01439
01440 if (!(* data_func) (auth, &decoded))
01441 {
01442 _dbus_string_free (&decoded);
01443 return FALSE;
01444 }
01445
01446 _dbus_string_free (&decoded);
01447 return TRUE;
01448 }
01449
01450 static dbus_bool_t
01451 handle_auth (DBusAuth *auth, const DBusString *args)
01452 {
01453 if (_dbus_string_get_length (args) == 0)
01454 {
01455
01456 if (!send_rejected (auth))
01457 return FALSE;
01458
01459 return TRUE;
01460 }
01461 else
01462 {
01463 int i;
01464 DBusString mech;
01465 DBusString hex_response;
01466
01467 _dbus_string_find_blank (args, 0, &i);
01468
01469 if (!_dbus_string_init (&mech))
01470 return FALSE;
01471
01472 if (!_dbus_string_init (&hex_response))
01473 {
01474 _dbus_string_free (&mech);
01475 return FALSE;
01476 }
01477
01478 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01479 goto failed;
01480
01481 _dbus_string_skip_blank (args, i, &i);
01482 if (!_dbus_string_copy (args, i, &hex_response, 0))
01483 goto failed;
01484
01485 auth->mech = find_mech (&mech, auth->allowed_mechs);
01486 if (auth->mech != NULL)
01487 {
01488 _dbus_verbose ("%s: Trying mechanism %s\n",
01489 DBUS_AUTH_NAME (auth),
01490 auth->mech->mechanism);
01491
01492 if (!process_data (auth, &hex_response,
01493 auth->mech->server_data_func))
01494 goto failed;
01495 }
01496 else
01497 {
01498
01499 _dbus_verbose ("%s: Unsupported mechanism %s\n",
01500 DBUS_AUTH_NAME (auth),
01501 _dbus_string_get_const_data (&mech));
01502
01503 if (!send_rejected (auth))
01504 goto failed;
01505 }
01506
01507 _dbus_string_free (&mech);
01508 _dbus_string_free (&hex_response);
01509
01510 return TRUE;
01511
01512 failed:
01513 auth->mech = NULL;
01514 _dbus_string_free (&mech);
01515 _dbus_string_free (&hex_response);
01516 return FALSE;
01517 }
01518 }
01519
01520 static dbus_bool_t
01521 handle_server_state_waiting_for_auth (DBusAuth *auth,
01522 DBusAuthCommand command,
01523 const DBusString *args)
01524 {
01525 switch (command)
01526 {
01527 case DBUS_AUTH_COMMAND_AUTH:
01528 return handle_auth (auth, args);
01529
01530 case DBUS_AUTH_COMMAND_CANCEL:
01531 case DBUS_AUTH_COMMAND_DATA:
01532 return send_error (auth, "Not currently in an auth conversation");
01533
01534 case DBUS_AUTH_COMMAND_BEGIN:
01535 goto_state (auth, &common_state_need_disconnect);
01536 return TRUE;
01537
01538 case DBUS_AUTH_COMMAND_ERROR:
01539 return send_rejected (auth);
01540
01541 case DBUS_AUTH_COMMAND_REJECTED:
01542 case DBUS_AUTH_COMMAND_OK:
01543 case DBUS_AUTH_COMMAND_UNKNOWN:
01544 default:
01545 return send_error (auth, "Unknown command");
01546 }
01547 }
01548
01549 static dbus_bool_t
01550 handle_server_state_waiting_for_data (DBusAuth *auth,
01551 DBusAuthCommand command,
01552 const DBusString *args)
01553 {
01554 switch (command)
01555 {
01556 case DBUS_AUTH_COMMAND_AUTH:
01557 return send_error (auth, "Sent AUTH while another AUTH in progress");
01558
01559 case DBUS_AUTH_COMMAND_CANCEL:
01560 case DBUS_AUTH_COMMAND_ERROR:
01561 return send_rejected (auth);
01562
01563 case DBUS_AUTH_COMMAND_DATA:
01564 return process_data (auth, args, auth->mech->server_data_func);
01565
01566 case DBUS_AUTH_COMMAND_BEGIN:
01567 goto_state (auth, &common_state_need_disconnect);
01568 return TRUE;
01569
01570 case DBUS_AUTH_COMMAND_REJECTED:
01571 case DBUS_AUTH_COMMAND_OK:
01572 case DBUS_AUTH_COMMAND_UNKNOWN:
01573 default:
01574 return send_error (auth, "Unknown command");
01575 }
01576 }
01577
01578 static dbus_bool_t
01579 handle_server_state_waiting_for_begin (DBusAuth *auth,
01580 DBusAuthCommand command,
01581 const DBusString *args)
01582 {
01583 switch (command)
01584 {
01585 case DBUS_AUTH_COMMAND_AUTH:
01586 return send_error (auth, "Sent AUTH while expecting BEGIN");
01587
01588 case DBUS_AUTH_COMMAND_DATA:
01589 return send_error (auth, "Sent DATA while expecting BEGIN");
01590
01591 case DBUS_AUTH_COMMAND_BEGIN:
01592 goto_state (auth, &common_state_authenticated);
01593 return TRUE;
01594
01595 case DBUS_AUTH_COMMAND_REJECTED:
01596 case DBUS_AUTH_COMMAND_OK:
01597 case DBUS_AUTH_COMMAND_UNKNOWN:
01598 default:
01599 return send_error (auth, "Unknown command");
01600
01601 case DBUS_AUTH_COMMAND_CANCEL:
01602 case DBUS_AUTH_COMMAND_ERROR:
01603 return send_rejected (auth);
01604 }
01605 }
01606
01607
01608 static dbus_bool_t
01609 get_word (const DBusString *str,
01610 int *start,
01611 DBusString *word)
01612 {
01613 int i;
01614
01615 _dbus_string_skip_blank (str, *start, start);
01616 _dbus_string_find_blank (str, *start, &i);
01617
01618 if (i > *start)
01619 {
01620 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01621 return FALSE;
01622
01623 *start = i;
01624 }
01625
01626 return TRUE;
01627 }
01628
01629 static dbus_bool_t
01630 record_mechanisms (DBusAuth *auth,
01631 const DBusString *args)
01632 {
01633 int next;
01634 int len;
01635
01636 if (auth->already_got_mechanisms)
01637 return TRUE;
01638
01639 len = _dbus_string_get_length (args);
01640
01641 next = 0;
01642 while (next < len)
01643 {
01644 DBusString m;
01645 const DBusAuthMechanismHandler *mech;
01646
01647 if (!_dbus_string_init (&m))
01648 goto nomem;
01649
01650 if (!get_word (args, &next, &m))
01651 {
01652 _dbus_string_free (&m);
01653 goto nomem;
01654 }
01655
01656 mech = find_mech (&m, auth->allowed_mechs);
01657
01658 if (mech != NULL)
01659 {
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 if (mech != &all_mechanisms[0])
01670 {
01671 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
01672 DBUS_AUTH_NAME (auth), mech->mechanism);
01673
01674 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01675 (void*) mech))
01676 {
01677 _dbus_string_free (&m);
01678 goto nomem;
01679 }
01680 }
01681 else
01682 {
01683 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
01684 DBUS_AUTH_NAME (auth), mech->mechanism);
01685 }
01686 }
01687 else
01688 {
01689 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01690 DBUS_AUTH_NAME (auth),
01691 _dbus_string_get_const_data (&m));
01692 }
01693
01694 _dbus_string_free (&m);
01695 }
01696
01697 auth->already_got_mechanisms = TRUE;
01698
01699 return TRUE;
01700
01701 nomem:
01702 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01703
01704 return FALSE;
01705 }
01706
01707 static dbus_bool_t
01708 process_rejected (DBusAuth *auth, const DBusString *args)
01709 {
01710 const DBusAuthMechanismHandler *mech;
01711 DBusAuthClient *client;
01712
01713 client = DBUS_AUTH_CLIENT (auth);
01714
01715 if (!auth->already_got_mechanisms)
01716 {
01717 if (!record_mechanisms (auth, args))
01718 return FALSE;
01719 }
01720
01721 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01722 {
01723 mech = client->mechs_to_try->data;
01724
01725 if (!send_auth (auth, mech))
01726 return FALSE;
01727
01728 _dbus_list_pop_first (&client->mechs_to_try);
01729
01730 _dbus_verbose ("%s: Trying mechanism %s\n",
01731 DBUS_AUTH_NAME (auth),
01732 mech->mechanism);
01733 }
01734 else
01735 {
01736
01737 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01738 DBUS_AUTH_NAME (auth));
01739 goto_state (auth, &common_state_need_disconnect);
01740 }
01741
01742 return TRUE;
01743 }
01744
01745
01746 static dbus_bool_t
01747 handle_client_state_waiting_for_data (DBusAuth *auth,
01748 DBusAuthCommand command,
01749 const DBusString *args)
01750 {
01751 _dbus_assert (auth->mech != NULL);
01752
01753 switch (command)
01754 {
01755 case DBUS_AUTH_COMMAND_DATA:
01756 return process_data (auth, args, auth->mech->client_data_func);
01757
01758 case DBUS_AUTH_COMMAND_REJECTED:
01759 return process_rejected (auth, args);
01760
01761 case DBUS_AUTH_COMMAND_OK:
01762 return send_begin (auth, args);
01763
01764 case DBUS_AUTH_COMMAND_ERROR:
01765 return send_cancel (auth);
01766
01767 case DBUS_AUTH_COMMAND_AUTH:
01768 case DBUS_AUTH_COMMAND_CANCEL:
01769 case DBUS_AUTH_COMMAND_BEGIN:
01770 case DBUS_AUTH_COMMAND_UNKNOWN:
01771 default:
01772 return send_error (auth, "Unknown command");
01773 }
01774 }
01775
01776 static dbus_bool_t
01777 handle_client_state_waiting_for_ok (DBusAuth *auth,
01778 DBusAuthCommand command,
01779 const DBusString *args)
01780 {
01781 switch (command)
01782 {
01783 case DBUS_AUTH_COMMAND_REJECTED:
01784 return process_rejected (auth, args);
01785
01786 case DBUS_AUTH_COMMAND_OK:
01787 return send_begin (auth, args);
01788
01789 case DBUS_AUTH_COMMAND_DATA:
01790 case DBUS_AUTH_COMMAND_ERROR:
01791 return send_cancel (auth);
01792
01793 case DBUS_AUTH_COMMAND_AUTH:
01794 case DBUS_AUTH_COMMAND_CANCEL:
01795 case DBUS_AUTH_COMMAND_BEGIN:
01796 case DBUS_AUTH_COMMAND_UNKNOWN:
01797 default:
01798 return send_error (auth, "Unknown command");
01799 }
01800 }
01801
01802 static dbus_bool_t
01803 handle_client_state_waiting_for_reject (DBusAuth *auth,
01804 DBusAuthCommand command,
01805 const DBusString *args)
01806 {
01807 switch (command)
01808 {
01809 case DBUS_AUTH_COMMAND_REJECTED:
01810 return process_rejected (auth, args);
01811
01812 case DBUS_AUTH_COMMAND_AUTH:
01813 case DBUS_AUTH_COMMAND_CANCEL:
01814 case DBUS_AUTH_COMMAND_DATA:
01815 case DBUS_AUTH_COMMAND_BEGIN:
01816 case DBUS_AUTH_COMMAND_OK:
01817 case DBUS_AUTH_COMMAND_ERROR:
01818 case DBUS_AUTH_COMMAND_UNKNOWN:
01819 default:
01820 goto_state (auth, &common_state_need_disconnect);
01821 return TRUE;
01822 }
01823 }
01824
01828 typedef struct {
01829 const char *name;
01830 DBusAuthCommand command;
01831 } DBusAuthCommandName;
01832
01833 static const DBusAuthCommandName auth_command_names[] = {
01834 { "AUTH", DBUS_AUTH_COMMAND_AUTH },
01835 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
01836 { "DATA", DBUS_AUTH_COMMAND_DATA },
01837 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
01838 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
01839 { "OK", DBUS_AUTH_COMMAND_OK },
01840 { "ERROR", DBUS_AUTH_COMMAND_ERROR }
01841 };
01842
01843 static DBusAuthCommand
01844 lookup_command_from_name (DBusString *command)
01845 {
01846 int i;
01847
01848 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
01849 {
01850 if (_dbus_string_equal_c_str (command,
01851 auth_command_names[i].name))
01852 return auth_command_names[i].command;
01853 }
01854
01855 return DBUS_AUTH_COMMAND_UNKNOWN;
01856 }
01857
01858 static void
01859 goto_state (DBusAuth *auth, const DBusAuthStateData *state)
01860 {
01861 _dbus_verbose ("%s: going from state %s to state %s\n",
01862 DBUS_AUTH_NAME (auth),
01863 auth->state->name,
01864 state->name);
01865
01866 auth->state = state;
01867 }
01868
01869
01870 static dbus_bool_t
01871 process_command (DBusAuth *auth)
01872 {
01873 DBusAuthCommand command;
01874 DBusString line;
01875 DBusString args;
01876 int eol;
01877 int i, j;
01878 dbus_bool_t retval;
01879
01880
01881
01882 retval = FALSE;
01883
01884 eol = 0;
01885 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
01886 return FALSE;
01887
01888 if (!_dbus_string_init (&line))
01889 {
01890 auth->needed_memory = TRUE;
01891 return FALSE;
01892 }
01893
01894 if (!_dbus_string_init (&args))
01895 {
01896 _dbus_string_free (&line);
01897 auth->needed_memory = TRUE;
01898 return FALSE;
01899 }
01900
01901 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
01902 goto out;
01903
01904 if (!_dbus_string_validate_ascii (&line, 0,
01905 _dbus_string_get_length (&line)))
01906 {
01907 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
01908 DBUS_AUTH_NAME (auth));
01909 if (!send_error (auth, "Command contained non-ASCII"))
01910 goto out;
01911 else
01912 goto next_command;
01913 }
01914
01915 _dbus_verbose ("%s: got command \"%s\"\n",
01916 DBUS_AUTH_NAME (auth),
01917 _dbus_string_get_const_data (&line));
01918
01919 _dbus_string_find_blank (&line, 0, &i);
01920 _dbus_string_skip_blank (&line, i, &j);
01921
01922 if (j > i)
01923 _dbus_string_delete (&line, i, j - i);
01924
01925 if (!_dbus_string_move (&line, i, &args, 0))
01926 goto out;
01927
01928
01929
01930
01931
01932 command = lookup_command_from_name (&line);
01933 if (!(* auth->state->handler) (auth, command, &args))
01934 goto out;
01935
01936 next_command:
01937
01938
01939
01940
01941
01942 _dbus_string_delete (&auth->incoming, 0, eol);
01943
01944
01945 _dbus_string_delete (&auth->incoming, 0, 2);
01946
01947 retval = TRUE;
01948
01949 out:
01950 _dbus_string_free (&args);
01951 _dbus_string_free (&line);
01952
01953 if (!retval)
01954 auth->needed_memory = TRUE;
01955 else
01956 auth->needed_memory = FALSE;
01957
01958 return retval;
01959 }
01960
01961
01976 DBusAuth*
01977 _dbus_auth_server_new (const DBusString *guid)
01978 {
01979 DBusAuth *auth;
01980 DBusAuthServer *server_auth;
01981 DBusString guid_copy;
01982
01983 if (!_dbus_string_init (&guid_copy))
01984 return NULL;
01985
01986 if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
01987 {
01988 _dbus_string_free (&guid_copy);
01989 return NULL;
01990 }
01991
01992 auth = _dbus_auth_new (sizeof (DBusAuthServer));
01993 if (auth == NULL)
01994 {
01995 _dbus_string_free (&guid_copy);
01996 return NULL;
01997 }
01998
01999 auth->side = auth_side_server;
02000 auth->state = &server_state_waiting_for_auth;
02001
02002 server_auth = DBUS_AUTH_SERVER (auth);
02003
02004 server_auth->guid = guid_copy;
02005
02006
02007
02008
02009 server_auth->failures = 0;
02010 server_auth->max_failures = 6;
02011
02012 return auth;
02013 }
02014
02022 DBusAuth*
02023 _dbus_auth_client_new (void)
02024 {
02025 DBusAuth *auth;
02026 DBusString guid_str;
02027
02028 if (!_dbus_string_init (&guid_str))
02029 return NULL;
02030
02031 auth = _dbus_auth_new (sizeof (DBusAuthClient));
02032 if (auth == NULL)
02033 {
02034 _dbus_string_free (&guid_str);
02035 return NULL;
02036 }
02037
02038 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02039
02040 auth->side = auth_side_client;
02041 auth->state = &client_state_need_send_auth;
02042
02043
02044
02045 if (!send_auth (auth, &all_mechanisms[0]))
02046 {
02047 _dbus_auth_unref (auth);
02048 return NULL;
02049 }
02050
02051 return auth;
02052 }
02053
02060 DBusAuth *
02061 _dbus_auth_ref (DBusAuth *auth)
02062 {
02063 _dbus_assert (auth != NULL);
02064
02065 auth->refcount += 1;
02066
02067 return auth;
02068 }
02069
02075 void
02076 _dbus_auth_unref (DBusAuth *auth)
02077 {
02078 _dbus_assert (auth != NULL);
02079 _dbus_assert (auth->refcount > 0);
02080
02081 auth->refcount -= 1;
02082 if (auth->refcount == 0)
02083 {
02084 shutdown_mech (auth);
02085
02086 if (DBUS_AUTH_IS_CLIENT (auth))
02087 {
02088 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02089 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02090 }
02091 else
02092 {
02093 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02094
02095 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02096 }
02097
02098 if (auth->keyring)
02099 _dbus_keyring_unref (auth->keyring);
02100
02101 _dbus_string_free (&auth->context);
02102 _dbus_string_free (&auth->challenge);
02103 _dbus_string_free (&auth->identity);
02104 _dbus_string_free (&auth->incoming);
02105 _dbus_string_free (&auth->outgoing);
02106
02107 dbus_free_string_array (auth->allowed_mechs);
02108
02109 dbus_free (auth);
02110 }
02111 }
02112
02121 dbus_bool_t
02122 _dbus_auth_set_mechanisms (DBusAuth *auth,
02123 const char **mechanisms)
02124 {
02125 char **copy;
02126
02127 if (mechanisms != NULL)
02128 {
02129 copy = _dbus_dup_string_array (mechanisms);
02130 if (copy == NULL)
02131 return FALSE;
02132 }
02133 else
02134 copy = NULL;
02135
02136 dbus_free_string_array (auth->allowed_mechs);
02137
02138 auth->allowed_mechs = copy;
02139
02140 return TRUE;
02141 }
02142
02147 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02148
02156 DBusAuthState
02157 _dbus_auth_do_work (DBusAuth *auth)
02158 {
02159 auth->needed_memory = FALSE;
02160
02161
02162 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02163
02164 do
02165 {
02166 if (DBUS_AUTH_IN_END_STATE (auth))
02167 break;
02168
02169 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02170 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02171 {
02172 goto_state (auth, &common_state_need_disconnect);
02173 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02174 DBUS_AUTH_NAME (auth));
02175 break;
02176 }
02177 }
02178 while (process_command (auth));
02179
02180 if (auth->needed_memory)
02181 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02182 else if (_dbus_string_get_length (&auth->outgoing) > 0)
02183 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02184 else if (auth->state == &common_state_need_disconnect)
02185 return DBUS_AUTH_STATE_NEED_DISCONNECT;
02186 else if (auth->state == &common_state_authenticated)
02187 return DBUS_AUTH_STATE_AUTHENTICATED;
02188 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02189 }
02190
02200 dbus_bool_t
02201 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
02202 const DBusString **str)
02203 {
02204 _dbus_assert (auth != NULL);
02205 _dbus_assert (str != NULL);
02206
02207 *str = NULL;
02208
02209 if (_dbus_string_get_length (&auth->outgoing) == 0)
02210 return FALSE;
02211
02212 *str = &auth->outgoing;
02213
02214 return TRUE;
02215 }
02216
02225 void
02226 _dbus_auth_bytes_sent (DBusAuth *auth,
02227 int bytes_sent)
02228 {
02229 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02230 DBUS_AUTH_NAME (auth),
02231 bytes_sent,
02232 _dbus_string_get_const_data (&auth->outgoing));
02233
02234 _dbus_string_delete (&auth->outgoing,
02235 0, bytes_sent);
02236 }
02237
02245 void
02246 _dbus_auth_get_buffer (DBusAuth *auth,
02247 DBusString **buffer)
02248 {
02249 _dbus_assert (auth != NULL);
02250 _dbus_assert (!auth->buffer_outstanding);
02251
02252 *buffer = &auth->incoming;
02253
02254 auth->buffer_outstanding = TRUE;
02255 }
02256
02264 void
02265 _dbus_auth_return_buffer (DBusAuth *auth,
02266 DBusString *buffer,
02267 int bytes_read)
02268 {
02269 _dbus_assert (buffer == &auth->incoming);
02270 _dbus_assert (auth->buffer_outstanding);
02271
02272 auth->buffer_outstanding = FALSE;
02273 }
02274
02284 void
02285 _dbus_auth_get_unused_bytes (DBusAuth *auth,
02286 const DBusString **str)
02287 {
02288 if (!DBUS_AUTH_IN_END_STATE (auth))
02289 return;
02290
02291 *str = &auth->incoming;
02292 }
02293
02294
02301 void
02302 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02303 {
02304 if (!DBUS_AUTH_IN_END_STATE (auth))
02305 return;
02306
02307 _dbus_string_set_length (&auth->incoming, 0);
02308 }
02309
02318 dbus_bool_t
02319 _dbus_auth_needs_encoding (DBusAuth *auth)
02320 {
02321 if (auth->state != &common_state_authenticated)
02322 return FALSE;
02323
02324 if (auth->mech != NULL)
02325 {
02326 if (DBUS_AUTH_IS_CLIENT (auth))
02327 return auth->mech->client_encode_func != NULL;
02328 else
02329 return auth->mech->server_encode_func != NULL;
02330 }
02331 else
02332 return FALSE;
02333 }
02334
02345 dbus_bool_t
02346 _dbus_auth_encode_data (DBusAuth *auth,
02347 const DBusString *plaintext,
02348 DBusString *encoded)
02349 {
02350 _dbus_assert (plaintext != encoded);
02351
02352 if (auth->state != &common_state_authenticated)
02353 return FALSE;
02354
02355 if (_dbus_auth_needs_encoding (auth))
02356 {
02357 if (DBUS_AUTH_IS_CLIENT (auth))
02358 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02359 else
02360 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02361 }
02362 else
02363 {
02364 return _dbus_string_copy (plaintext, 0, encoded,
02365 _dbus_string_get_length (encoded));
02366 }
02367 }
02368
02377 dbus_bool_t
02378 _dbus_auth_needs_decoding (DBusAuth *auth)
02379 {
02380 if (auth->state != &common_state_authenticated)
02381 return FALSE;
02382
02383 if (auth->mech != NULL)
02384 {
02385 if (DBUS_AUTH_IS_CLIENT (auth))
02386 return auth->mech->client_decode_func != NULL;
02387 else
02388 return auth->mech->server_decode_func != NULL;
02389 }
02390 else
02391 return FALSE;
02392 }
02393
02394
02408 dbus_bool_t
02409 _dbus_auth_decode_data (DBusAuth *auth,
02410 const DBusString *encoded,
02411 DBusString *plaintext)
02412 {
02413 _dbus_assert (plaintext != encoded);
02414
02415 if (auth->state != &common_state_authenticated)
02416 return FALSE;
02417
02418 if (_dbus_auth_needs_decoding (auth))
02419 {
02420 if (DBUS_AUTH_IS_CLIENT (auth))
02421 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02422 else
02423 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02424 }
02425 else
02426 {
02427 return _dbus_string_copy (encoded, 0, plaintext,
02428 _dbus_string_get_length (plaintext));
02429 }
02430 }
02431
02439 void
02440 _dbus_auth_set_credentials (DBusAuth *auth,
02441 const DBusCredentials *credentials)
02442 {
02443 auth->credentials = *credentials;
02444 }
02445
02453 void
02454 _dbus_auth_get_identity (DBusAuth *auth,
02455 DBusCredentials *credentials)
02456 {
02457 if (auth->state == &common_state_authenticated)
02458 *credentials = auth->authorized_identity;
02459 else
02460 _dbus_credentials_clear (credentials);
02461 }
02462
02469 const char*
02470 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02471 {
02472 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02473
02474 if (auth->state == &common_state_authenticated)
02475 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02476 else
02477 return NULL;
02478 }
02479
02488 dbus_bool_t
02489 _dbus_auth_set_context (DBusAuth *auth,
02490 const DBusString *context)
02491 {
02492 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02493 &auth->context, 0, _dbus_string_get_length (context));
02494 }
02495
02498