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
01899 DBusAuth *
01900 _dbus_auth_ref (DBusAuth *auth)
01901 {
01902 _dbus_assert (auth != NULL);
01903
01904 auth->refcount += 1;
01905
01906 return auth;
01907 }
01908
01914 void
01915 _dbus_auth_unref (DBusAuth *auth)
01916 {
01917 _dbus_assert (auth != NULL);
01918 _dbus_assert (auth->refcount > 0);
01919
01920 auth->refcount -= 1;
01921 if (auth->refcount == 0)
01922 {
01923 shutdown_mech (auth);
01924
01925 if (DBUS_AUTH_IS_CLIENT (auth))
01926 {
01927 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01928 }
01929
01930 if (auth->keyring)
01931 _dbus_keyring_unref (auth->keyring);
01932
01933 _dbus_string_free (&auth->context);
01934 _dbus_string_free (&auth->challenge);
01935 _dbus_string_free (&auth->identity);
01936 _dbus_string_free (&auth->incoming);
01937 _dbus_string_free (&auth->outgoing);
01938
01939 dbus_free_string_array (auth->allowed_mechs);
01940
01941 dbus_free (auth);
01942 }
01943 }
01944
01953 dbus_bool_t
01954 _dbus_auth_set_mechanisms (DBusAuth *auth,
01955 const char **mechanisms)
01956 {
01957 char **copy;
01958
01959 if (mechanisms != NULL)
01960 {
01961 copy = _dbus_dup_string_array (mechanisms);
01962 if (copy == NULL)
01963 return FALSE;
01964 }
01965 else
01966 copy = NULL;
01967
01968 dbus_free_string_array (auth->allowed_mechs);
01969
01970 auth->allowed_mechs = copy;
01971
01972 return TRUE;
01973 }
01974
01979 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->need_disconnect || (auth)->authenticated)
01980
01988 DBusAuthState
01989 _dbus_auth_do_work (DBusAuth *auth)
01990 {
01991 auth->needed_memory = FALSE;
01992
01993
01994 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
01995
01996 do
01997 {
01998 if (DBUS_AUTH_IN_END_STATE (auth))
01999 break;
02000
02001 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02002 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02003 {
02004 auth->need_disconnect = TRUE;
02005 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02006 DBUS_AUTH_NAME (auth));
02007 break;
02008 }
02009
02010 if (auth->mech == NULL &&
02011 auth->already_got_mechanisms &&
02012 DBUS_AUTH_CLIENT (auth)->mechs_to_try == NULL)
02013 {
02014 auth->need_disconnect = TRUE;
02015 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
02016 DBUS_AUTH_NAME (auth));
02017 break;
02018 }
02019 }
02020 while (process_command (auth));
02021
02022 if (DBUS_AUTH_IS_SERVER (auth) &&
02023 DBUS_AUTH_SERVER (auth)->failures >=
02024 DBUS_AUTH_SERVER (auth)->max_failures)
02025 auth->need_disconnect = TRUE;
02026
02027 if (auth->need_disconnect)
02028 return DBUS_AUTH_STATE_NEED_DISCONNECT;
02029 else if (auth->authenticated)
02030 {
02031 if (_dbus_string_get_length (&auth->incoming) > 0)
02032 return DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES;
02033 else
02034 return DBUS_AUTH_STATE_AUTHENTICATED;
02035 }
02036 else if (auth->needed_memory)
02037 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02038 else if (_dbus_string_get_length (&auth->outgoing) > 0)
02039 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02040 else
02041 return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02042 }
02043
02053 dbus_bool_t
02054 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
02055 const DBusString **str)
02056 {
02057 _dbus_assert (auth != NULL);
02058 _dbus_assert (str != NULL);
02059
02060 *str = NULL;
02061
02062 if (DBUS_AUTH_IN_END_STATE (auth))
02063 return FALSE;
02064
02065 if (_dbus_string_get_length (&auth->outgoing) == 0)
02066 return FALSE;
02067
02068 *str = &auth->outgoing;
02069
02070 return TRUE;
02071 }
02072
02081 void
02082 _dbus_auth_bytes_sent (DBusAuth *auth,
02083 int bytes_sent)
02084 {
02085 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02086 DBUS_AUTH_NAME (auth),
02087 bytes_sent,
02088 _dbus_string_get_const_data (&auth->outgoing));
02089
02090 _dbus_string_delete (&auth->outgoing,
02091 0, bytes_sent);
02092
02093 if (auth->authenticated_pending_output &&
02094 _dbus_string_get_length (&auth->outgoing) == 0)
02095 auth->authenticated = TRUE;
02096 }
02097
02105 void
02106 _dbus_auth_get_buffer (DBusAuth *auth,
02107 DBusString **buffer)
02108 {
02109 _dbus_assert (auth != NULL);
02110 _dbus_assert (!auth->buffer_outstanding);
02111
02112 *buffer = &auth->incoming;
02113
02114 auth->buffer_outstanding = TRUE;
02115 }
02116
02124 void
02125 _dbus_auth_return_buffer (DBusAuth *auth,
02126 DBusString *buffer,
02127 int bytes_read)
02128 {
02129 _dbus_assert (buffer == &auth->incoming);
02130 _dbus_assert (auth->buffer_outstanding);
02131
02132 auth->buffer_outstanding = FALSE;
02133 }
02134
02144 void
02145 _dbus_auth_get_unused_bytes (DBusAuth *auth,
02146 const DBusString **str)
02147 {
02148 if (!DBUS_AUTH_IN_END_STATE (auth))
02149 return;
02150
02151 *str = &auth->incoming;
02152 }
02153
02154
02161 void
02162 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02163 {
02164 if (!DBUS_AUTH_IN_END_STATE (auth))
02165 return;
02166
02167 _dbus_string_set_length (&auth->incoming, 0);
02168 }
02169
02178 dbus_bool_t
02179 _dbus_auth_needs_encoding (DBusAuth *auth)
02180 {
02181 if (!auth->authenticated)
02182 return FALSE;
02183
02184 if (auth->mech != NULL)
02185 {
02186 if (DBUS_AUTH_IS_CLIENT (auth))
02187 return auth->mech->client_encode_func != NULL;
02188 else
02189 return auth->mech->server_encode_func != NULL;
02190 }
02191 else
02192 return FALSE;
02193 }
02194
02205 dbus_bool_t
02206 _dbus_auth_encode_data (DBusAuth *auth,
02207 const DBusString *plaintext,
02208 DBusString *encoded)
02209 {
02210 _dbus_assert (plaintext != encoded);
02211
02212 if (!auth->authenticated)
02213 return FALSE;
02214
02215 if (_dbus_auth_needs_encoding (auth))
02216 {
02217 if (DBUS_AUTH_IS_CLIENT (auth))
02218 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02219 else
02220 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02221 }
02222 else
02223 {
02224 return _dbus_string_copy (plaintext, 0, encoded,
02225 _dbus_string_get_length (encoded));
02226 }
02227 }
02228
02237 dbus_bool_t
02238 _dbus_auth_needs_decoding (DBusAuth *auth)
02239 {
02240 if (!auth->authenticated)
02241 return FALSE;
02242
02243 if (auth->mech != NULL)
02244 {
02245 if (DBUS_AUTH_IS_CLIENT (auth))
02246 return auth->mech->client_decode_func != NULL;
02247 else
02248 return auth->mech->server_decode_func != NULL;
02249 }
02250 else
02251 return FALSE;
02252 }
02253
02254
02268 dbus_bool_t
02269 _dbus_auth_decode_data (DBusAuth *auth,
02270 const DBusString *encoded,
02271 DBusString *plaintext)
02272 {
02273 _dbus_assert (plaintext != encoded);
02274
02275 if (!auth->authenticated)
02276 return FALSE;
02277
02278 if (_dbus_auth_needs_decoding (auth))
02279 {
02280 if (DBUS_AUTH_IS_CLIENT (auth))
02281 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
02282 else
02283 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
02284 }
02285 else
02286 {
02287 return _dbus_string_copy (encoded, 0, plaintext,
02288 _dbus_string_get_length (plaintext));
02289 }
02290 }
02291
02299 void
02300 _dbus_auth_set_credentials (DBusAuth *auth,
02301 const DBusCredentials *credentials)
02302 {
02303 auth->credentials = *credentials;
02304 }
02305
02313 void
02314 _dbus_auth_get_identity (DBusAuth *auth,
02315 DBusCredentials *credentials)
02316 {
02317 if (auth->authenticated)
02318 *credentials = auth->authorized_identity;
02319 else
02320 _dbus_credentials_clear (credentials);
02321 }
02322
02331 dbus_bool_t
02332 _dbus_auth_set_context (DBusAuth *auth,
02333 const DBusString *context)
02334 {
02335 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
02336 &auth->context, 0, _dbus_string_get_length (context));
02337 }
02338
02341 #ifdef DBUS_BUILD_TESTS
02342 #include "dbus-test.h"
02343 #include "dbus-auth-script.h"
02344 #include <stdio.h>
02345
02346 static dbus_bool_t
02347 process_test_subdir (const DBusString *test_base_dir,
02348 const char *subdir)
02349 {
02350 DBusString test_directory;
02351 DBusString filename;
02352 DBusDirIter *dir;
02353 dbus_bool_t retval;
02354 DBusError error;
02355
02356 retval = FALSE;
02357 dir = NULL;
02358
02359 if (!_dbus_string_init (&test_directory))
02360 _dbus_assert_not_reached ("didn't allocate test_directory\n");
02361
02362 _dbus_string_init_const (&filename, subdir);
02363
02364 if (!_dbus_string_copy (test_base_dir, 0,
02365 &test_directory, 0))
02366 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
02367
02368 if (!_dbus_concat_dir_and_file (&test_directory, &filename))
02369 _dbus_assert_not_reached ("couldn't allocate full path");
02370
02371 _dbus_string_free (&filename);
02372 if (!_dbus_string_init (&filename))
02373 _dbus_assert_not_reached ("didn't allocate filename string\n");
02374
02375 dbus_error_init (&error);
02376 dir = _dbus_directory_open (&test_directory, &error);
02377 if (dir == NULL)
02378 {
02379 _dbus_warn ("Could not open %s: %s\n",
02380 _dbus_string_get_const_data (&test_directory),
02381 error.message);
02382 dbus_error_free (&error);
02383 goto failed;
02384 }
02385
02386 printf ("Testing %s:\n", subdir);
02387
02388 next:
02389 while (_dbus_directory_get_next_file (dir, &filename, &error))
02390 {
02391 DBusString full_path;
02392
02393 if (!_dbus_string_init (&full_path))
02394 _dbus_assert_not_reached ("couldn't init string");
02395
02396 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
02397 _dbus_assert_not_reached ("couldn't copy dir to full_path");
02398
02399 if (!_dbus_concat_dir_and_file (&full_path, &filename))
02400 _dbus_assert_not_reached ("couldn't concat file to dir");
02401
02402 if (!_dbus_string_ends_with_c_str (&filename, ".auth-script"))
02403 {
02404 _dbus_verbose ("Skipping non-.auth-script file %s\n",
02405 _dbus_string_get_const_data (&filename));
02406 _dbus_string_free (&full_path);
02407 goto next;
02408 }
02409
02410 printf (" %s\n", _dbus_string_get_const_data (&filename));
02411
02412 if (!_dbus_auth_script_run (&full_path))
02413 {
02414 _dbus_string_free (&full_path);
02415 goto failed;
02416 }
02417 else
02418 _dbus_string_free (&full_path);
02419 }
02420
02421 if (dbus_error_is_set (&error))
02422 {
02423 _dbus_warn ("Could not get next file in %s: %s\n",
02424 _dbus_string_get_const_data (&test_directory), error.message);
02425 dbus_error_free (&error);
02426 goto failed;
02427 }
02428
02429 retval = TRUE;
02430
02431 failed:
02432
02433 if (dir)
02434 _dbus_directory_close (dir);
02435 _dbus_string_free (&test_directory);
02436 _dbus_string_free (&filename);
02437
02438 return retval;
02439 }
02440
02441 static dbus_bool_t
02442 process_test_dirs (const char *test_data_dir)
02443 {
02444 DBusString test_directory;
02445 dbus_bool_t retval;
02446
02447 retval = FALSE;
02448
02449 _dbus_string_init_const (&test_directory, test_data_dir);
02450
02451 if (!process_test_subdir (&test_directory, "auth"))
02452 goto failed;
02453
02454 retval = TRUE;
02455
02456 failed:
02457
02458 _dbus_string_free (&test_directory);
02459
02460 return retval;
02461 }
02462
02463 dbus_bool_t
02464 _dbus_auth_test (const char *test_data_dir)
02465 {
02466
02467 if (test_data_dir == NULL)
02468 return TRUE;
02469
02470 if (!process_test_dirs (test_data_dir))
02471 return FALSE;
02472
02473 return TRUE;
02474 }
02475
02476 #endif