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