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