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