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