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