D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-auth.c Authentication 00003 * 00004 * Copyright (C) 2002, 2003, 2004 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-auth.h" 00026 #include "dbus-string.h" 00027 #include "dbus-list.h" 00028 #include "dbus-internals.h" 00029 #include "dbus-keyring.h" 00030 #include "dbus-sha.h" 00031 #include "dbus-protocol.h" 00032 #include "dbus-credentials.h" 00033 00070 typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth, 00071 DBusString *response); 00072 00077 typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth, 00078 const DBusString *data); 00079 00083 typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth, 00084 const DBusString *data, 00085 DBusString *encoded); 00086 00090 typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, 00091 const DBusString *data, 00092 DBusString *decoded); 00093 00097 typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); 00098 00102 typedef struct 00103 { 00104 const char *mechanism; 00105 DBusAuthDataFunction server_data_func; 00106 DBusAuthEncodeFunction server_encode_func; 00107 DBusAuthDecodeFunction server_decode_func; 00108 DBusAuthShutdownFunction server_shutdown_func; 00109 DBusInitialResponseFunction client_initial_response_func; 00110 DBusAuthDataFunction client_data_func; 00111 DBusAuthEncodeFunction client_encode_func; 00112 DBusAuthDecodeFunction client_decode_func; 00113 DBusAuthShutdownFunction client_shutdown_func; 00114 } DBusAuthMechanismHandler; 00115 00119 typedef enum { 00120 DBUS_AUTH_COMMAND_AUTH, 00121 DBUS_AUTH_COMMAND_CANCEL, 00122 DBUS_AUTH_COMMAND_DATA, 00123 DBUS_AUTH_COMMAND_BEGIN, 00124 DBUS_AUTH_COMMAND_REJECTED, 00125 DBUS_AUTH_COMMAND_OK, 00126 DBUS_AUTH_COMMAND_ERROR, 00127 DBUS_AUTH_COMMAND_UNKNOWN, 00128 DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD, 00129 DBUS_AUTH_COMMAND_AGREE_UNIX_FD 00130 } DBusAuthCommand; 00131 00137 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth, 00138 DBusAuthCommand command, 00139 const DBusString *args); 00140 00144 typedef struct 00145 { 00146 const char *name; 00147 DBusAuthStateFunction handler; 00148 } DBusAuthStateData; 00149 00153 struct DBusAuth 00154 { 00155 int refcount; 00156 const char *side; 00158 DBusString incoming; 00159 DBusString outgoing; 00161 const DBusAuthStateData *state; 00163 const DBusAuthMechanismHandler *mech; 00165 DBusString identity; 00169 DBusCredentials *credentials; 00172 DBusCredentials *authorized_identity; 00174 DBusCredentials *desired_identity; 00176 DBusString context; 00177 DBusKeyring *keyring; 00178 int cookie_id; 00179 DBusString challenge; 00181 char **allowed_mechs; 00185 unsigned int needed_memory : 1; 00188 unsigned int already_got_mechanisms : 1; 00189 unsigned int already_asked_for_initial_response : 1; 00190 unsigned int buffer_outstanding : 1; 00192 unsigned int unix_fd_possible : 1; 00193 unsigned int unix_fd_negotiated : 1; 00194 }; 00195 00199 typedef struct 00200 { 00201 DBusAuth base; 00203 DBusList *mechs_to_try; 00205 DBusString guid_from_server; 00207 } DBusAuthClient; 00208 00212 typedef struct 00213 { 00214 DBusAuth base; 00216 int failures; 00217 int max_failures; 00219 DBusString guid; 00221 } DBusAuthServer; 00222 00223 static void goto_state (DBusAuth *auth, 00224 const DBusAuthStateData *new_state); 00225 static dbus_bool_t send_auth (DBusAuth *auth, 00226 const DBusAuthMechanismHandler *mech); 00227 static dbus_bool_t send_data (DBusAuth *auth, 00228 DBusString *data); 00229 static dbus_bool_t send_rejected (DBusAuth *auth); 00230 static dbus_bool_t send_error (DBusAuth *auth, 00231 const char *message); 00232 static dbus_bool_t send_ok (DBusAuth *auth); 00233 static dbus_bool_t send_begin (DBusAuth *auth); 00234 static dbus_bool_t send_cancel (DBusAuth *auth); 00235 static dbus_bool_t send_negotiate_unix_fd (DBusAuth *auth); 00236 static dbus_bool_t send_agree_unix_fd (DBusAuth *auth); 00237 00242 static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth, 00243 DBusAuthCommand command, 00244 const DBusString *args); 00245 static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth, 00246 DBusAuthCommand command, 00247 const DBusString *args); 00248 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth, 00249 DBusAuthCommand command, 00250 const DBusString *args); 00251 00252 static const DBusAuthStateData server_state_waiting_for_auth = { 00253 "WaitingForAuth", handle_server_state_waiting_for_auth 00254 }; 00255 static const DBusAuthStateData server_state_waiting_for_data = { 00256 "WaitingForData", handle_server_state_waiting_for_data 00257 }; 00258 static const DBusAuthStateData server_state_waiting_for_begin = { 00259 "WaitingForBegin", handle_server_state_waiting_for_begin 00260 }; 00261 00266 static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth, 00267 DBusAuthCommand command, 00268 const DBusString *args); 00269 static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth, 00270 DBusAuthCommand command, 00271 const DBusString *args); 00272 static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth, 00273 DBusAuthCommand command, 00274 const DBusString *args); 00275 static dbus_bool_t handle_client_state_waiting_for_agree_unix_fd (DBusAuth *auth, 00276 DBusAuthCommand command, 00277 const DBusString *args); 00278 00279 static const DBusAuthStateData client_state_need_send_auth = { 00280 "NeedSendAuth", NULL 00281 }; 00282 static const DBusAuthStateData client_state_waiting_for_data = { 00283 "WaitingForData", handle_client_state_waiting_for_data 00284 }; 00285 /* The WaitingForOK state doesn't appear to be used. 00286 * See https://bugs.freedesktop.org/show_bug.cgi?id=97298 */ 00287 _DBUS_GNUC_UNUSED 00288 static const DBusAuthStateData client_state_waiting_for_ok = { 00289 "WaitingForOK", handle_client_state_waiting_for_ok 00290 }; 00291 static const DBusAuthStateData client_state_waiting_for_reject = { 00292 "WaitingForReject", handle_client_state_waiting_for_reject 00293 }; 00294 static const DBusAuthStateData client_state_waiting_for_agree_unix_fd = { 00295 "WaitingForAgreeUnixFD", handle_client_state_waiting_for_agree_unix_fd 00296 }; 00297 00302 static const DBusAuthStateData common_state_authenticated = { 00303 "Authenticated", NULL 00304 }; 00305 00306 static const DBusAuthStateData common_state_need_disconnect = { 00307 "NeedDisconnect", NULL 00308 }; 00309 00310 static const char auth_side_client[] = "client"; 00311 static const char auth_side_server[] = "server"; 00316 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server) 00317 00321 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client) 00322 00326 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth)) 00327 00331 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth)) 00332 00338 #define DBUS_AUTH_NAME(auth) ((auth)->side) 00339 00340 static DBusAuth* 00341 _dbus_auth_new (int size) 00342 { 00343 DBusAuth *auth; 00344 00345 auth = dbus_malloc0 (size); 00346 if (auth == NULL) 00347 return NULL; 00348 00349 auth->refcount = 1; 00350 00351 auth->keyring = NULL; 00352 auth->cookie_id = -1; 00353 00354 /* note that we don't use the max string length feature, 00355 * because you can't use that feature if you're going to 00356 * try to recover from out-of-memory (it creates 00357 * what looks like unrecoverable inability to alloc 00358 * more space in the string). But we do handle 00359 * overlong buffers in _dbus_auth_do_work(). 00360 */ 00361 00362 if (!_dbus_string_init (&auth->incoming)) 00363 goto enomem_0; 00364 00365 if (!_dbus_string_init (&auth->outgoing)) 00366 goto enomem_1; 00367 00368 if (!_dbus_string_init (&auth->identity)) 00369 goto enomem_2; 00370 00371 if (!_dbus_string_init (&auth->context)) 00372 goto enomem_3; 00373 00374 if (!_dbus_string_init (&auth->challenge)) 00375 goto enomem_4; 00376 00377 /* default context if none is specified */ 00378 if (!_dbus_string_append (&auth->context, "org_freedesktop_general")) 00379 goto enomem_5; 00380 00381 auth->credentials = _dbus_credentials_new (); 00382 if (auth->credentials == NULL) 00383 goto enomem_6; 00384 00385 auth->authorized_identity = _dbus_credentials_new (); 00386 if (auth->authorized_identity == NULL) 00387 goto enomem_7; 00388 00389 auth->desired_identity = _dbus_credentials_new (); 00390 if (auth->desired_identity == NULL) 00391 goto enomem_8; 00392 00393 return auth; 00394 00395 #if 0 00396 enomem_9: 00397 _dbus_credentials_unref (auth->desired_identity); 00398 #endif 00399 enomem_8: 00400 _dbus_credentials_unref (auth->authorized_identity); 00401 enomem_7: 00402 _dbus_credentials_unref (auth->credentials); 00403 enomem_6: 00404 /* last alloc was an append to context, which is freed already below */ ; 00405 enomem_5: 00406 _dbus_string_free (&auth->challenge); 00407 enomem_4: 00408 _dbus_string_free (&auth->context); 00409 enomem_3: 00410 _dbus_string_free (&auth->identity); 00411 enomem_2: 00412 _dbus_string_free (&auth->outgoing); 00413 enomem_1: 00414 _dbus_string_free (&auth->incoming); 00415 enomem_0: 00416 dbus_free (auth); 00417 return NULL; 00418 } 00419 00420 static void 00421 shutdown_mech (DBusAuth *auth) 00422 { 00423 /* Cancel any auth */ 00424 auth->already_asked_for_initial_response = FALSE; 00425 _dbus_string_set_length (&auth->identity, 0); 00426 00427 _dbus_credentials_clear (auth->authorized_identity); 00428 _dbus_credentials_clear (auth->desired_identity); 00429 00430 if (auth->mech != NULL) 00431 { 00432 _dbus_verbose ("%s: Shutting down mechanism %s\n", 00433 DBUS_AUTH_NAME (auth), auth->mech->mechanism); 00434 00435 if (DBUS_AUTH_IS_CLIENT (auth)) 00436 (* auth->mech->client_shutdown_func) (auth); 00437 else 00438 (* auth->mech->server_shutdown_func) (auth); 00439 00440 auth->mech = NULL; 00441 } 00442 } 00443 00444 /* 00445 * DBUS_COOKIE_SHA1 mechanism 00446 */ 00447 00448 /* Returns TRUE but with an empty string hash if the 00449 * cookie_id isn't known. As with all this code 00450 * TRUE just means we had enough memory. 00451 */ 00452 static dbus_bool_t 00453 sha1_compute_hash (DBusAuth *auth, 00454 int cookie_id, 00455 const DBusString *server_challenge, 00456 const DBusString *client_challenge, 00457 DBusString *hash) 00458 { 00459 DBusString cookie; 00460 DBusString to_hash; 00461 dbus_bool_t retval; 00462 00463 _dbus_assert (auth->keyring != NULL); 00464 00465 retval = FALSE; 00466 00467 if (!_dbus_string_init (&cookie)) 00468 return FALSE; 00469 00470 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id, 00471 &cookie)) 00472 goto out_0; 00473 00474 if (_dbus_string_get_length (&cookie) == 0) 00475 { 00476 retval = TRUE; 00477 goto out_0; 00478 } 00479 00480 if (!_dbus_string_init (&to_hash)) 00481 goto out_0; 00482 00483 if (!_dbus_string_copy (server_challenge, 0, 00484 &to_hash, _dbus_string_get_length (&to_hash))) 00485 goto out_1; 00486 00487 if (!_dbus_string_append (&to_hash, ":")) 00488 goto out_1; 00489 00490 if (!_dbus_string_copy (client_challenge, 0, 00491 &to_hash, _dbus_string_get_length (&to_hash))) 00492 goto out_1; 00493 00494 if (!_dbus_string_append (&to_hash, ":")) 00495 goto out_1; 00496 00497 if (!_dbus_string_copy (&cookie, 0, 00498 &to_hash, _dbus_string_get_length (&to_hash))) 00499 goto out_1; 00500 00501 if (!_dbus_sha_compute (&to_hash, hash)) 00502 goto out_1; 00503 00504 retval = TRUE; 00505 00506 out_1: 00507 _dbus_string_zero (&to_hash); 00508 _dbus_string_free (&to_hash); 00509 out_0: 00510 _dbus_string_zero (&cookie); 00511 _dbus_string_free (&cookie); 00512 return retval; 00513 } 00514 00519 #define N_CHALLENGE_BYTES (128/8) 00520 00521 static dbus_bool_t 00522 sha1_handle_first_client_response (DBusAuth *auth, 00523 const DBusString *data) 00524 { 00525 /* We haven't sent a challenge yet, we're expecting a desired 00526 * username from the client. 00527 */ 00528 DBusString tmp; 00529 DBusString tmp2; 00530 dbus_bool_t retval = FALSE; 00531 DBusError error = DBUS_ERROR_INIT; 00532 00533 _dbus_string_set_length (&auth->challenge, 0); 00534 00535 if (_dbus_string_get_length (data) > 0) 00536 { 00537 if (_dbus_string_get_length (&auth->identity) > 0) 00538 { 00539 /* Tried to send two auth identities, wtf */ 00540 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 00541 DBUS_AUTH_NAME (auth)); 00542 return send_rejected (auth); 00543 } 00544 else 00545 { 00546 /* this is our auth identity */ 00547 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 00548 return FALSE; 00549 } 00550 } 00551 00552 if (!_dbus_credentials_add_from_user (auth->desired_identity, data)) 00553 { 00554 _dbus_verbose ("%s: Did not get a valid username from client\n", 00555 DBUS_AUTH_NAME (auth)); 00556 return send_rejected (auth); 00557 } 00558 00559 if (!_dbus_string_init (&tmp)) 00560 return FALSE; 00561 00562 if (!_dbus_string_init (&tmp2)) 00563 { 00564 _dbus_string_free (&tmp); 00565 return FALSE; 00566 } 00567 00568 /* we cache the keyring for speed, so here we drop it if it's the 00569 * wrong one. FIXME caching the keyring here is useless since we use 00570 * a different DBusAuth for every connection. 00571 */ 00572 if (auth->keyring && 00573 !_dbus_keyring_is_for_credentials (auth->keyring, 00574 auth->desired_identity)) 00575 { 00576 _dbus_keyring_unref (auth->keyring); 00577 auth->keyring = NULL; 00578 } 00579 00580 if (auth->keyring == NULL) 00581 { 00582 auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity, 00583 &auth->context, 00584 &error); 00585 00586 if (auth->keyring == NULL) 00587 { 00588 if (dbus_error_has_name (&error, 00589 DBUS_ERROR_NO_MEMORY)) 00590 { 00591 dbus_error_free (&error); 00592 goto out; 00593 } 00594 else 00595 { 00596 _DBUS_ASSERT_ERROR_IS_SET (&error); 00597 _dbus_verbose ("%s: Error loading keyring: %s\n", 00598 DBUS_AUTH_NAME (auth), error.message); 00599 if (send_rejected (auth)) 00600 retval = TRUE; /* retval is only about mem */ 00601 dbus_error_free (&error); 00602 goto out; 00603 } 00604 } 00605 else 00606 { 00607 _dbus_assert (!dbus_error_is_set (&error)); 00608 } 00609 } 00610 00611 _dbus_assert (auth->keyring != NULL); 00612 00613 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); 00614 if (auth->cookie_id < 0) 00615 { 00616 _DBUS_ASSERT_ERROR_IS_SET (&error); 00617 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n", 00618 DBUS_AUTH_NAME (auth), error.message); 00619 if (send_rejected (auth)) 00620 retval = TRUE; 00621 dbus_error_free (&error); 00622 goto out; 00623 } 00624 else 00625 { 00626 _dbus_assert (!dbus_error_is_set (&error)); 00627 } 00628 00629 if (!_dbus_string_copy (&auth->context, 0, 00630 &tmp2, _dbus_string_get_length (&tmp2))) 00631 goto out; 00632 00633 if (!_dbus_string_append (&tmp2, " ")) 00634 goto out; 00635 00636 if (!_dbus_string_append_int (&tmp2, auth->cookie_id)) 00637 goto out; 00638 00639 if (!_dbus_string_append (&tmp2, " ")) 00640 goto out; 00641 00642 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error)) 00643 { 00644 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 00645 { 00646 dbus_error_free (&error); 00647 goto out; 00648 } 00649 else 00650 { 00651 _DBUS_ASSERT_ERROR_IS_SET (&error); 00652 _dbus_verbose ("%s: Error generating challenge: %s\n", 00653 DBUS_AUTH_NAME (auth), error.message); 00654 if (send_rejected (auth)) 00655 retval = TRUE; /* retval is only about mem */ 00656 00657 dbus_error_free (&error); 00658 goto out; 00659 } 00660 } 00661 00662 _dbus_string_set_length (&auth->challenge, 0); 00663 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0)) 00664 goto out; 00665 00666 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2, 00667 _dbus_string_get_length (&tmp2))) 00668 goto out; 00669 00670 if (!send_data (auth, &tmp2)) 00671 goto out; 00672 00673 goto_state (auth, &server_state_waiting_for_data); 00674 retval = TRUE; 00675 00676 out: 00677 _dbus_string_zero (&tmp); 00678 _dbus_string_free (&tmp); 00679 _dbus_string_zero (&tmp2); 00680 _dbus_string_free (&tmp2); 00681 00682 return retval; 00683 } 00684 00685 static dbus_bool_t 00686 sha1_handle_second_client_response (DBusAuth *auth, 00687 const DBusString *data) 00688 { 00689 /* We are expecting a response which is the hex-encoded client 00690 * challenge, space, then SHA-1 hash of the concatenation of our 00691 * challenge, ":", client challenge, ":", secret key, all 00692 * hex-encoded. 00693 */ 00694 int i; 00695 DBusString client_challenge; 00696 DBusString client_hash; 00697 dbus_bool_t retval; 00698 DBusString correct_hash; 00699 00700 retval = FALSE; 00701 00702 if (!_dbus_string_find_blank (data, 0, &i)) 00703 { 00704 _dbus_verbose ("%s: no space separator in client response\n", 00705 DBUS_AUTH_NAME (auth)); 00706 return send_rejected (auth); 00707 } 00708 00709 if (!_dbus_string_init (&client_challenge)) 00710 goto out_0; 00711 00712 if (!_dbus_string_init (&client_hash)) 00713 goto out_1; 00714 00715 if (!_dbus_string_copy_len (data, 0, i, &client_challenge, 00716 0)) 00717 goto out_2; 00718 00719 _dbus_string_skip_blank (data, i, &i); 00720 00721 if (!_dbus_string_copy_len (data, i, 00722 _dbus_string_get_length (data) - i, 00723 &client_hash, 00724 0)) 00725 goto out_2; 00726 00727 if (_dbus_string_get_length (&client_challenge) == 0 || 00728 _dbus_string_get_length (&client_hash) == 0) 00729 { 00730 _dbus_verbose ("%s: zero-length client challenge or hash\n", 00731 DBUS_AUTH_NAME (auth)); 00732 if (send_rejected (auth)) 00733 retval = TRUE; 00734 goto out_2; 00735 } 00736 00737 if (!_dbus_string_init (&correct_hash)) 00738 goto out_2; 00739 00740 if (!sha1_compute_hash (auth, auth->cookie_id, 00741 &auth->challenge, 00742 &client_challenge, 00743 &correct_hash)) 00744 goto out_3; 00745 00746 /* if cookie_id was invalid, then we get an empty hash */ 00747 if (_dbus_string_get_length (&correct_hash) == 0) 00748 { 00749 if (send_rejected (auth)) 00750 retval = TRUE; 00751 goto out_3; 00752 } 00753 00754 if (!_dbus_string_equal (&client_hash, &correct_hash)) 00755 { 00756 if (send_rejected (auth)) 00757 retval = TRUE; 00758 goto out_3; 00759 } 00760 00761 if (!_dbus_credentials_add_credentials (auth->authorized_identity, 00762 auth->desired_identity)) 00763 goto out_3; 00764 00765 /* Copy process ID from the socket credentials if it's there 00766 */ 00767 if (!_dbus_credentials_add_credential (auth->authorized_identity, 00768 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 00769 auth->credentials)) 00770 goto out_3; 00771 00772 if (!send_ok (auth)) 00773 goto out_3; 00774 00775 _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n", 00776 DBUS_AUTH_NAME (auth)); 00777 00778 retval = TRUE; 00779 00780 out_3: 00781 _dbus_string_zero (&correct_hash); 00782 _dbus_string_free (&correct_hash); 00783 out_2: 00784 _dbus_string_zero (&client_hash); 00785 _dbus_string_free (&client_hash); 00786 out_1: 00787 _dbus_string_free (&client_challenge); 00788 out_0: 00789 return retval; 00790 } 00791 00792 static dbus_bool_t 00793 handle_server_data_cookie_sha1_mech (DBusAuth *auth, 00794 const DBusString *data) 00795 { 00796 if (auth->cookie_id < 0) 00797 return sha1_handle_first_client_response (auth, data); 00798 else 00799 return sha1_handle_second_client_response (auth, data); 00800 } 00801 00802 static void 00803 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth) 00804 { 00805 auth->cookie_id = -1; 00806 _dbus_string_set_length (&auth->challenge, 0); 00807 } 00808 00809 static dbus_bool_t 00810 handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth, 00811 DBusString *response) 00812 { 00813 DBusString username; 00814 dbus_bool_t retval; 00815 00816 retval = FALSE; 00817 00818 if (!_dbus_string_init (&username)) 00819 return FALSE; 00820 00821 if (!_dbus_append_user_from_current_process (&username)) 00822 goto out_0; 00823 00824 if (!_dbus_string_hex_encode (&username, 0, 00825 response, 00826 _dbus_string_get_length (response))) 00827 goto out_0; 00828 00829 retval = TRUE; 00830 00831 out_0: 00832 _dbus_string_free (&username); 00833 00834 return retval; 00835 } 00836 00837 static dbus_bool_t 00838 handle_client_data_cookie_sha1_mech (DBusAuth *auth, 00839 const DBusString *data) 00840 { 00841 /* The data we get from the server should be the cookie context 00842 * name, the cookie ID, and the server challenge, separated by 00843 * spaces. We send back our challenge string and the correct hash. 00844 */ 00845 dbus_bool_t retval = FALSE; 00846 DBusString context; 00847 DBusString cookie_id_str; 00848 DBusString server_challenge; 00849 DBusString client_challenge; 00850 DBusString correct_hash; 00851 DBusString tmp; 00852 int i, j; 00853 long val; 00854 DBusError error = DBUS_ERROR_INIT; 00855 00856 if (!_dbus_string_find_blank (data, 0, &i)) 00857 { 00858 if (send_error (auth, 00859 "Server did not send context/ID/challenge properly")) 00860 retval = TRUE; 00861 goto out_0; 00862 } 00863 00864 if (!_dbus_string_init (&context)) 00865 goto out_0; 00866 00867 if (!_dbus_string_copy_len (data, 0, i, 00868 &context, 0)) 00869 goto out_1; 00870 00871 _dbus_string_skip_blank (data, i, &i); 00872 if (!_dbus_string_find_blank (data, i, &j)) 00873 { 00874 if (send_error (auth, 00875 "Server did not send context/ID/challenge properly")) 00876 retval = TRUE; 00877 goto out_1; 00878 } 00879 00880 if (!_dbus_string_init (&cookie_id_str)) 00881 goto out_1; 00882 00883 if (!_dbus_string_copy_len (data, i, j - i, 00884 &cookie_id_str, 0)) 00885 goto out_2; 00886 00887 if (!_dbus_string_init (&server_challenge)) 00888 goto out_2; 00889 00890 i = j; 00891 _dbus_string_skip_blank (data, i, &i); 00892 j = _dbus_string_get_length (data); 00893 00894 if (!_dbus_string_copy_len (data, i, j - i, 00895 &server_challenge, 0)) 00896 goto out_3; 00897 00898 if (!_dbus_keyring_validate_context (&context)) 00899 { 00900 if (send_error (auth, "Server sent invalid cookie context")) 00901 retval = TRUE; 00902 goto out_3; 00903 } 00904 00905 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL)) 00906 { 00907 if (send_error (auth, "Could not parse cookie ID as an integer")) 00908 retval = TRUE; 00909 goto out_3; 00910 } 00911 00912 if (_dbus_string_get_length (&server_challenge) == 0) 00913 { 00914 if (send_error (auth, "Empty server challenge string")) 00915 retval = TRUE; 00916 goto out_3; 00917 } 00918 00919 if (auth->keyring == NULL) 00920 { 00921 auth->keyring = _dbus_keyring_new_for_credentials (NULL, 00922 &context, 00923 &error); 00924 00925 if (auth->keyring == NULL) 00926 { 00927 if (dbus_error_has_name (&error, 00928 DBUS_ERROR_NO_MEMORY)) 00929 { 00930 dbus_error_free (&error); 00931 goto out_3; 00932 } 00933 else 00934 { 00935 _DBUS_ASSERT_ERROR_IS_SET (&error); 00936 00937 _dbus_verbose ("%s: Error loading keyring: %s\n", 00938 DBUS_AUTH_NAME (auth), error.message); 00939 00940 if (send_error (auth, "Could not load cookie file")) 00941 retval = TRUE; /* retval is only about mem */ 00942 00943 dbus_error_free (&error); 00944 goto out_3; 00945 } 00946 } 00947 else 00948 { 00949 _dbus_assert (!dbus_error_is_set (&error)); 00950 } 00951 } 00952 00953 _dbus_assert (auth->keyring != NULL); 00954 00955 if (!_dbus_string_init (&tmp)) 00956 goto out_3; 00957 00958 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES, &error)) 00959 { 00960 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 00961 { 00962 dbus_error_free (&error); 00963 goto out_4; 00964 } 00965 else 00966 { 00967 _DBUS_ASSERT_ERROR_IS_SET (&error); 00968 00969 _dbus_verbose ("%s: Failed to generate challenge: %s\n", 00970 DBUS_AUTH_NAME (auth), error.message); 00971 00972 if (send_error (auth, "Failed to generate challenge")) 00973 retval = TRUE; /* retval is only about mem */ 00974 00975 dbus_error_free (&error); 00976 goto out_4; 00977 } 00978 } 00979 00980 if (!_dbus_string_init (&client_challenge)) 00981 goto out_4; 00982 00983 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0)) 00984 goto out_5; 00985 00986 if (!_dbus_string_init (&correct_hash)) 00987 goto out_5; 00988 00989 if (!sha1_compute_hash (auth, val, 00990 &server_challenge, 00991 &client_challenge, 00992 &correct_hash)) 00993 goto out_6; 00994 00995 if (_dbus_string_get_length (&correct_hash) == 0) 00996 { 00997 /* couldn't find the cookie ID or something */ 00998 if (send_error (auth, "Don't have the requested cookie ID")) 00999 retval = TRUE; 01000 goto out_6; 01001 } 01002 01003 _dbus_string_set_length (&tmp, 0); 01004 01005 if (!_dbus_string_copy (&client_challenge, 0, &tmp, 01006 _dbus_string_get_length (&tmp))) 01007 goto out_6; 01008 01009 if (!_dbus_string_append (&tmp, " ")) 01010 goto out_6; 01011 01012 if (!_dbus_string_copy (&correct_hash, 0, &tmp, 01013 _dbus_string_get_length (&tmp))) 01014 goto out_6; 01015 01016 if (!send_data (auth, &tmp)) 01017 goto out_6; 01018 01019 retval = TRUE; 01020 01021 out_6: 01022 _dbus_string_zero (&correct_hash); 01023 _dbus_string_free (&correct_hash); 01024 out_5: 01025 _dbus_string_free (&client_challenge); 01026 out_4: 01027 _dbus_string_zero (&tmp); 01028 _dbus_string_free (&tmp); 01029 out_3: 01030 _dbus_string_free (&server_challenge); 01031 out_2: 01032 _dbus_string_free (&cookie_id_str); 01033 out_1: 01034 _dbus_string_free (&context); 01035 out_0: 01036 return retval; 01037 } 01038 01039 static void 01040 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth) 01041 { 01042 auth->cookie_id = -1; 01043 _dbus_string_set_length (&auth->challenge, 0); 01044 } 01045 01046 /* 01047 * EXTERNAL mechanism 01048 */ 01049 01050 static dbus_bool_t 01051 handle_server_data_external_mech (DBusAuth *auth, 01052 const DBusString *data) 01053 { 01054 if (_dbus_credentials_are_anonymous (auth->credentials)) 01055 { 01056 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n", 01057 DBUS_AUTH_NAME (auth)); 01058 return send_rejected (auth); 01059 } 01060 01061 if (_dbus_string_get_length (data) > 0) 01062 { 01063 if (_dbus_string_get_length (&auth->identity) > 0) 01064 { 01065 /* Tried to send two auth identities, wtf */ 01066 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 01067 DBUS_AUTH_NAME (auth)); 01068 return send_rejected (auth); 01069 } 01070 else 01071 { 01072 /* this is our auth identity */ 01073 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 01074 return FALSE; 01075 } 01076 } 01077 01078 /* Poke client for an auth identity, if none given */ 01079 if (_dbus_string_get_length (&auth->identity) == 0 && 01080 !auth->already_asked_for_initial_response) 01081 { 01082 if (send_data (auth, NULL)) 01083 { 01084 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n", 01085 DBUS_AUTH_NAME (auth)); 01086 auth->already_asked_for_initial_response = TRUE; 01087 goto_state (auth, &server_state_waiting_for_data); 01088 return TRUE; 01089 } 01090 else 01091 return FALSE; 01092 } 01093 01094 _dbus_credentials_clear (auth->desired_identity); 01095 01096 /* If auth->identity is still empty here, then client 01097 * responded with an empty string after we poked it for 01098 * an initial response. This means to try to auth the 01099 * identity provided in the credentials. 01100 */ 01101 if (_dbus_string_get_length (&auth->identity) == 0) 01102 { 01103 if (!_dbus_credentials_add_credentials (auth->desired_identity, 01104 auth->credentials)) 01105 { 01106 return FALSE; /* OOM */ 01107 } 01108 } 01109 else 01110 { 01111 if (!_dbus_credentials_add_from_user (auth->desired_identity, 01112 &auth->identity)) 01113 { 01114 _dbus_verbose ("%s: could not get credentials from uid string\n", 01115 DBUS_AUTH_NAME (auth)); 01116 return send_rejected (auth); 01117 } 01118 } 01119 01120 if (_dbus_credentials_are_anonymous (auth->desired_identity)) 01121 { 01122 _dbus_verbose ("%s: desired user %s is no good\n", 01123 DBUS_AUTH_NAME (auth), 01124 _dbus_string_get_const_data (&auth->identity)); 01125 return send_rejected (auth); 01126 } 01127 01128 if (_dbus_credentials_are_superset (auth->credentials, 01129 auth->desired_identity)) 01130 { 01131 /* client has authenticated */ 01132 if (!_dbus_credentials_add_credentials (auth->authorized_identity, 01133 auth->desired_identity)) 01134 return FALSE; 01135 01136 /* also copy misc process info from the socket credentials 01137 */ 01138 if (!_dbus_credentials_add_credential (auth->authorized_identity, 01139 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 01140 auth->credentials)) 01141 return FALSE; 01142 01143 if (!_dbus_credentials_add_credential (auth->authorized_identity, 01144 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, 01145 auth->credentials)) 01146 return FALSE; 01147 01148 if (!_dbus_credentials_add_credential (auth->authorized_identity, 01149 DBUS_CREDENTIAL_LINUX_SECURITY_LABEL, 01150 auth->credentials)) 01151 return FALSE; 01152 01153 if (!send_ok (auth)) 01154 return FALSE; 01155 01156 _dbus_verbose ("%s: authenticated client based on socket credentials\n", 01157 DBUS_AUTH_NAME (auth)); 01158 01159 return TRUE; 01160 } 01161 else 01162 { 01163 _dbus_verbose ("%s: desired identity not found in socket credentials\n", 01164 DBUS_AUTH_NAME (auth)); 01165 return send_rejected (auth); 01166 } 01167 } 01168 01169 static void 01170 handle_server_shutdown_external_mech (DBusAuth *auth) 01171 { 01172 01173 } 01174 01175 static dbus_bool_t 01176 handle_client_initial_response_external_mech (DBusAuth *auth, 01177 DBusString *response) 01178 { 01179 /* We always append our UID as an initial response, so the server 01180 * doesn't have to send back an empty challenge to check whether we 01181 * want to specify an identity. i.e. this avoids a round trip that 01182 * the spec for the EXTERNAL mechanism otherwise requires. 01183 */ 01184 DBusString plaintext; 01185 01186 if (!_dbus_string_init (&plaintext)) 01187 return FALSE; 01188 01189 if (!_dbus_append_user_from_current_process (&plaintext)) 01190 goto failed; 01191 01192 if (!_dbus_string_hex_encode (&plaintext, 0, 01193 response, 01194 _dbus_string_get_length (response))) 01195 goto failed; 01196 01197 _dbus_string_free (&plaintext); 01198 01199 return TRUE; 01200 01201 failed: 01202 _dbus_string_free (&plaintext); 01203 return FALSE; 01204 } 01205 01206 static dbus_bool_t 01207 handle_client_data_external_mech (DBusAuth *auth, 01208 const DBusString *data) 01209 { 01210 01211 return TRUE; 01212 } 01213 01214 static void 01215 handle_client_shutdown_external_mech (DBusAuth *auth) 01216 { 01217 01218 } 01219 01220 /* 01221 * ANONYMOUS mechanism 01222 */ 01223 01224 static dbus_bool_t 01225 handle_server_data_anonymous_mech (DBusAuth *auth, 01226 const DBusString *data) 01227 { 01228 if (_dbus_string_get_length (data) > 0) 01229 { 01230 /* Client is allowed to send "trace" data, the only defined 01231 * meaning is that if it contains '@' it is an email address, 01232 * and otherwise it is anything else, and it's supposed to be 01233 * UTF-8 01234 */ 01235 if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data))) 01236 { 01237 _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n", 01238 DBUS_AUTH_NAME (auth)); 01239 return send_rejected (auth); 01240 } 01241 01242 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", 01243 DBUS_AUTH_NAME (auth), 01244 _dbus_string_get_const_data (data)); 01245 } 01246 01247 /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ 01248 _dbus_credentials_clear (auth->desired_identity); 01249 01250 /* Copy process ID from the socket credentials 01251 */ 01252 if (!_dbus_credentials_add_credential (auth->authorized_identity, 01253 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 01254 auth->credentials)) 01255 return FALSE; 01256 01257 /* Anonymous is always allowed */ 01258 if (!send_ok (auth)) 01259 return FALSE; 01260 01261 _dbus_verbose ("%s: authenticated client as anonymous\n", 01262 DBUS_AUTH_NAME (auth)); 01263 01264 return TRUE; 01265 } 01266 01267 static void 01268 handle_server_shutdown_anonymous_mech (DBusAuth *auth) 01269 { 01270 01271 } 01272 01273 static dbus_bool_t 01274 handle_client_initial_response_anonymous_mech (DBusAuth *auth, 01275 DBusString *response) 01276 { 01277 /* Our initial response is a "trace" string which must be valid UTF-8 01278 * and must be an email address if it contains '@'. 01279 * We just send the dbus implementation info, like a user-agent or 01280 * something, because... why not. There's nothing guaranteed here 01281 * though, we could change it later. 01282 */ 01283 DBusString plaintext; 01284 01285 if (!_dbus_string_init (&plaintext)) 01286 return FALSE; 01287 01288 if (!_dbus_string_append (&plaintext, 01289 "libdbus " DBUS_VERSION_STRING)) 01290 goto failed; 01291 01292 if (!_dbus_string_hex_encode (&plaintext, 0, 01293 response, 01294 _dbus_string_get_length (response))) 01295 goto failed; 01296 01297 _dbus_string_free (&plaintext); 01298 01299 return TRUE; 01300 01301 failed: 01302 _dbus_string_free (&plaintext); 01303 return FALSE; 01304 } 01305 01306 static dbus_bool_t 01307 handle_client_data_anonymous_mech (DBusAuth *auth, 01308 const DBusString *data) 01309 { 01310 01311 return TRUE; 01312 } 01313 01314 static void 01315 handle_client_shutdown_anonymous_mech (DBusAuth *auth) 01316 { 01317 01318 } 01319 01320 /* Put mechanisms here in order of preference. 01321 * Right now we have: 01322 * 01323 * - EXTERNAL checks socket credentials (or in the future, other info from the OS) 01324 * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE 01325 * - ANONYMOUS checks nothing but doesn't auth the person as a user 01326 * 01327 * We might ideally add a mechanism to chain to Cyrus SASL so we can 01328 * use its mechanisms as well. 01329 * 01330 */ 01331 static const DBusAuthMechanismHandler 01332 all_mechanisms[] = { 01333 { "EXTERNAL", 01334 handle_server_data_external_mech, 01335 NULL, NULL, 01336 handle_server_shutdown_external_mech, 01337 handle_client_initial_response_external_mech, 01338 handle_client_data_external_mech, 01339 NULL, NULL, 01340 handle_client_shutdown_external_mech }, 01341 { "DBUS_COOKIE_SHA1", 01342 handle_server_data_cookie_sha1_mech, 01343 NULL, NULL, 01344 handle_server_shutdown_cookie_sha1_mech, 01345 handle_client_initial_response_cookie_sha1_mech, 01346 handle_client_data_cookie_sha1_mech, 01347 NULL, NULL, 01348 handle_client_shutdown_cookie_sha1_mech }, 01349 { "ANONYMOUS", 01350 handle_server_data_anonymous_mech, 01351 NULL, NULL, 01352 handle_server_shutdown_anonymous_mech, 01353 handle_client_initial_response_anonymous_mech, 01354 handle_client_data_anonymous_mech, 01355 NULL, NULL, 01356 handle_client_shutdown_anonymous_mech }, 01357 { NULL, NULL } 01358 }; 01359 01360 static const DBusAuthMechanismHandler* 01361 find_mech (const DBusString *name, 01362 char **allowed_mechs) 01363 { 01364 int i; 01365 01366 if (allowed_mechs != NULL && 01367 !_dbus_string_array_contains ((const char**) allowed_mechs, 01368 _dbus_string_get_const_data (name))) 01369 return NULL; 01370 01371 i = 0; 01372 while (all_mechanisms[i].mechanism != NULL) 01373 { 01374 if (_dbus_string_equal_c_str (name, 01375 all_mechanisms[i].mechanism)) 01376 01377 return &all_mechanisms[i]; 01378 01379 ++i; 01380 } 01381 01382 return NULL; 01383 } 01384 01385 static dbus_bool_t 01386 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) 01387 { 01388 DBusString auth_command; 01389 01390 if (!_dbus_string_init (&auth_command)) 01391 return FALSE; 01392 01393 if (!_dbus_string_append (&auth_command, 01394 "AUTH ")) 01395 { 01396 _dbus_string_free (&auth_command); 01397 return FALSE; 01398 } 01399 01400 if (!_dbus_string_append (&auth_command, 01401 mech->mechanism)) 01402 { 01403 _dbus_string_free (&auth_command); 01404 return FALSE; 01405 } 01406 01407 if (mech->client_initial_response_func != NULL) 01408 { 01409 if (!_dbus_string_append (&auth_command, " ")) 01410 { 01411 _dbus_string_free (&auth_command); 01412 return FALSE; 01413 } 01414 01415 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 01416 { 01417 _dbus_string_free (&auth_command); 01418 return FALSE; 01419 } 01420 } 01421 01422 if (!_dbus_string_append (&auth_command, 01423 "\r\n")) 01424 { 01425 _dbus_string_free (&auth_command); 01426 return FALSE; 01427 } 01428 01429 if (!_dbus_string_copy (&auth_command, 0, 01430 &auth->outgoing, 01431 _dbus_string_get_length (&auth->outgoing))) 01432 { 01433 _dbus_string_free (&auth_command); 01434 return FALSE; 01435 } 01436 01437 _dbus_string_free (&auth_command); 01438 shutdown_mech (auth); 01439 auth->mech = mech; 01440 goto_state (auth, &client_state_waiting_for_data); 01441 01442 return TRUE; 01443 } 01444 01445 static dbus_bool_t 01446 send_data (DBusAuth *auth, DBusString *data) 01447 { 01448 int old_len; 01449 01450 if (data == NULL || _dbus_string_get_length (data) == 0) 01451 return _dbus_string_append (&auth->outgoing, "DATA\r\n"); 01452 else 01453 { 01454 old_len = _dbus_string_get_length (&auth->outgoing); 01455 if (!_dbus_string_append (&auth->outgoing, "DATA ")) 01456 goto out; 01457 01458 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, 01459 _dbus_string_get_length (&auth->outgoing))) 01460 goto out; 01461 01462 if (!_dbus_string_append (&auth->outgoing, "\r\n")) 01463 goto out; 01464 01465 return TRUE; 01466 01467 out: 01468 _dbus_string_set_length (&auth->outgoing, old_len); 01469 01470 return FALSE; 01471 } 01472 } 01473 01474 static dbus_bool_t 01475 send_rejected (DBusAuth *auth) 01476 { 01477 DBusString command; 01478 DBusAuthServer *server_auth; 01479 int i; 01480 01481 if (!_dbus_string_init (&command)) 01482 return FALSE; 01483 01484 if (!_dbus_string_append (&command, 01485 "REJECTED")) 01486 goto nomem; 01487 01488 i = 0; 01489 while (all_mechanisms[i].mechanism != NULL) 01490 { 01491 if (!_dbus_string_append (&command, 01492 " ")) 01493 goto nomem; 01494 01495 if (!_dbus_string_append (&command, 01496 all_mechanisms[i].mechanism)) 01497 goto nomem; 01498 01499 ++i; 01500 } 01501 01502 if (!_dbus_string_append (&command, "\r\n")) 01503 goto nomem; 01504 01505 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 01506 _dbus_string_get_length (&auth->outgoing))) 01507 goto nomem; 01508 01509 shutdown_mech (auth); 01510 01511 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 01512 server_auth = DBUS_AUTH_SERVER (auth); 01513 server_auth->failures += 1; 01514 01515 if (server_auth->failures >= server_auth->max_failures) 01516 goto_state (auth, &common_state_need_disconnect); 01517 else 01518 goto_state (auth, &server_state_waiting_for_auth); 01519 01520 _dbus_string_free (&command); 01521 01522 return TRUE; 01523 01524 nomem: 01525 _dbus_string_free (&command); 01526 return FALSE; 01527 } 01528 01529 static dbus_bool_t 01530 send_error (DBusAuth *auth, const char *message) 01531 { 01532 return _dbus_string_append_printf (&auth->outgoing, 01533 "ERROR \"%s\"\r\n", message); 01534 } 01535 01536 static dbus_bool_t 01537 send_ok (DBusAuth *auth) 01538 { 01539 int orig_len; 01540 01541 orig_len = _dbus_string_get_length (&auth->outgoing); 01542 01543 if (_dbus_string_append (&auth->outgoing, "OK ") && 01544 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, 01545 0, 01546 &auth->outgoing, 01547 _dbus_string_get_length (&auth->outgoing)) && 01548 _dbus_string_append (&auth->outgoing, "\r\n")) 01549 { 01550 goto_state (auth, &server_state_waiting_for_begin); 01551 return TRUE; 01552 } 01553 else 01554 { 01555 _dbus_string_set_length (&auth->outgoing, orig_len); 01556 return FALSE; 01557 } 01558 } 01559 01560 static dbus_bool_t 01561 send_begin (DBusAuth *auth) 01562 { 01563 01564 if (!_dbus_string_append (&auth->outgoing, 01565 "BEGIN\r\n")) 01566 return FALSE; 01567 01568 goto_state (auth, &common_state_authenticated); 01569 return TRUE; 01570 } 01571 01572 static dbus_bool_t 01573 process_ok(DBusAuth *auth, 01574 const DBusString *args_from_ok) { 01575 01576 int end_of_hex; 01577 01578 /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ 01579 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); 01580 01581 /* We decode the hex string to binary, using guid_from_server as scratch... */ 01582 01583 end_of_hex = 0; 01584 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, 01585 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) 01586 return FALSE; 01587 01588 /* now clear out the scratch */ 01589 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 01590 01591 if (end_of_hex != _dbus_string_get_length (args_from_ok) || 01592 end_of_hex == 0) 01593 { 01594 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", 01595 end_of_hex, _dbus_string_get_length (args_from_ok)); 01596 goto_state (auth, &common_state_need_disconnect); 01597 return TRUE; 01598 } 01599 01600 if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) { 01601 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 01602 return FALSE; 01603 } 01604 01605 _dbus_verbose ("Got GUID '%s' from the server\n", 01606 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); 01607 01608 if (auth->unix_fd_possible) 01609 return send_negotiate_unix_fd(auth); 01610 01611 _dbus_verbose("Not negotiating unix fd passing, since not possible\n"); 01612 return send_begin (auth); 01613 } 01614 01615 static dbus_bool_t 01616 send_cancel (DBusAuth *auth) 01617 { 01618 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) 01619 { 01620 goto_state (auth, &client_state_waiting_for_reject); 01621 return TRUE; 01622 } 01623 else 01624 return FALSE; 01625 } 01626 01627 static dbus_bool_t 01628 process_data (DBusAuth *auth, 01629 const DBusString *args, 01630 DBusAuthDataFunction data_func) 01631 { 01632 int end; 01633 DBusString decoded; 01634 01635 if (!_dbus_string_init (&decoded)) 01636 return FALSE; 01637 01638 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) 01639 { 01640 _dbus_string_free (&decoded); 01641 return FALSE; 01642 } 01643 01644 if (_dbus_string_get_length (args) != end) 01645 { 01646 _dbus_string_free (&decoded); 01647 if (!send_error (auth, "Invalid hex encoding")) 01648 return FALSE; 01649 01650 return TRUE; 01651 } 01652 01653 #ifdef DBUS_ENABLE_VERBOSE_MODE 01654 if (_dbus_string_validate_ascii (&decoded, 0, 01655 _dbus_string_get_length (&decoded))) 01656 _dbus_verbose ("%s: data: '%s'\n", 01657 DBUS_AUTH_NAME (auth), 01658 _dbus_string_get_const_data (&decoded)); 01659 #endif 01660 01661 if (!(* data_func) (auth, &decoded)) 01662 { 01663 _dbus_string_free (&decoded); 01664 return FALSE; 01665 } 01666 01667 _dbus_string_free (&decoded); 01668 return TRUE; 01669 } 01670 01671 static dbus_bool_t 01672 send_negotiate_unix_fd (DBusAuth *auth) 01673 { 01674 if (!_dbus_string_append (&auth->outgoing, 01675 "NEGOTIATE_UNIX_FD\r\n")) 01676 return FALSE; 01677 01678 goto_state (auth, &client_state_waiting_for_agree_unix_fd); 01679 return TRUE; 01680 } 01681 01682 static dbus_bool_t 01683 send_agree_unix_fd (DBusAuth *auth) 01684 { 01685 _dbus_assert(auth->unix_fd_possible); 01686 01687 auth->unix_fd_negotiated = TRUE; 01688 _dbus_verbose("Agreed to UNIX FD passing\n"); 01689 01690 if (!_dbus_string_append (&auth->outgoing, 01691 "AGREE_UNIX_FD\r\n")) 01692 return FALSE; 01693 01694 goto_state (auth, &server_state_waiting_for_begin); 01695 return TRUE; 01696 } 01697 01698 static dbus_bool_t 01699 handle_auth (DBusAuth *auth, const DBusString *args) 01700 { 01701 if (_dbus_string_get_length (args) == 0) 01702 { 01703 /* No args to the auth, send mechanisms */ 01704 if (!send_rejected (auth)) 01705 return FALSE; 01706 01707 return TRUE; 01708 } 01709 else 01710 { 01711 int i; 01712 DBusString mech; 01713 DBusString hex_response; 01714 01715 _dbus_string_find_blank (args, 0, &i); 01716 01717 if (!_dbus_string_init (&mech)) 01718 return FALSE; 01719 01720 if (!_dbus_string_init (&hex_response)) 01721 { 01722 _dbus_string_free (&mech); 01723 return FALSE; 01724 } 01725 01726 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 01727 goto failed; 01728 01729 _dbus_string_skip_blank (args, i, &i); 01730 if (!_dbus_string_copy (args, i, &hex_response, 0)) 01731 goto failed; 01732 01733 auth->mech = find_mech (&mech, auth->allowed_mechs); 01734 if (auth->mech != NULL) 01735 { 01736 _dbus_verbose ("%s: Trying mechanism %s\n", 01737 DBUS_AUTH_NAME (auth), 01738 auth->mech->mechanism); 01739 01740 if (!process_data (auth, &hex_response, 01741 auth->mech->server_data_func)) 01742 goto failed; 01743 } 01744 else 01745 { 01746 /* Unsupported mechanism */ 01747 _dbus_verbose ("%s: Unsupported mechanism %s\n", 01748 DBUS_AUTH_NAME (auth), 01749 _dbus_string_get_const_data (&mech)); 01750 01751 if (!send_rejected (auth)) 01752 goto failed; 01753 } 01754 01755 _dbus_string_free (&mech); 01756 _dbus_string_free (&hex_response); 01757 01758 return TRUE; 01759 01760 failed: 01761 auth->mech = NULL; 01762 _dbus_string_free (&mech); 01763 _dbus_string_free (&hex_response); 01764 return FALSE; 01765 } 01766 } 01767 01768 static dbus_bool_t 01769 handle_server_state_waiting_for_auth (DBusAuth *auth, 01770 DBusAuthCommand command, 01771 const DBusString *args) 01772 { 01773 switch (command) 01774 { 01775 case DBUS_AUTH_COMMAND_AUTH: 01776 return handle_auth (auth, args); 01777 01778 case DBUS_AUTH_COMMAND_CANCEL: 01779 case DBUS_AUTH_COMMAND_DATA: 01780 return send_error (auth, "Not currently in an auth conversation"); 01781 01782 case DBUS_AUTH_COMMAND_BEGIN: 01783 goto_state (auth, &common_state_need_disconnect); 01784 return TRUE; 01785 01786 case DBUS_AUTH_COMMAND_ERROR: 01787 return send_rejected (auth); 01788 01789 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01790 return send_error (auth, "Need to authenticate first"); 01791 01792 case DBUS_AUTH_COMMAND_REJECTED: 01793 case DBUS_AUTH_COMMAND_OK: 01794 case DBUS_AUTH_COMMAND_UNKNOWN: 01795 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01796 default: 01797 return send_error (auth, "Unknown command"); 01798 } 01799 } 01800 01801 static dbus_bool_t 01802 handle_server_state_waiting_for_data (DBusAuth *auth, 01803 DBusAuthCommand command, 01804 const DBusString *args) 01805 { 01806 switch (command) 01807 { 01808 case DBUS_AUTH_COMMAND_AUTH: 01809 return send_error (auth, "Sent AUTH while another AUTH in progress"); 01810 01811 case DBUS_AUTH_COMMAND_CANCEL: 01812 case DBUS_AUTH_COMMAND_ERROR: 01813 return send_rejected (auth); 01814 01815 case DBUS_AUTH_COMMAND_DATA: 01816 return process_data (auth, args, auth->mech->server_data_func); 01817 01818 case DBUS_AUTH_COMMAND_BEGIN: 01819 goto_state (auth, &common_state_need_disconnect); 01820 return TRUE; 01821 01822 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01823 return send_error (auth, "Need to authenticate first"); 01824 01825 case DBUS_AUTH_COMMAND_REJECTED: 01826 case DBUS_AUTH_COMMAND_OK: 01827 case DBUS_AUTH_COMMAND_UNKNOWN: 01828 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01829 default: 01830 return send_error (auth, "Unknown command"); 01831 } 01832 } 01833 01834 static dbus_bool_t 01835 handle_server_state_waiting_for_begin (DBusAuth *auth, 01836 DBusAuthCommand command, 01837 const DBusString *args) 01838 { 01839 switch (command) 01840 { 01841 case DBUS_AUTH_COMMAND_AUTH: 01842 return send_error (auth, "Sent AUTH while expecting BEGIN"); 01843 01844 case DBUS_AUTH_COMMAND_DATA: 01845 return send_error (auth, "Sent DATA while expecting BEGIN"); 01846 01847 case DBUS_AUTH_COMMAND_BEGIN: 01848 goto_state (auth, &common_state_authenticated); 01849 return TRUE; 01850 01851 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01852 if (auth->unix_fd_possible) 01853 return send_agree_unix_fd(auth); 01854 else 01855 return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible"); 01856 01857 case DBUS_AUTH_COMMAND_REJECTED: 01858 case DBUS_AUTH_COMMAND_OK: 01859 case DBUS_AUTH_COMMAND_UNKNOWN: 01860 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01861 default: 01862 return send_error (auth, "Unknown command"); 01863 01864 case DBUS_AUTH_COMMAND_CANCEL: 01865 case DBUS_AUTH_COMMAND_ERROR: 01866 return send_rejected (auth); 01867 } 01868 } 01869 01870 /* return FALSE if no memory, TRUE if all OK */ 01871 static dbus_bool_t 01872 get_word (const DBusString *str, 01873 int *start, 01874 DBusString *word) 01875 { 01876 int i; 01877 01878 _dbus_string_skip_blank (str, *start, start); 01879 _dbus_string_find_blank (str, *start, &i); 01880 01881 if (i > *start) 01882 { 01883 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) 01884 return FALSE; 01885 01886 *start = i; 01887 } 01888 01889 return TRUE; 01890 } 01891 01892 static dbus_bool_t 01893 record_mechanisms (DBusAuth *auth, 01894 const DBusString *args) 01895 { 01896 int next; 01897 int len; 01898 01899 if (auth->already_got_mechanisms) 01900 return TRUE; 01901 01902 len = _dbus_string_get_length (args); 01903 01904 next = 0; 01905 while (next < len) 01906 { 01907 DBusString m; 01908 const DBusAuthMechanismHandler *mech; 01909 01910 if (!_dbus_string_init (&m)) 01911 goto nomem; 01912 01913 if (!get_word (args, &next, &m)) 01914 { 01915 _dbus_string_free (&m); 01916 goto nomem; 01917 } 01918 01919 mech = find_mech (&m, auth->allowed_mechs); 01920 01921 if (mech != NULL) 01922 { 01923 /* FIXME right now we try mechanisms in the order 01924 * the server lists them; should we do them in 01925 * some more deterministic order? 01926 * 01927 * Probably in all_mechanisms order, our order of 01928 * preference. Of course when the server is us, 01929 * it lists things in that order anyhow. 01930 */ 01931 01932 if (mech != &all_mechanisms[0]) 01933 { 01934 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", 01935 DBUS_AUTH_NAME (auth), mech->mechanism); 01936 01937 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 01938 (void*) mech)) 01939 { 01940 _dbus_string_free (&m); 01941 goto nomem; 01942 } 01943 } 01944 else 01945 { 01946 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", 01947 DBUS_AUTH_NAME (auth), mech->mechanism); 01948 } 01949 } 01950 else 01951 { 01952 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", 01953 DBUS_AUTH_NAME (auth), 01954 _dbus_string_get_const_data (&m)); 01955 } 01956 01957 _dbus_string_free (&m); 01958 } 01959 01960 auth->already_got_mechanisms = TRUE; 01961 01962 return TRUE; 01963 01964 nomem: 01965 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 01966 01967 return FALSE; 01968 } 01969 01970 static dbus_bool_t 01971 process_rejected (DBusAuth *auth, const DBusString *args) 01972 { 01973 const DBusAuthMechanismHandler *mech; 01974 DBusAuthClient *client; 01975 01976 client = DBUS_AUTH_CLIENT (auth); 01977 01978 if (!auth->already_got_mechanisms) 01979 { 01980 if (!record_mechanisms (auth, args)) 01981 return FALSE; 01982 } 01983 01984 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 01985 { 01986 mech = client->mechs_to_try->data; 01987 01988 if (!send_auth (auth, mech)) 01989 return FALSE; 01990 01991 _dbus_list_pop_first (&client->mechs_to_try); 01992 01993 _dbus_verbose ("%s: Trying mechanism %s\n", 01994 DBUS_AUTH_NAME (auth), 01995 mech->mechanism); 01996 } 01997 else 01998 { 01999 /* Give up */ 02000 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", 02001 DBUS_AUTH_NAME (auth)); 02002 goto_state (auth, &common_state_need_disconnect); 02003 } 02004 02005 return TRUE; 02006 } 02007 02008 02009 static dbus_bool_t 02010 handle_client_state_waiting_for_data (DBusAuth *auth, 02011 DBusAuthCommand command, 02012 const DBusString *args) 02013 { 02014 _dbus_assert (auth->mech != NULL); 02015 02016 switch (command) 02017 { 02018 case DBUS_AUTH_COMMAND_DATA: 02019 return process_data (auth, args, auth->mech->client_data_func); 02020 02021 case DBUS_AUTH_COMMAND_REJECTED: 02022 return process_rejected (auth, args); 02023 02024 case DBUS_AUTH_COMMAND_OK: 02025 return process_ok(auth, args); 02026 02027 case DBUS_AUTH_COMMAND_ERROR: 02028 return send_cancel (auth); 02029 02030 case DBUS_AUTH_COMMAND_AUTH: 02031 case DBUS_AUTH_COMMAND_CANCEL: 02032 case DBUS_AUTH_COMMAND_BEGIN: 02033 case DBUS_AUTH_COMMAND_UNKNOWN: 02034 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02035 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02036 default: 02037 return send_error (auth, "Unknown command"); 02038 } 02039 } 02040 02041 static dbus_bool_t 02042 handle_client_state_waiting_for_ok (DBusAuth *auth, 02043 DBusAuthCommand command, 02044 const DBusString *args) 02045 { 02046 switch (command) 02047 { 02048 case DBUS_AUTH_COMMAND_REJECTED: 02049 return process_rejected (auth, args); 02050 02051 case DBUS_AUTH_COMMAND_OK: 02052 return process_ok(auth, args); 02053 02054 case DBUS_AUTH_COMMAND_DATA: 02055 case DBUS_AUTH_COMMAND_ERROR: 02056 return send_cancel (auth); 02057 02058 case DBUS_AUTH_COMMAND_AUTH: 02059 case DBUS_AUTH_COMMAND_CANCEL: 02060 case DBUS_AUTH_COMMAND_BEGIN: 02061 case DBUS_AUTH_COMMAND_UNKNOWN: 02062 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02063 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02064 default: 02065 return send_error (auth, "Unknown command"); 02066 } 02067 } 02068 02069 static dbus_bool_t 02070 handle_client_state_waiting_for_reject (DBusAuth *auth, 02071 DBusAuthCommand command, 02072 const DBusString *args) 02073 { 02074 switch (command) 02075 { 02076 case DBUS_AUTH_COMMAND_REJECTED: 02077 return process_rejected (auth, args); 02078 02079 case DBUS_AUTH_COMMAND_AUTH: 02080 case DBUS_AUTH_COMMAND_CANCEL: 02081 case DBUS_AUTH_COMMAND_DATA: 02082 case DBUS_AUTH_COMMAND_BEGIN: 02083 case DBUS_AUTH_COMMAND_OK: 02084 case DBUS_AUTH_COMMAND_ERROR: 02085 case DBUS_AUTH_COMMAND_UNKNOWN: 02086 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02087 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02088 default: 02089 goto_state (auth, &common_state_need_disconnect); 02090 return TRUE; 02091 } 02092 } 02093 02094 static dbus_bool_t 02095 handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth, 02096 DBusAuthCommand command, 02097 const DBusString *args) 02098 { 02099 switch (command) 02100 { 02101 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02102 _dbus_assert(auth->unix_fd_possible); 02103 auth->unix_fd_negotiated = TRUE; 02104 _dbus_verbose("Successfully negotiated UNIX FD passing\n"); 02105 return send_begin (auth); 02106 02107 case DBUS_AUTH_COMMAND_ERROR: 02108 _dbus_assert(auth->unix_fd_possible); 02109 auth->unix_fd_negotiated = FALSE; 02110 _dbus_verbose("Failed to negotiate UNIX FD passing\n"); 02111 return send_begin (auth); 02112 02113 case DBUS_AUTH_COMMAND_OK: 02114 case DBUS_AUTH_COMMAND_DATA: 02115 case DBUS_AUTH_COMMAND_REJECTED: 02116 case DBUS_AUTH_COMMAND_AUTH: 02117 case DBUS_AUTH_COMMAND_CANCEL: 02118 case DBUS_AUTH_COMMAND_BEGIN: 02119 case DBUS_AUTH_COMMAND_UNKNOWN: 02120 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02121 default: 02122 return send_error (auth, "Unknown command"); 02123 } 02124 } 02125 02129 typedef struct { 02130 const char *name; 02131 DBusAuthCommand command; 02132 } DBusAuthCommandName; 02133 02134 static const DBusAuthCommandName auth_command_names[] = { 02135 { "AUTH", DBUS_AUTH_COMMAND_AUTH }, 02136 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, 02137 { "DATA", DBUS_AUTH_COMMAND_DATA }, 02138 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, 02139 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, 02140 { "OK", DBUS_AUTH_COMMAND_OK }, 02141 { "ERROR", DBUS_AUTH_COMMAND_ERROR }, 02142 { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD }, 02143 { "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD } 02144 }; 02145 02146 static DBusAuthCommand 02147 lookup_command_from_name (DBusString *command) 02148 { 02149 int i; 02150 02151 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) 02152 { 02153 if (_dbus_string_equal_c_str (command, 02154 auth_command_names[i].name)) 02155 return auth_command_names[i].command; 02156 } 02157 02158 return DBUS_AUTH_COMMAND_UNKNOWN; 02159 } 02160 02161 static void 02162 goto_state (DBusAuth *auth, 02163 const DBusAuthStateData *state) 02164 { 02165 _dbus_verbose ("%s: going from state %s to state %s\n", 02166 DBUS_AUTH_NAME (auth), 02167 auth->state->name, 02168 state->name); 02169 02170 auth->state = state; 02171 } 02172 02173 /* returns whether to call it again right away */ 02174 static dbus_bool_t 02175 process_command (DBusAuth *auth) 02176 { 02177 DBusAuthCommand command; 02178 DBusString line; 02179 DBusString args; 02180 int eol; 02181 int i, j; 02182 dbus_bool_t retval; 02183 02184 /* _dbus_verbose ("%s: trying process_command()\n"); */ 02185 02186 retval = FALSE; 02187 02188 eol = 0; 02189 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 02190 return FALSE; 02191 02192 if (!_dbus_string_init (&line)) 02193 { 02194 auth->needed_memory = TRUE; 02195 return FALSE; 02196 } 02197 02198 if (!_dbus_string_init (&args)) 02199 { 02200 _dbus_string_free (&line); 02201 auth->needed_memory = TRUE; 02202 return FALSE; 02203 } 02204 02205 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) 02206 goto out; 02207 02208 if (!_dbus_string_validate_ascii (&line, 0, 02209 _dbus_string_get_length (&line))) 02210 { 02211 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", 02212 DBUS_AUTH_NAME (auth)); 02213 if (!send_error (auth, "Command contained non-ASCII")) 02214 goto out; 02215 else 02216 goto next_command; 02217 } 02218 02219 _dbus_verbose ("%s: got command \"%s\"\n", 02220 DBUS_AUTH_NAME (auth), 02221 _dbus_string_get_const_data (&line)); 02222 02223 _dbus_string_find_blank (&line, 0, &i); 02224 _dbus_string_skip_blank (&line, i, &j); 02225 02226 if (j > i) 02227 _dbus_string_delete (&line, i, j - i); 02228 02229 if (!_dbus_string_move (&line, i, &args, 0)) 02230 goto out; 02231 02232 /* FIXME 1.0 we should probably validate that only the allowed 02233 * chars are in the command name 02234 */ 02235 02236 command = lookup_command_from_name (&line); 02237 if (!(* auth->state->handler) (auth, command, &args)) 02238 goto out; 02239 02240 next_command: 02241 02242 /* We've succeeded in processing the whole command so drop it out 02243 * of the incoming buffer and return TRUE to try another command. 02244 */ 02245 02246 _dbus_string_delete (&auth->incoming, 0, eol); 02247 02248 /* kill the \r\n */ 02249 _dbus_string_delete (&auth->incoming, 0, 2); 02250 02251 retval = TRUE; 02252 02253 out: 02254 _dbus_string_free (&args); 02255 _dbus_string_free (&line); 02256 02257 if (!retval) 02258 auth->needed_memory = TRUE; 02259 else 02260 auth->needed_memory = FALSE; 02261 02262 return retval; 02263 } 02264 02265 02280 DBusAuth* 02281 _dbus_auth_server_new (const DBusString *guid) 02282 { 02283 DBusAuth *auth; 02284 DBusAuthServer *server_auth; 02285 DBusString guid_copy; 02286 02287 if (!_dbus_string_init (&guid_copy)) 02288 return NULL; 02289 02290 if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) 02291 { 02292 _dbus_string_free (&guid_copy); 02293 return NULL; 02294 } 02295 02296 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 02297 if (auth == NULL) 02298 { 02299 _dbus_string_free (&guid_copy); 02300 return NULL; 02301 } 02302 02303 auth->side = auth_side_server; 02304 auth->state = &server_state_waiting_for_auth; 02305 02306 server_auth = DBUS_AUTH_SERVER (auth); 02307 02308 server_auth->guid = guid_copy; 02309 02310 /* perhaps this should be per-mechanism with a lower 02311 * max 02312 */ 02313 server_auth->failures = 0; 02314 server_auth->max_failures = 6; 02315 02316 return auth; 02317 } 02318 02326 DBusAuth* 02327 _dbus_auth_client_new (void) 02328 { 02329 DBusAuth *auth; 02330 DBusString guid_str; 02331 02332 if (!_dbus_string_init (&guid_str)) 02333 return NULL; 02334 02335 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 02336 if (auth == NULL) 02337 { 02338 _dbus_string_free (&guid_str); 02339 return NULL; 02340 } 02341 02342 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; 02343 02344 auth->side = auth_side_client; 02345 auth->state = &client_state_need_send_auth; 02346 02347 /* Start the auth conversation by sending AUTH for our default 02348 * mechanism */ 02349 if (!send_auth (auth, &all_mechanisms[0])) 02350 { 02351 _dbus_auth_unref (auth); 02352 return NULL; 02353 } 02354 02355 return auth; 02356 } 02357 02364 DBusAuth * 02365 _dbus_auth_ref (DBusAuth *auth) 02366 { 02367 _dbus_assert (auth != NULL); 02368 02369 auth->refcount += 1; 02370 02371 return auth; 02372 } 02373 02379 void 02380 _dbus_auth_unref (DBusAuth *auth) 02381 { 02382 _dbus_assert (auth != NULL); 02383 _dbus_assert (auth->refcount > 0); 02384 02385 auth->refcount -= 1; 02386 if (auth->refcount == 0) 02387 { 02388 shutdown_mech (auth); 02389 02390 if (DBUS_AUTH_IS_CLIENT (auth)) 02391 { 02392 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 02393 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 02394 } 02395 else 02396 { 02397 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 02398 02399 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); 02400 } 02401 02402 if (auth->keyring) 02403 _dbus_keyring_unref (auth->keyring); 02404 02405 _dbus_string_free (&auth->context); 02406 _dbus_string_free (&auth->challenge); 02407 _dbus_string_free (&auth->identity); 02408 _dbus_string_free (&auth->incoming); 02409 _dbus_string_free (&auth->outgoing); 02410 02411 dbus_free_string_array (auth->allowed_mechs); 02412 02413 _dbus_credentials_unref (auth->credentials); 02414 _dbus_credentials_unref (auth->authorized_identity); 02415 _dbus_credentials_unref (auth->desired_identity); 02416 02417 dbus_free (auth); 02418 } 02419 } 02420 02429 dbus_bool_t 02430 _dbus_auth_set_mechanisms (DBusAuth *auth, 02431 const char **mechanisms) 02432 { 02433 char **copy; 02434 02435 if (mechanisms != NULL) 02436 { 02437 copy = _dbus_dup_string_array (mechanisms); 02438 if (copy == NULL) 02439 return FALSE; 02440 } 02441 else 02442 copy = NULL; 02443 02444 dbus_free_string_array (auth->allowed_mechs); 02445 02446 auth->allowed_mechs = copy; 02447 02448 return TRUE; 02449 } 02450 02455 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) 02456 02464 DBusAuthState 02465 _dbus_auth_do_work (DBusAuth *auth) 02466 { 02467 auth->needed_memory = FALSE; 02468 02469 /* Max amount we'll buffer up before deciding someone's on crack */ 02470 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 02471 02472 do 02473 { 02474 if (DBUS_AUTH_IN_END_STATE (auth)) 02475 break; 02476 02477 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 02478 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 02479 { 02480 goto_state (auth, &common_state_need_disconnect); 02481 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", 02482 DBUS_AUTH_NAME (auth)); 02483 break; 02484 } 02485 } 02486 while (process_command (auth)); 02487 02488 if (auth->needed_memory) 02489 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 02490 else if (_dbus_string_get_length (&auth->outgoing) > 0) 02491 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 02492 else if (auth->state == &common_state_need_disconnect) 02493 return DBUS_AUTH_STATE_NEED_DISCONNECT; 02494 else if (auth->state == &common_state_authenticated) 02495 return DBUS_AUTH_STATE_AUTHENTICATED; 02496 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 02497 } 02498 02508 dbus_bool_t 02509 _dbus_auth_get_bytes_to_send (DBusAuth *auth, 02510 const DBusString **str) 02511 { 02512 _dbus_assert (auth != NULL); 02513 _dbus_assert (str != NULL); 02514 02515 *str = NULL; 02516 02517 if (_dbus_string_get_length (&auth->outgoing) == 0) 02518 return FALSE; 02519 02520 *str = &auth->outgoing; 02521 02522 return TRUE; 02523 } 02524 02533 void 02534 _dbus_auth_bytes_sent (DBusAuth *auth, 02535 int bytes_sent) 02536 { 02537 _dbus_verbose ("%s: Sent %d bytes of: %s\n", 02538 DBUS_AUTH_NAME (auth), 02539 bytes_sent, 02540 _dbus_string_get_const_data (&auth->outgoing)); 02541 02542 _dbus_string_delete (&auth->outgoing, 02543 0, bytes_sent); 02544 } 02545 02553 void 02554 _dbus_auth_get_buffer (DBusAuth *auth, 02555 DBusString **buffer) 02556 { 02557 _dbus_assert (auth != NULL); 02558 _dbus_assert (!auth->buffer_outstanding); 02559 02560 *buffer = &auth->incoming; 02561 02562 auth->buffer_outstanding = TRUE; 02563 } 02564 02571 void 02572 _dbus_auth_return_buffer (DBusAuth *auth, 02573 DBusString *buffer) 02574 { 02575 _dbus_assert (buffer == &auth->incoming); 02576 _dbus_assert (auth->buffer_outstanding); 02577 02578 auth->buffer_outstanding = FALSE; 02579 } 02580 02590 void 02591 _dbus_auth_get_unused_bytes (DBusAuth *auth, 02592 const DBusString **str) 02593 { 02594 if (!DBUS_AUTH_IN_END_STATE (auth)) 02595 return; 02596 02597 *str = &auth->incoming; 02598 } 02599 02600 02607 void 02608 _dbus_auth_delete_unused_bytes (DBusAuth *auth) 02609 { 02610 if (!DBUS_AUTH_IN_END_STATE (auth)) 02611 return; 02612 02613 _dbus_string_set_length (&auth->incoming, 0); 02614 } 02615 02624 dbus_bool_t 02625 _dbus_auth_needs_encoding (DBusAuth *auth) 02626 { 02627 if (auth->state != &common_state_authenticated) 02628 return FALSE; 02629 02630 if (auth->mech != NULL) 02631 { 02632 if (DBUS_AUTH_IS_CLIENT (auth)) 02633 return auth->mech->client_encode_func != NULL; 02634 else 02635 return auth->mech->server_encode_func != NULL; 02636 } 02637 else 02638 return FALSE; 02639 } 02640 02651 dbus_bool_t 02652 _dbus_auth_encode_data (DBusAuth *auth, 02653 const DBusString *plaintext, 02654 DBusString *encoded) 02655 { 02656 _dbus_assert (plaintext != encoded); 02657 02658 if (auth->state != &common_state_authenticated) 02659 return FALSE; 02660 02661 if (_dbus_auth_needs_encoding (auth)) 02662 { 02663 if (DBUS_AUTH_IS_CLIENT (auth)) 02664 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 02665 else 02666 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 02667 } 02668 else 02669 { 02670 return _dbus_string_copy (plaintext, 0, encoded, 02671 _dbus_string_get_length (encoded)); 02672 } 02673 } 02674 02683 dbus_bool_t 02684 _dbus_auth_needs_decoding (DBusAuth *auth) 02685 { 02686 if (auth->state != &common_state_authenticated) 02687 return FALSE; 02688 02689 if (auth->mech != NULL) 02690 { 02691 if (DBUS_AUTH_IS_CLIENT (auth)) 02692 return auth->mech->client_decode_func != NULL; 02693 else 02694 return auth->mech->server_decode_func != NULL; 02695 } 02696 else 02697 return FALSE; 02698 } 02699 02700 02714 dbus_bool_t 02715 _dbus_auth_decode_data (DBusAuth *auth, 02716 const DBusString *encoded, 02717 DBusString *plaintext) 02718 { 02719 _dbus_assert (plaintext != encoded); 02720 02721 if (auth->state != &common_state_authenticated) 02722 return FALSE; 02723 02724 if (_dbus_auth_needs_decoding (auth)) 02725 { 02726 if (DBUS_AUTH_IS_CLIENT (auth)) 02727 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 02728 else 02729 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 02730 } 02731 else 02732 { 02733 return _dbus_string_copy (encoded, 0, plaintext, 02734 _dbus_string_get_length (plaintext)); 02735 } 02736 } 02737 02746 dbus_bool_t 02747 _dbus_auth_set_credentials (DBusAuth *auth, 02748 DBusCredentials *credentials) 02749 { 02750 _dbus_credentials_clear (auth->credentials); 02751 return _dbus_credentials_add_credentials (auth->credentials, 02752 credentials); 02753 } 02754 02764 DBusCredentials* 02765 _dbus_auth_get_identity (DBusAuth *auth) 02766 { 02767 if (auth->state == &common_state_authenticated) 02768 { 02769 return auth->authorized_identity; 02770 } 02771 else 02772 { 02773 /* FIXME instead of this, keep an empty credential around that 02774 * doesn't require allocation or something 02775 */ 02776 /* return empty credentials */ 02777 _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); 02778 return auth->authorized_identity; 02779 } 02780 } 02781 02788 const char* 02789 _dbus_auth_get_guid_from_server (DBusAuth *auth) 02790 { 02791 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); 02792 02793 if (auth->state == &common_state_authenticated) 02794 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 02795 else 02796 return NULL; 02797 } 02798 02807 dbus_bool_t 02808 _dbus_auth_set_context (DBusAuth *auth, 02809 const DBusString *context) 02810 { 02811 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), 02812 &auth->context, 0, _dbus_string_get_length (context)); 02813 } 02814 02822 void 02823 _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b) 02824 { 02825 auth->unix_fd_possible = b; 02826 } 02827 02834 dbus_bool_t 02835 _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth) 02836 { 02837 return auth->unix_fd_negotiated; 02838 } 02839 02842 /* tests in dbus-auth-util.c */