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 DBusError error;
00547
00548 dbus_error_init (&error);
00549 auth->keyring = _dbus_keyring_new_homedir (data,
00550 &auth->context,
00551 &error);
00552
00553 if (auth->keyring == NULL)
00554 {
00555 if (dbus_error_has_name (&error,
00556 DBUS_ERROR_NO_MEMORY))
00557 {
00558 dbus_error_free (&error);
00559 goto out;
00560 }
00561 else
00562 {
00563 _DBUS_ASSERT_ERROR_IS_SET (&error);
00564 _dbus_verbose ("%s: Error loading keyring: %s\n",
00565 DBUS_AUTH_NAME (auth), error.message);
00566 if (send_rejected (auth))
00567 retval = TRUE;
00568 dbus_error_free (&error);
00569 goto out;
00570 }
00571 }
00572 else
00573 {
00574 _dbus_assert (!dbus_error_is_set (&error));
00575 }
00576 }
00577
00578 _dbus_assert (auth->keyring != NULL);
00579
00580 dbus_error_init (&error);
00581 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00582 if (auth->cookie_id < 0)
00583 {
00584 _DBUS_ASSERT_ERROR_IS_SET (&error);
00585 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00586 DBUS_AUTH_NAME (auth), error.message);
00587 if (send_rejected (auth))
00588 retval = TRUE;
00589 dbus_error_free (&error);
00590 goto out;
00591 }
00592 else
00593 {
00594 _dbus_assert (!dbus_error_is_set (&error));
00595 }
00596
00597 if (!_dbus_string_copy (&auth->context, 0,
00598 &tmp2, _dbus_string_get_length (&tmp2)))
00599 goto out;
00600
00601 if (!_dbus_string_append (&tmp2, " "))
00602 goto out;
00603
00604 if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00605 goto out;
00606
00607 if (!_dbus_string_append (&tmp2, " "))
00608 goto out;
00609
00610 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00611 goto out;
00612
00613 _dbus_string_set_length (&auth->challenge, 0);
00614 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00615 goto out;
00616
00617 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00618 _dbus_string_get_length (&tmp2)))
00619 goto out;
00620
00621 if (!send_data (auth, &tmp2))
00622 goto out;
00623
00624 goto_state (auth, &server_state_waiting_for_data);
00625 retval = TRUE;
00626
00627 out:
00628 _dbus_string_zero (&tmp);
00629 _dbus_string_free (&tmp);
00630 _dbus_string_zero (&tmp2);
00631 _dbus_string_free (&tmp2);
00632
00633 return retval;
00634 }
00635
00636 static dbus_bool_t
00637 sha1_handle_second_client_response (DBusAuth *auth,
00638 const DBusString *data)
00639 {
00640
00641
00642
00643
00644
00645 int i;
00646 DBusString client_challenge;
00647 DBusString client_hash;
00648 dbus_bool_t retval;
00649 DBusString correct_hash;
00650
00651 retval = FALSE;
00652
00653 if (!_dbus_string_find_blank (data, 0, &i))
00654 {
00655 _dbus_verbose ("%s: no space separator in client response\n",
00656 DBUS_AUTH_NAME (auth));
00657 return send_rejected (auth);
00658 }
00659
00660 if (!_dbus_string_init (&client_challenge))
00661 goto out_0;
00662
00663 if (!_dbus_string_init (&client_hash))
00664 goto out_1;
00665
00666 if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00667 0))
00668 goto out_2;
00669
00670 _dbus_string_skip_blank (data, i, &i);
00671
00672 if (!_dbus_string_copy_len (data, i,
00673 _dbus_string_get_length (data) - i,
00674 &client_hash,
00675 0))
00676 goto out_2;
00677
00678 if (_dbus_string_get_length (&client_challenge) == 0 ||
00679 _dbus_string_get_length (&client_hash) == 0)
00680 {
00681 _dbus_verbose ("%s: zero-length client challenge or hash\n",
00682 DBUS_AUTH_NAME (auth));
00683 if (send_rejected (auth))
00684 retval = TRUE;
00685 goto out_2;
00686 }
00687
00688 if (!_dbus_string_init (&correct_hash))
00689 goto out_2;
00690
00691 if (!sha1_compute_hash (auth, auth->cookie_id,
00692 &auth->challenge,
00693 &client_challenge,
00694 &correct_hash))
00695 goto out_3;
00696
00697
00698 if (_dbus_string_get_length (&correct_hash) == 0)
00699 {
00700 if (send_rejected (auth))
00701 retval = TRUE;
00702 goto out_3;
00703 }
00704
00705 if (!_dbus_string_equal (&client_hash, &correct_hash))
00706 {
00707 if (send_rejected (auth))
00708 retval = TRUE;
00709 goto out_3;
00710 }
00711
00712 if (!send_ok (auth))
00713 goto out_3;
00714
00715 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n",
00716 DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
00717
00718 auth->authorized_identity = auth->desired_identity;
00719 retval = TRUE;
00720
00721 out_3:
00722 _dbus_string_zero (&correct_hash);
00723 _dbus_string_free (&correct_hash);
00724 out_2:
00725 _dbus_string_zero (&client_hash);
00726 _dbus_string_free (&client_hash);
00727 out_1:
00728 _dbus_string_free (&client_challenge);
00729 out_0:
00730 return retval;
00731 }
00732
00733 static dbus_bool_t
00734 handle_server_data_cookie_sha1_mech (DBusAuth *auth,
00735 const DBusString *data)
00736 {
00737 if (auth->cookie_id < 0)
00738 return sha1_handle_first_client_response (auth, data);
00739 else
00740 return sha1_handle_second_client_response (auth, data);
00741 }
00742
00743 static void
00744 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00745 {
00746 auth->cookie_id = -1;
00747 _dbus_string_set_length (&auth->challenge, 0);
00748 }
00749
00750 static dbus_bool_t
00751 handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
00752 DBusString *response)
00753 {
00754 const DBusString *username;
00755 dbus_bool_t retval;
00756
00757 retval = FALSE;
00758
00759 if (!_dbus_username_from_current_process (&username))
00760 goto out_0;
00761
00762 if (!_dbus_string_hex_encode (username, 0,
00763 response,
00764 _dbus_string_get_length (response)))
00765 goto out_0;
00766
00767 retval = TRUE;
00768
00769 out_0:
00770 return retval;
00771 }
00772
00773 static dbus_bool_t
00774 handle_client_data_cookie_sha1_mech (DBusAuth *auth,
00775 const DBusString *data)
00776 {
00777
00778
00779
00780
00781 dbus_bool_t retval;
00782 DBusString context;
00783 DBusString cookie_id_str;
00784 DBusString server_challenge;
00785 DBusString client_challenge;
00786 DBusString correct_hash;
00787 DBusString tmp;
00788 int i, j;
00789 long val;
00790
00791 retval = FALSE;
00792
00793 if (!_dbus_string_find_blank (data, 0, &i))
00794 {
00795 if (send_error (auth,
00796 "Server did not send context/ID/challenge properly"))
00797 retval = TRUE;
00798 goto out_0;
00799 }
00800
00801 if (!_dbus_string_init (&context))
00802 goto out_0;
00803
00804 if (!_dbus_string_copy_len (data, 0, i,
00805 &context, 0))
00806 goto out_1;
00807
00808 _dbus_string_skip_blank (data, i, &i);
00809 if (!_dbus_string_find_blank (data, i, &j))
00810 {
00811 if (send_error (auth,
00812 "Server did not send context/ID/challenge properly"))
00813 retval = TRUE;
00814 goto out_1;
00815 }
00816
00817 if (!_dbus_string_init (&cookie_id_str))
00818 goto out_1;
00819
00820 if (!_dbus_string_copy_len (data, i, j - i,
00821 &cookie_id_str, 0))
00822 goto out_2;
00823
00824 if (!_dbus_string_init (&server_challenge))
00825 goto out_2;
00826
00827 i = j;
00828 _dbus_string_skip_blank (data, i, &i);
00829 j = _dbus_string_get_length (data);
00830
00831 if (!_dbus_string_copy_len (data, i, j - i,
00832 &server_challenge, 0))
00833 goto out_3;
00834
00835 if (!_dbus_keyring_validate_context (&context))
00836 {
00837 if (send_error (auth, "Server sent invalid cookie context"))
00838 retval = TRUE;
00839 goto out_3;
00840 }
00841
00842 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00843 {
00844 if (send_error (auth, "Could not parse cookie ID as an integer"))
00845 retval = TRUE;
00846 goto out_3;
00847 }
00848
00849 if (_dbus_string_get_length (&server_challenge) == 0)
00850 {
00851 if (send_error (auth, "Empty server challenge string"))
00852 retval = TRUE;
00853 goto out_3;
00854 }
00855
00856 if (auth->keyring == NULL)
00857 {
00858 DBusError error;
00859
00860 dbus_error_init (&error);
00861 auth->keyring = _dbus_keyring_new_homedir (NULL,
00862 &context,
00863 &error);
00864
00865 if (auth->keyring == NULL)
00866 {
00867 if (dbus_error_has_name (&error,
00868 DBUS_ERROR_NO_MEMORY))
00869 {
00870 dbus_error_free (&error);
00871 goto out_3;
00872 }
00873 else
00874 {
00875 _DBUS_ASSERT_ERROR_IS_SET (&error);
00876
00877 _dbus_verbose ("%s: Error loading keyring: %s\n",
00878 DBUS_AUTH_NAME (auth), error.message);
00879
00880 if (send_error (auth, "Could not load cookie file"))
00881 retval = TRUE;
00882
00883 dbus_error_free (&error);
00884 goto out_3;
00885 }
00886 }
00887 else
00888 {
00889 _dbus_assert (!dbus_error_is_set (&error));
00890 }
00891 }
00892
00893 _dbus_assert (auth->keyring != NULL);
00894
00895 if (!_dbus_string_init (&tmp))
00896 goto out_3;
00897
00898 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00899 goto out_4;
00900
00901 if (!_dbus_string_init (&client_challenge))
00902 goto out_4;
00903
00904 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00905 goto out_5;
00906
00907 if (!_dbus_string_init (&correct_hash))
00908 goto out_5;
00909
00910 if (!sha1_compute_hash (auth, val,
00911 &server_challenge,
00912 &client_challenge,
00913 &correct_hash))
00914 goto out_6;
00915
00916 if (_dbus_string_get_length (&correct_hash) == 0)
00917 {
00918
00919 if (send_error (auth, "Don't have the requested cookie ID"))
00920 retval = TRUE;
00921 goto out_6;
00922 }
00923
00924 _dbus_string_set_length (&tmp, 0);
00925
00926 if (!_dbus_string_copy (&client_challenge, 0, &tmp,
00927 _dbus_string_get_length (&tmp)))
00928 goto out_6;
00929
00930 if (!_dbus_string_append (&tmp, " "))
00931 goto out_6;
00932
00933 if (!_dbus_string_copy (&correct_hash, 0, &tmp,
00934 _dbus_string_get_length (&tmp)))
00935 goto out_6;
00936
00937 if (!send_data (auth, &tmp))
00938 goto out_6;
00939
00940 retval = TRUE;
00941
00942 out_6:
00943 _dbus_string_zero (&correct_hash);
00944 _dbus_string_free (&correct_hash);
00945 out_5:
00946 _dbus_string_free (&client_challenge);
00947 out_4:
00948 _dbus_string_zero (&tmp);
00949 _dbus_string_free (&tmp);
00950 out_3:
00951 _dbus_string_free (&server_challenge);
00952 out_2:
00953 _dbus_string_free (&cookie_id_str);
00954 out_1:
00955 _dbus_string_free (&context);
00956 out_0:
00957 return retval;
00958 }
00959
00960 static void
00961 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
00962 {
00963 auth->cookie_id = -1;
00964 _dbus_string_set_length (&auth->challenge, 0);
00965 }
00966
00967 static dbus_bool_t
00968 handle_server_data_external_mech (DBusAuth *auth,
00969 const DBusString *data)
00970 {
00971 if (auth->credentials.uid == DBUS_UID_UNSET)
00972 {
00973 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
00974 DBUS_AUTH_NAME (auth));
00975 return send_rejected (auth);
00976 }
00977
00978 if (_dbus_string_get_length (data) > 0)
00979 {
00980 if (_dbus_string_get_length (&auth->identity) > 0)
00981 {
00982
00983 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00984 DBUS_AUTH_NAME (auth));
00985 return send_rejected (auth);
00986 }
00987 else
00988 {
00989
00990 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00991 return FALSE;
00992 }
00993 }
00994
00995
00996 if (_dbus_string_get_length (&auth->identity) == 0 &&
00997 !auth->already_asked_for_initial_response)
00998 {
00999 if (send_data (auth, NULL))
01000 {
01001 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01002 DBUS_AUTH_NAME (auth));
01003 auth->already_asked_for_initial_response = TRUE;
01004 return TRUE;
01005 }
01006 else
01007 return FALSE;
01008 }
01009
01010 _dbus_credentials_clear (&auth->desired_identity);
01011
01012
01013
01014
01015
01016
01017 if (_dbus_string_get_length (&auth->identity) == 0)
01018 {
01019 auth->desired_identity.uid = auth->credentials.uid;
01020 }
01021 else
01022 {
01023 if (!_dbus_parse_uid (&auth->identity,
01024 &auth->desired_identity.uid))
01025 {
01026 _dbus_verbose ("%s: could not get credentials from uid string\n",
01027 DBUS_AUTH_NAME (auth));
01028 return send_rejected (auth);
01029 }
01030 }
01031
01032 if (auth->desired_identity.uid == DBUS_UID_UNSET)
01033 {
01034 _dbus_verbose ("%s: desired user %s is no good\n",
01035 DBUS_AUTH_NAME (auth),
01036 _dbus_string_get_const_data (&auth->identity));
01037 return send_rejected (auth);
01038 }
01039
01040 if (_dbus_credentials_match (&auth->desired_identity,
01041 &auth->credentials))
01042 {
01043
01044 if (!send_ok (auth))
01045 return FALSE;
01046
01047 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
01048 " matching socket credentials UID "DBUS_UID_FORMAT"\n",
01049 DBUS_AUTH_NAME (auth),
01050 auth->desired_identity.uid,
01051 auth->credentials.uid);
01052
01053 auth->authorized_identity.pid = auth->credentials.pid;
01054 auth->authorized_identity.uid = auth->desired_identity.uid;
01055 return TRUE;
01056 }
01057 else
01058 {
01059 _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
01060 " gid="DBUS_GID_FORMAT
01061 " do not allow uid="DBUS_UID_FORMAT
01062 " gid="DBUS_GID_FORMAT"\n",
01063 DBUS_AUTH_NAME (auth),
01064 auth->credentials.uid, auth->credentials.gid,
01065 auth->desired_identity.uid, auth->desired_identity.gid);
01066 return send_rejected (auth);
01067 }
01068 }
01069
01070 static void
01071 handle_server_shutdown_external_mech (DBusAuth *auth)
01072 {
01073
01074 }
01075
01076 static dbus_bool_t
01077 handle_client_initial_response_external_mech (DBusAuth *auth,
01078 DBusString *response)
01079 {
01080
01081
01082
01083
01084
01085 DBusString plaintext;
01086
01087 if (!_dbus_string_init (&plaintext))
01088 return FALSE;
01089
01090 if (!_dbus_string_append_uint (&plaintext,
01091 _dbus_getuid ()))
01092 goto failed;
01093
01094 if (!_dbus_string_hex_encode (&plaintext, 0,
01095 response,
01096 _dbus_string_get_length (response)))
01097 goto failed;
01098
01099 _dbus_string_free (&plaintext);
01100
01101 return TRUE;
01102
01103 failed:
01104 _dbus_string_free (&plaintext);
01105 return FALSE;
01106 }
01107
01108 static dbus_bool_t
01109 handle_client_data_external_mech (DBusAuth *auth,
01110 const DBusString *data)
01111 {
01112
01113 return TRUE;
01114 }
01115
01116 static void
01117 handle_client_shutdown_external_mech (DBusAuth *auth)
01118 {
01119
01120 }
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131 static const DBusAuthMechanismHandler
01132 all_mechanisms[] = {
01133 { "EXTERNAL",
01134 handle_server_data_external_mech,
01135 NULL, NULL,
01136 handle_server_shutdown_external_mech,
01137 handle_client_initial_response_external_mech,
01138 handle_client_data_external_mech,
01139 NULL, NULL,
01140 handle_client_shutdown_external_mech },
01141 { "DBUS_COOKIE_SHA1",
01142 handle_server_data_cookie_sha1_mech,
01143 NULL, NULL,
01144 handle_server_shutdown_cookie_sha1_mech,
01145 handle_client_initial_response_cookie_sha1_mech,
01146 handle_client_data_cookie_sha1_mech,
01147 NULL, NULL,
01148 handle_client_shutdown_cookie_sha1_mech },
01149 { NULL, NULL }
01150 };
01151
01152 static const DBusAuthMechanismHandler*
01153 find_mech (const DBusString *name,
01154 char **allowed_mechs)
01155 {
01156 int i;
01157
01158 if (allowed_mechs != NULL &&
01159 !_dbus_string_array_contains ((const char**) allowed_mechs,
01160 _dbus_string_get_const_data (name)))
01161 return NULL;
01162
01163 i = 0;
01164 while (all_mechanisms[i].mechanism != NULL)
01165 {
01166 if (_dbus_string_equal_c_str (name,
01167 all_mechanisms[i].mechanism))
01168
01169 return &all_mechanisms[i];
01170
01171 ++i;
01172 }
01173
01174 return NULL;
01175 }
01176
01177 static dbus_bool_t
01178 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01179 {
01180 DBusString auth_command;
01181
01182 if (!_dbus_string_init (&auth_command))
01183 return FALSE;
01184
01185 if (!_dbus_string_append (&auth_command,
01186 "AUTH "))
01187 {
01188 _dbus_string_free (&auth_command);
01189 return FALSE;
01190 }
01191
01192 if (!_dbus_string_append (&auth_command,
01193 mech->mechanism))
01194 {
01195 _dbus_string_free (&auth_command);
01196 return FALSE;
01197 }
01198
01199 if (mech->client_initial_response_func != NULL)
01200 {
01201 if (!_dbus_string_append (&auth_command, " "))
01202 {
01203 _dbus_string_free (&auth_command);
01204 return FALSE;
01205 }
01206
01207 if (!(* mech->client_initial_response_func) (auth, &auth_command))
01208 {
01209 _dbus_string_free (&auth_command);
01210 return FALSE;
01211 }
01212 }
01213
01214 if (!_dbus_string_append (&auth_command,
01215 "\r\n"))
01216 {
01217 _dbus_string_free (&auth_command);
01218 return FALSE;
01219 }
01220
01221 if (!_dbus_string_copy (&auth_command, 0,
01222 &auth->outgoing,
01223 _dbus_string_get_length (&auth->outgoing)))
01224 {
01225 _dbus_string_free (&auth_command);
01226 return FALSE;
01227 }
01228
01229 _dbus_string_free (&auth_command);
01230 shutdown_mech (auth);
01231 auth->mech = mech;
01232 goto_state (auth, &client_state_waiting_for_data);
01233
01234 return TRUE;
01235 }
01236
01237 static dbus_bool_t
01238 send_data (DBusAuth *auth, DBusString *data)
01239 {
01240 int old_len;
01241
01242 if (data == NULL || _dbus_string_get_length (data) == 0)
01243 return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01244 else
01245 {
01246 old_len = _dbus_string_get_length (&auth->outgoing);
01247 if (!_dbus_string_append (&auth->outgoing, "DATA "))
01248 goto out;
01249
01250 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01251 _dbus_string_get_length (&auth->outgoing)))
01252 goto out;
01253
01254 if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01255 goto out;
01256
01257 return TRUE;
01258
01259 out:
01260 _dbus_string_set_length (&auth->outgoing, old_len);
01261
01262 return FALSE;
01263 }
01264 }
01265
01266 static dbus_bool_t
01267 send_rejected (DBusAuth *auth)
01268 {
01269 DBusString command;
01270 DBusAuthServer *server_auth;
01271 int i;
01272
01273 if (!_dbus_string_init (&command))
01274 return FALSE;
01275
01276 if (!_dbus_string_append (&command,
01277 "REJECTED"))
01278 goto nomem;
01279
01280 i = 0;
01281 while (all_mechanisms[i].mechanism != NULL)
01282 {
01283 if (!_dbus_string_append (&command,
01284 " "))
01285 goto nomem;
01286
01287 if (!_dbus_string_append (&command,
01288 all_mechanisms[i].mechanism))
01289 goto nomem;
01290
01291 ++i;
01292 }
01293
01294 if (!_dbus_string_append (&command, "\r\n"))
01295 goto nomem;
01296
01297 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01298 _dbus_string_get_length (&auth->outgoing)))
01299 goto nomem;
01300
01301 shutdown_mech (auth);
01302
01303 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01304 server_auth = DBUS_AUTH_SERVER (auth);
01305 server_auth->failures += 1;
01306
01307 if (server_auth->failures >= server_auth->max_failures)
01308 goto_state (auth, &common_state_need_disconnect);
01309 else
01310 goto_state (auth, &server_state_waiting_for_auth);
01311
01312 _dbus_string_free (&command);
01313
01314 return TRUE;
01315
01316 nomem:
01317 _dbus_string_free (&command);
01318 return FALSE;
01319 }
01320
01321 static dbus_bool_t
01322 send_error (DBusAuth *auth, const char *message)
01323 {
01324 return _dbus_string_append_printf (&auth->outgoing,
01325 "ERROR \"%s\"\r\n", message);
01326 }
01327
01328 static dbus_bool_t
01329 send_ok (DBusAuth *auth)
01330 {
01331 int orig_len;
01332
01333 orig_len = _dbus_string_get_length (&auth->outgoing);
01334
01335 if (_dbus_string_append (&auth->outgoing, "OK ") &&
01336 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01337 0,
01338 &auth->outgoing,
01339 _dbus_string_get_length (&auth->outgoing)) &&
01340 _dbus_string_append (&auth->outgoing, "\r\n"))
01341 {
01342 goto_state (auth, &server_state_waiting_for_begin);
01343 return TRUE;
01344 }
01345 else
01346 {
01347 _dbus_string_set_length (&auth->outgoing, orig_len);
01348 return FALSE;
01349 }
01350 }
01351
01352 static dbus_bool_t
01353 send_begin (DBusAuth *auth,
01354 const DBusString *args_from_ok)
01355 {
01356 int end_of_hex;
01357
01358
01359 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01360
01361
01362
01363 end_of_hex = 0;
01364 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01365 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01366 return FALSE;
01367
01368
01369 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01370
01371 if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01372 end_of_hex == 0)
01373 {
01374 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01375 end_of_hex, _dbus_string_get_length (args_from_ok));
01376 goto_state (auth, &common_state_need_disconnect);
01377 return TRUE;
01378 }
01379
01380 if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01381 _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01382 {
01383 _dbus_verbose ("Got GUID '%s' from the server\n",
01384 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01385
01386 goto_state (auth, &common_state_authenticated);
01387 return TRUE;
01388 }
01389 else
01390 {
01391 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01392 return FALSE;
01393 }
01394 }
01395
01396 static dbus_bool_t
01397 send_cancel (DBusAuth *auth)
01398 {
01399 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
01400 {
01401 goto_state (auth, &client_state_waiting_for_reject);
01402 return TRUE;
01403 }
01404 else
01405 return FALSE;
01406 }
01407
01408 static dbus_bool_t
01409 process_data (DBusAuth *auth,
01410 const DBusString *args,
01411 DBusAuthDataFunction data_func)
01412 {
01413 int end;
01414 DBusString decoded;
01415
01416 if (!_dbus_string_init (&decoded))
01417 return FALSE;
01418
01419 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01420 {
01421 _dbus_string_free (&decoded);
01422 return FALSE;
01423 }
01424
01425 if (_dbus_string_get_length (args) != end)
01426 {
01427 _dbus_string_free (&decoded);
01428 if (!send_error (auth, "Invalid hex encoding"))
01429 return FALSE;
01430
01431 return TRUE;
01432 }
01433
01434 #ifdef DBUS_ENABLE_VERBOSE_MODE
01435 if (_dbus_string_validate_ascii (&decoded, 0,
01436 _dbus_string_get_length (&decoded)))
01437 _dbus_verbose ("%s: data: '%s'\n",
01438 DBUS_AUTH_NAME (auth),
01439 _dbus_string_get_const_data (&decoded));
01440 #endif
01441
01442 if (!(* data_func) (auth, &decoded))
01443 {
01444 _dbus_string_free (&decoded);
01445 return FALSE;
01446 }
01447
01448 _dbus_string_free (&decoded);
01449 return TRUE;
01450 }
01451
01452 static dbus_bool_t
01453 handle_auth (DBusAuth *auth, const DBusString *args)
01454 {
01455 if (_dbus_string_get_length (args) == 0)
01456 {
01457
01458 if (!send_rejected (auth))
01459 return FALSE;
01460
01461 return TRUE;
01462 }
01463 else
01464 {
01465 int i;
01466 DBusString mech;
01467 DBusString hex_response;
01468
01469 _dbus_string_find_blank (args, 0, &i);
01470
01471 if (!_dbus_string_init (&mech))
01472 return FALSE;
01473
01474 if (!_dbus_string_init (&hex_response))
01475 {
01476 _dbus_string_free (&mech);
01477 return FALSE;
01478 }
01479
01480 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
01481 goto failed;
01482
01483 _dbus_string_skip_blank (args, i, &i);
01484 if (!_dbus_string_copy (args, i, &hex_response, 0))
01485 goto failed;
01486
01487 auth->mech = find_mech (&mech, auth->allowed_mechs);
01488 if (auth->mech != NULL)
01489 {
01490 _dbus_verbose ("%s: Trying mechanism %s\n",
01491 DBUS_AUTH_NAME (auth),
01492 auth->mech->mechanism);
01493
01494 if (!process_data (auth, &hex_response,
01495 auth->mech->server_data_func))
01496 goto failed;
01497 }
01498 else
01499 {
01500
01501 _dbus_verbose ("%s: Unsupported mechanism %s\n",
01502 DBUS_AUTH_NAME (auth),
01503 _dbus_string_get_const_data (&mech));
01504
01505 if (!send_rejected (auth))
01506 goto failed;
01507 }
01508
01509 _dbus_string_free (&mech);
01510 _dbus_string_free (&hex_response);
01511
01512 return TRUE;
01513
01514 failed:
01515 auth->mech = NULL;
01516 _dbus_string_free (&mech);
01517 _dbus_string_free (&hex_response);
01518 return FALSE;
01519 }
01520 }
01521
01522 static dbus_bool_t
01523 handle_server_state_waiting_for_auth (DBusAuth *auth,
01524 DBusAuthCommand command,
01525 const DBusString *args)
01526 {
01527 switch (command)
01528 {
01529 case DBUS_AUTH_COMMAND_AUTH:
01530 return handle_auth (auth, args);
01531
01532 case DBUS_AUTH_COMMAND_CANCEL:
01533 case DBUS_AUTH_COMMAND_DATA:
01534 return send_error (auth, "Not currently in an auth conversation");
01535
01536 case DBUS_AUTH_COMMAND_BEGIN:
01537 goto_state (auth, &common_state_need_disconnect);
01538 return TRUE;
01539
01540 case DBUS_AUTH_COMMAND_ERROR:
01541 return send_rejected (auth);
01542
01543 case DBUS_AUTH_COMMAND_REJECTED:
01544 case DBUS_AUTH_COMMAND_OK:
01545 case DBUS_AUTH_COMMAND_UNKNOWN:
01546 default:
01547 return send_error (auth, "Unknown command");
01548 }
01549 }
01550
01551 static dbus_bool_t
01552 handle_server_state_waiting_for_data (DBusAuth *auth,
01553 DBusAuthCommand command,
01554 const DBusString *args)
01555 {
01556 switch (command)
01557 {
01558 case DBUS_AUTH_COMMAND_AUTH:
01559 return send_error (auth, "Sent AUTH while another AUTH in progress");
01560
01561 case DBUS_AUTH_COMMAND_CANCEL:
01562 case DBUS_AUTH_COMMAND_ERROR:
01563 return send_rejected (auth);
01564
01565 case DBUS_AUTH_COMMAND_DATA:
01566 return process_data (auth, args, auth->mech->server_data_func);
01567
01568 case DBUS_AUTH_COMMAND_BEGIN:
01569 goto_state (auth, &common_state_need_disconnect);
01570 return TRUE;
01571
01572 case DBUS_AUTH_COMMAND_REJECTED:
01573 case DBUS_AUTH_COMMAND_OK:
01574 case DBUS_AUTH_COMMAND_UNKNOWN:
01575 default:
01576 return send_error (auth, "Unknown command");
01577 }
01578 }
01579
01580 static dbus_bool_t
01581 handle_server_state_waiting_for_begin (DBusAuth *auth,
01582 DBusAuthCommand command,
01583 const DBusString *args)
01584 {
01585 switch (command)
01586 {
01587 case DBUS_AUTH_COMMAND_AUTH:
01588 return send_error (auth, "Sent AUTH while expecting BEGIN");
01589
01590 case DBUS_AUTH_COMMAND_DATA:
01591 return send_error (auth, "Sent DATA while expecting BEGIN");
01592
01593 case DBUS_AUTH_COMMAND_BEGIN:
01594 goto_state (auth, &common_state_authenticated);
01595 return TRUE;
01596
01597 case DBUS_AUTH_COMMAND_REJECTED:
01598 case DBUS_AUTH_COMMAND_OK:
01599 case DBUS_AUTH_COMMAND_UNKNOWN:
01600 default:
01601 return send_error (auth, "Unknown command");
01602
01603 case DBUS_AUTH_COMMAND_CANCEL:
01604 case DBUS_AUTH_COMMAND_ERROR:
01605 return send_rejected (auth);
01606 }
01607 }
01608
01609
01610 static dbus_bool_t
01611 get_word (const DBusString *str,
01612 int *start,
01613 DBusString *word)
01614 {
01615 int i;
01616
01617 _dbus_string_skip_blank (str, *start, start);
01618 _dbus_string_find_blank (str, *start, &i);
01619
01620 if (i > *start)
01621 {
01622 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
01623 return FALSE;
01624
01625 *start = i;
01626 }
01627
01628 return TRUE;
01629 }
01630
01631 static dbus_bool_t
01632 record_mechanisms (DBusAuth *auth,
01633 const DBusString *args)
01634 {
01635 int next;
01636 int len;
01637
01638 if (auth->already_got_mechanisms)
01639 return TRUE;
01640
01641 len = _dbus_string_get_length (args);
01642
01643 next = 0;
01644 while (next < len)
01645 {
01646 DBusString m;
01647 const DBusAuthMechanismHandler *mech;
01648
01649 if (!_dbus_string_init (&m))
01650 goto nomem;
01651
01652 if (!get_word (args, &next, &m))
01653 {
01654 _dbus_string_free (&m);
01655 goto nomem;
01656 }
01657
01658 mech = find_mech (&m, auth->allowed_mechs);
01659
01660 if (mech != NULL)
01661 {
01662
01663
01664
01665
01666
01667
01668
01669
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: Server offered mechanism \"%s\" that we don't know how to use\n",
01684 DBUS_AUTH_NAME (auth),
01685 _dbus_string_get_const_data (&m));
01686 }
01687
01688 _dbus_string_free (&m);
01689 }
01690
01691 auth->already_got_mechanisms = TRUE;
01692
01693 return TRUE;
01694
01695 nomem:
01696 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01697
01698 return FALSE;
01699 }
01700
01701 static dbus_bool_t
01702 process_rejected (DBusAuth *auth, const DBusString *args)
01703 {
01704 const DBusAuthMechanismHandler *mech;
01705 DBusAuthClient *client;
01706
01707 client = DBUS_AUTH_CLIENT (auth);
01708
01709 if (!auth->already_got_mechanisms)
01710 {
01711 if (!record_mechanisms (auth, args))
01712 return FALSE;
01713 }
01714
01715 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
01716 {
01717 mech = client->mechs_to_try->data;
01718
01719 if (!send_auth (auth, mech))
01720 return FALSE;
01721
01722 _dbus_list_pop_first (&client->mechs_to_try);
01723
01724 _dbus_verbose ("%s: Trying mechanism %s\n",
01725 DBUS_AUTH_NAME (auth),
01726 mech->mechanism);
01727 }
01728 else
01729 {
01730
01731 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
01732 DBUS_AUTH_NAME (auth));
01733 goto_state (auth, &common_state_need_disconnect);
01734 }
01735
01736 return TRUE;
01737 }
01738
01739
01740 static dbus_bool_t
01741 handle_client_state_waiting_for_data (DBusAuth *auth,
01742 DBusAuthCommand command,
01743 const DBusString *args)
01744 {
01745 _dbus_assert (auth->mech != NULL);
01746
01747 switch (command)
01748 {
01749 case DBUS_AUTH_COMMAND_DATA:
01750 return process_data (auth, args, auth->mech->client_data_func);
01751
01752 case DBUS_AUTH_COMMAND_REJECTED:
01753 return process_rejected (auth, args);
01754
01755 case DBUS_AUTH_COMMAND_OK:
01756 return send_begin (auth, args);
01757
01758 case DBUS_AUTH_COMMAND_ERROR:
01759 return send_cancel (auth);
01760
01761 case DBUS_AUTH_COMMAND_AUTH:
01762 case DBUS_AUTH_COMMAND_CANCEL:
01763 case DBUS_AUTH_COMMAND_BEGIN:
01764 case DBUS_AUTH_COMMAND_UNKNOWN:
01765 default:
01766 return send_error (auth, "Unknown command");
01767 }
01768 }
01769
01770 static dbus_bool_t
01771 handle_client_state_waiting_for_ok (DBusAuth *auth,
01772 DBusAuthCommand command,
01773 const DBusString *args)
01774 {
01775 switch (command)
01776 {
01777 case DBUS_AUTH_COMMAND_REJECTED:
01778 return process_rejected (auth, args);
01779
01780 case DBUS_AUTH_COMMAND_OK:
01781 return send_begin (auth, args);
01782
01783 case DBUS_AUTH_COMMAND_DATA:
01784 case DBUS_AUTH_COMMAND_ERROR:
01785 return send_cancel (auth);
01786
01787 case DBUS_AUTH_COMMAND_AUTH:
01788 case DBUS_AUTH_COMMAND_CANCEL:
01789 case DBUS_AUTH_COMMAND_BEGIN:
01790 case DBUS_AUTH_COMMAND_UNKNOWN:
01791 default:
01792 return send_error (auth, "Unknown command");
01793 }
01794 }
01795
01796 static dbus_bool_t
01797 handle_client_state_waiting_for_reject (DBusAuth *auth,
01798 DBusAuthCommand command,
01799 const DBusString *args)
01800 {
01801 switch (command)
01802 {
01803 case DBUS_AUTH_COMMAND_REJECTED:
01804 return process_rejected (auth, args);
01805
01806 case DBUS_AUTH_COMMAND_AUTH:
01807 case DBUS_AUTH_COMMAND_CANCEL:
01808 case DBUS_AUTH_COMMAND_DATA:
01809 case DBUS_AUTH_COMMAND_BEGIN:
01810 case DBUS_AUTH_COMMAND_OK:
01811 case DBUS_AUTH_COMMAND_ERROR:
01812 case DBUS_AUTH_COMMAND_UNKNOWN:
01813 default:
01814 goto_state (auth, &common_state_need_disconnect);
01815 return TRUE;
01816 }
01817 }
01818
01822 typedef struct {
01823 const char *name;
01824 DBusAuthCommand command;
01825 } DBusAuthCommandName;
01826
01827 static DBusAuthCommandName auth_command_names[] = {
01828 { "AUTH", DBUS_AUTH_COMMAND_AUTH },
01829 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
01830 { "DATA", DBUS_AUTH_COMMAND_DATA },
01831 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
01832 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
01833 { "OK", DBUS_AUTH_COMMAND_OK },
01834 { "ERROR", DBUS_AUTH_COMMAND_ERROR }
01835 };
01836
01837 static DBusAuthCommand
01838 lookup_command_from_name (DBusString *command)
01839 {
01840 int i;
01841
01842 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
01843 {
01844 if (_dbus_string_equal_c_str (command,
01845 auth_command_names[i].name))
01846 return auth_command_names[i].command;
01847 }
01848
01849 return DBUS_AUTH_COMMAND_UNKNOWN;
01850 }
01851
01852 static void
01853 goto_state (DBusAuth *auth, const DBusAuthStateData *state)
01854 {
01855 _dbus_verbose ("%s: going from state %s to state %s\n",
01856 DBUS_AUTH_NAME (auth),
01857 auth->state->name,
01858 state->name);
01859
01860 auth->state = state;
01861 }
01862
01863
01864 static dbus_bool_t
01865 process_command (DBusAuth *auth)
01866 {
01867 DBusAuthCommand command;
01868 DBusString line;
01869 DBusString args;
01870 int eol;
01871 int i, j;
01872 dbus_bool_t retval;
01873
01874
01875
01876 retval = FALSE;
01877
01878 eol = 0;
01879 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
01880 return FALSE;
01881
01882 if (!_dbus_string_init (&line))
01883 {
01884 auth->needed_memory = TRUE;
01885 return FALSE;
01886 }
01887
01888 if (!_dbus_string_init (&args))
01889 {
01890 _dbus_string_free (&line);
01891 auth->needed_memory = TRUE;
01892 return FALSE;
01893 }
01894
01895 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
01896 goto out;
01897
01898 if (!_dbus_string_validate_ascii (&line, 0,
01899 _dbus_string_get_length (&line)))
01900 {
01901 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
01902 DBUS_AUTH_NAME (auth));
01903 if (!send_error (auth, "Command contained non-ASCII"))
01904 goto out;
01905 else
01906 goto next_command;
01907 }
01908
01909 _dbus_verbose ("%s: got command \"%s\"\n",
01910 DBUS_AUTH_NAME (auth),
01911 _dbus_string_get_const_data (&line));
01912
01913 _dbus_string_find_blank (&line, 0, &i);
01914 _dbus_string_skip_blank (&line, i, &j);
01915
01916 if (j > i)
01917 _dbus_string_delete (&line, i, j - i);
01918
01919 if (!_dbus_string_move (&line, i, &args, 0))
01920 goto out;
01921
01922
01923
01924
01925
01926 command = lookup_command_from_name (&line);
01927 if (!(* auth->state->handler) (auth, command, &args))
01928 goto out;
01929
01930 next_command:
01931
01932
01933
01934
01935
01936 _dbus_string_delete (&auth->incoming, 0, eol);
01937
01938
01939 _dbus_string_delete (&auth->incoming, 0, 2);
01940
01941 retval = TRUE;
01942
01943 out:
01944 _dbus_string_free (&args);
01945 _dbus_string_free (&line);
01946
01947 if (!retval)
01948 auth->needed_memory = TRUE;
01949 else
01950 auth->needed_memory = FALSE;
01951
01952 return retval;
01953 }
01954
01955
01970 DBusAuth*
01971 _dbus_auth_server_new (const DBusString *guid)
01972 {
01973 DBusAuth *auth;
01974 DBusAuthServer *server_auth;
01975 DBusString guid_copy;
01976
01977 if (!_dbus_string_init (&guid_copy))
01978 return NULL;
01979
01980 if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
01981 {
01982 _dbus_string_free (&guid_copy);
01983 return NULL;
01984 }
01985
01986 auth = _dbus_auth_new (sizeof (DBusAuthServer));
01987 if (auth == NULL)
01988 {
01989 _dbus_string_free (&guid_copy);
01990 return NULL;
01991 }
01992
01993 auth->side = auth_side_server;
01994 auth->state = &server_state_waiting_for_auth;
01995
01996 server_auth = DBUS_AUTH_SERVER (auth);
01997
01998 server_auth->guid = guid_copy;
01999
02000
02001
02002
02003 server_auth->failures = 0;
02004 server_auth->max_failures = 6;
02005
02006 return auth;
02007 }
02008
02016 DBusAuth*
02017 _dbus_auth_client_new (void)
02018 {
02019 DBusAuth *auth;
02020 DBusString guid_str;
02021
02022 if (!_dbus_string_init (&guid_str))
02023 return NULL;
02024
02025 auth = _dbus_auth_new (sizeof (DBusAuthClient));
02026 if (auth == NULL)
02027 {
02028 _dbus_string_free (&guid_str);
02029 return NULL;
02030 }
02031
02032 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02033
02034 auth->side = auth_side_client;
02035 auth->state = &client_state_need_send_auth;
02036
02037
02038
02039 if (!send_auth (auth, &all_mechanisms[0]))
02040 {
02041 _dbus_auth_unref (auth);
02042 return NULL;
02043 }
02044
02045 return auth;
02046 }
02047
02054 DBusAuth *
02055 _dbus_auth_ref (DBusAuth *auth)
02056 {
02057 _dbus_assert (auth != NULL);
02058
02059 auth->refcount += 1;
02060
02061 return auth;
02062 }
02063
02069 void
02070 _dbus_auth_unref (DBusAuth *auth)
02071 {
02072 _dbus_assert (auth != NULL);
02073 _dbus_assert (auth->refcount > 0);
02074
02075 auth->refcount -= 1;
02076 if (auth->refcount == 0)
02077 {
02078 shutdown_mech (auth);
02079
02080 if (DBUS_AUTH_IS_CLIENT (auth))
02081 {
02082 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02083 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02084 }
02085 else
02086 {
02087 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02088
02089 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02090 }
02091
02092 if (auth->keyring)
02093 _dbus_keyring_unref (auth->keyring);
02094
02095 _dbus_string_free (&auth->context);
02096 _dbus_string_free (&auth->challenge);
02097 _dbus_string_free (&auth->identity);
02098 _dbus_string_free (&auth->incoming);
02099 _dbus_string_free (&auth->outgoing);
02100
02101 dbus_free_string_array (auth->allowed_mechs);
02102
02103 dbus_free (auth);
02104 }
02105 }
02106
02115 dbus_bool_t
02116 _dbus_auth_set_mechanisms (DBusAuth *auth,
02117 const char **mechanisms)
02118 {
02119 char **copy;
02120
02121 if (mechanisms != NULL)
02122 {
02123 copy = _dbus_dup_string_array (mechanisms);
02124 if (copy == NULL)
02125 return FALSE;
02126 }
02127 else
02128 copy = NULL;
02129
02130 dbus_free_string_array (auth->allowed_mechs);
02131
02132 auth->allowed_mechs = copy;
02133
02134 return TRUE;
02135 }
02136
02141 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02142
02150 DBusAuthState
02151 _dbus_auth_do_work (DBusAuth *auth)
02152 {
02153 auth->needed_memory = FALSE;
02154
02155
02156 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02157
02158 do
02159 {
02160 if (DBUS_AUTH_IN_END_STATE (auth))
02161 break;
02162
02163 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02164 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02165 {
02166 goto_state (auth, &common_state_need_disconnect);
02167 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02168 DBUS_AUTH_NAME (auth));
02169 break;
02170 }
02171 }
02172 while (process_command (auth));
02173
02174 if (auth->needed_memory)
02175 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02176 else if (_dbus_string_get_length (&auth->outgoing) > 0)
02177 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02178 else if (auth->state == &common_state_need_disconnect)
02179 return DBUS_AUTH_STATE_NEED_DISCONNECT;
02180 else if (auth->state == &common_state_authenticated)
02181 return DBUS_AUTH_STATE_AUTHENTICATED;
02182 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02183 }
02184
02194 dbus_bool_t
02195 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
02196 const DBusString **str)
02197 {
02198 _dbus_assert (auth != NULL);
02199 _dbus_assert (str != NULL);
02200
02201 *str = NULL;
02202
02203 if (_dbus_string_get_length (&auth->outgoing) == 0)
02204 return FALSE;
02205
02206 *str = &auth->outgoing;
02207
02208 return TRUE;
02209 }
02210
02219 void
02220 _dbus_auth_bytes_sent (DBusAuth *auth,
02221 int bytes_sent)
02222 {
02223 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02224 DBUS_AUTH_NAME (auth),
02225 bytes_sent,
02226 _dbus_string_get_const_data (&auth->outgoing));
02227
02228 _dbus_string_delete (&auth->outgoing,
02229 0, bytes_sent);
02230 }
02231
02239 void
02240 _dbus_auth_get_buffer (DBusAuth *auth,
02241 DBusString **buffer)
02242 {
02243 _dbus_assert (auth != NULL);
02244 _dbus_assert (!auth->buffer_outstanding);
02245
02246 *buffer = &auth->incoming;
02247
02248 auth->buffer_outstanding = TRUE;
02249 }
02250
02258 void
02259 _dbus_auth_return_buffer (DBusAuth *auth,
02260 DBusString *buffer,
02261 int bytes_read)
02262 {
02263 _dbus_assert (buffer == &auth->incoming);
02264 _dbus_assert (auth->buffer_outstanding);
02265
02266 auth->buffer_outstanding = FALSE;
02267 }
02268
02278 void
02279 _dbus_auth_get_unused_bytes (DBusAuth *auth,
02280 const DBusString **str)
02281 {
02282 if (!DBUS_AUTH_IN_END_STATE (auth))
02283 return;
02284
02285 *str = &auth->incoming;
02286 }
02287
02288
02295 void
02296 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02297 {
02298 if (!DBUS_AUTH_IN_END_STATE (auth))
02299 return;
02300
02301 _dbus_string_set_length (&auth->incoming, 0);
02302 }
02303
02312 dbus_bool_t
02313 _dbus_auth_needs_encoding (DBusAuth *auth)
02314 {
02315 if (auth->state != &common_state_authenticated)
02316 return FALSE;
02317
02318 if (auth->mech != NULL)
02319 {
02320 if (DBUS_AUTH_IS_CLIENT (auth))
02321 return auth->mech->client_encode_func != NULL;
02322 else
02323 return auth->mech->server_encode_func != NULL;
02324 }
02325 else
02326 return FALSE;
02327 }
02328
02339 dbus_bool_t
02340 _dbus_auth_encode_data (DBusAuth *auth,
02341 const DBusString *plaintext,
02342 DBusString *encoded)
02343 {
02344 _dbus_assert (plaintext != encoded);
02345
02346 if (auth->state != &common_state_authenticated)
02347 return FALSE;
02348
02349 if (_dbus_auth_needs_encoding (auth))
02350 {
02351 if (DBUS_AUTH_IS_CLIENT (auth))
02352 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02353 else
02354 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02355 }
02356 else
02357 {
02358 return _dbus_string_copy (plaintext, 0, encoded,
02359 _dbus_string_get_length (encoded));
02360 }
02361 }
02362
02371 dbus_bool_t
02372 _dbus_auth_needs_decoding (DBusAuth *auth)
02373 {
02374 if (auth->state != &common_state_authenticated)
02375 return FALSE;
02376
02377 if (auth->mech != NULL)
02378 {
02379 if (DBUS_AUTH_IS_CLIENT (auth))
02380 return auth->mech->client_decode_func != NULL;
02381 else
02382 return auth->mech->server_decode_func != NULL;
02383 }
02384 else
02385 return FALSE;
02386 }
02387
02388
02402 dbus_bool_t
02403 _dbus_auth_decode_data (DBusAuth *auth,
02404 const DBusString *encoded,
02405 DBusString *plaintext)
02406 {
02407 _dbus_assert (plaintext != encoded);
02408
02409 if (auth->state != &common_state_authenticated)
02410 return FALSE;
02411
02412 if (_dbus_auth_needs_decoding (auth))
02413 {
02414 if (DBUS_AUTH_IS_CLIENT (auth))
02415 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02416 else
02417 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02418 }
02419 else
02420 {
02421 return _dbus_string_copy (encoded, 0, plaintext,
02422 _dbus_string_get_length (plaintext));
02423 }
02424 }
02425
02433 void
02434 _dbus_auth_set_credentials (DBusAuth *auth,
02435 const DBusCredentials *credentials)
02436 {
02437 auth->credentials = *credentials;
02438 }
02439
02447 void
02448 _dbus_auth_get_identity (DBusAuth *auth,
02449 DBusCredentials *credentials)
02450 {
02451 if (auth->state == &common_state_authenticated)
02452 *credentials = auth->authorized_identity;
02453 else
02454 _dbus_credentials_clear (credentials);
02455 }
02456
02463 const char*
02464 _dbus_auth_get_guid_from_server (DBusAuth *auth)
02465 {
02466 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
02467
02468 if (auth->state == &common_state_authenticated)
02469 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02470 else
02471 return NULL;
02472 }
02473
02482 dbus_bool_t
02483 _dbus_auth_set_context (DBusAuth *auth,
02484 const DBusString *context)
02485 {
02486 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02487 &auth->context, 0, _dbus_string_get_length (context));
02488 }
02489
02492