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