D-Bus 1.4.6
|
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 01206 { 01207 DBusString plaintext; 01208 DBusString encoded; 01209 _dbus_string_init_const (&plaintext, "D-Bus " DBUS_VERSION_STRING); 01210 _dbus_string_init (&encoded); 01211 _dbus_string_hex_encode (&plaintext, 0, 01212 &encoded, 01213 0); 01214 _dbus_verbose ("%s: try '%s'\n", 01215 DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded)); 01216 } 01217 return send_rejected (auth); 01218 } 01219 01220 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", 01221 DBUS_AUTH_NAME (auth), 01222 _dbus_string_get_const_data (data)); 01223 } 01224 01225 /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ 01226 _dbus_credentials_clear (auth->desired_identity); 01227 01228 /* Copy process ID from the socket credentials 01229 */ 01230 if (!_dbus_credentials_add_credential (auth->authorized_identity, 01231 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 01232 auth->credentials)) 01233 return FALSE; 01234 01235 /* Anonymous is always allowed */ 01236 if (!send_ok (auth)) 01237 return FALSE; 01238 01239 _dbus_verbose ("%s: authenticated client as anonymous\n", 01240 DBUS_AUTH_NAME (auth)); 01241 01242 return TRUE; 01243 } 01244 01245 static void 01246 handle_server_shutdown_anonymous_mech (DBusAuth *auth) 01247 { 01248 01249 } 01250 01251 static dbus_bool_t 01252 handle_client_initial_response_anonymous_mech (DBusAuth *auth, 01253 DBusString *response) 01254 { 01255 /* Our initial response is a "trace" string which must be valid UTF-8 01256 * and must be an email address if it contains '@'. 01257 * We just send the dbus implementation info, like a user-agent or 01258 * something, because... why not. There's nothing guaranteed here 01259 * though, we could change it later. 01260 */ 01261 DBusString plaintext; 01262 01263 if (!_dbus_string_init (&plaintext)) 01264 return FALSE; 01265 01266 if (!_dbus_string_append (&plaintext, 01267 "libdbus " DBUS_VERSION_STRING)) 01268 goto failed; 01269 01270 if (!_dbus_string_hex_encode (&plaintext, 0, 01271 response, 01272 _dbus_string_get_length (response))) 01273 goto failed; 01274 01275 _dbus_string_free (&plaintext); 01276 01277 return TRUE; 01278 01279 failed: 01280 _dbus_string_free (&plaintext); 01281 return FALSE; 01282 } 01283 01284 static dbus_bool_t 01285 handle_client_data_anonymous_mech (DBusAuth *auth, 01286 const DBusString *data) 01287 { 01288 01289 return TRUE; 01290 } 01291 01292 static void 01293 handle_client_shutdown_anonymous_mech (DBusAuth *auth) 01294 { 01295 01296 } 01297 01298 /* Put mechanisms here in order of preference. 01299 * Right now we have: 01300 * 01301 * - EXTERNAL checks socket credentials (or in the future, other info from the OS) 01302 * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE 01303 * - ANONYMOUS checks nothing but doesn't auth the person as a user 01304 * 01305 * We might ideally add a mechanism to chain to Cyrus SASL so we can 01306 * use its mechanisms as well. 01307 * 01308 */ 01309 static const DBusAuthMechanismHandler 01310 all_mechanisms[] = { 01311 { "EXTERNAL", 01312 handle_server_data_external_mech, 01313 NULL, NULL, 01314 handle_server_shutdown_external_mech, 01315 handle_client_initial_response_external_mech, 01316 handle_client_data_external_mech, 01317 NULL, NULL, 01318 handle_client_shutdown_external_mech }, 01319 { "DBUS_COOKIE_SHA1", 01320 handle_server_data_cookie_sha1_mech, 01321 NULL, NULL, 01322 handle_server_shutdown_cookie_sha1_mech, 01323 handle_client_initial_response_cookie_sha1_mech, 01324 handle_client_data_cookie_sha1_mech, 01325 NULL, NULL, 01326 handle_client_shutdown_cookie_sha1_mech }, 01327 { "ANONYMOUS", 01328 handle_server_data_anonymous_mech, 01329 NULL, NULL, 01330 handle_server_shutdown_anonymous_mech, 01331 handle_client_initial_response_anonymous_mech, 01332 handle_client_data_anonymous_mech, 01333 NULL, NULL, 01334 handle_client_shutdown_anonymous_mech }, 01335 { NULL, NULL } 01336 }; 01337 01338 static const DBusAuthMechanismHandler* 01339 find_mech (const DBusString *name, 01340 char **allowed_mechs) 01341 { 01342 int i; 01343 01344 if (allowed_mechs != NULL && 01345 !_dbus_string_array_contains ((const char**) allowed_mechs, 01346 _dbus_string_get_const_data (name))) 01347 return NULL; 01348 01349 i = 0; 01350 while (all_mechanisms[i].mechanism != NULL) 01351 { 01352 if (_dbus_string_equal_c_str (name, 01353 all_mechanisms[i].mechanism)) 01354 01355 return &all_mechanisms[i]; 01356 01357 ++i; 01358 } 01359 01360 return NULL; 01361 } 01362 01363 static dbus_bool_t 01364 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) 01365 { 01366 DBusString auth_command; 01367 01368 if (!_dbus_string_init (&auth_command)) 01369 return FALSE; 01370 01371 if (!_dbus_string_append (&auth_command, 01372 "AUTH ")) 01373 { 01374 _dbus_string_free (&auth_command); 01375 return FALSE; 01376 } 01377 01378 if (!_dbus_string_append (&auth_command, 01379 mech->mechanism)) 01380 { 01381 _dbus_string_free (&auth_command); 01382 return FALSE; 01383 } 01384 01385 if (mech->client_initial_response_func != NULL) 01386 { 01387 if (!_dbus_string_append (&auth_command, " ")) 01388 { 01389 _dbus_string_free (&auth_command); 01390 return FALSE; 01391 } 01392 01393 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 01394 { 01395 _dbus_string_free (&auth_command); 01396 return FALSE; 01397 } 01398 } 01399 01400 if (!_dbus_string_append (&auth_command, 01401 "\r\n")) 01402 { 01403 _dbus_string_free (&auth_command); 01404 return FALSE; 01405 } 01406 01407 if (!_dbus_string_copy (&auth_command, 0, 01408 &auth->outgoing, 01409 _dbus_string_get_length (&auth->outgoing))) 01410 { 01411 _dbus_string_free (&auth_command); 01412 return FALSE; 01413 } 01414 01415 _dbus_string_free (&auth_command); 01416 shutdown_mech (auth); 01417 auth->mech = mech; 01418 goto_state (auth, &client_state_waiting_for_data); 01419 01420 return TRUE; 01421 } 01422 01423 static dbus_bool_t 01424 send_data (DBusAuth *auth, DBusString *data) 01425 { 01426 int old_len; 01427 01428 if (data == NULL || _dbus_string_get_length (data) == 0) 01429 return _dbus_string_append (&auth->outgoing, "DATA\r\n"); 01430 else 01431 { 01432 old_len = _dbus_string_get_length (&auth->outgoing); 01433 if (!_dbus_string_append (&auth->outgoing, "DATA ")) 01434 goto out; 01435 01436 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, 01437 _dbus_string_get_length (&auth->outgoing))) 01438 goto out; 01439 01440 if (!_dbus_string_append (&auth->outgoing, "\r\n")) 01441 goto out; 01442 01443 return TRUE; 01444 01445 out: 01446 _dbus_string_set_length (&auth->outgoing, old_len); 01447 01448 return FALSE; 01449 } 01450 } 01451 01452 static dbus_bool_t 01453 send_rejected (DBusAuth *auth) 01454 { 01455 DBusString command; 01456 DBusAuthServer *server_auth; 01457 int i; 01458 01459 if (!_dbus_string_init (&command)) 01460 return FALSE; 01461 01462 if (!_dbus_string_append (&command, 01463 "REJECTED")) 01464 goto nomem; 01465 01466 i = 0; 01467 while (all_mechanisms[i].mechanism != NULL) 01468 { 01469 if (!_dbus_string_append (&command, 01470 " ")) 01471 goto nomem; 01472 01473 if (!_dbus_string_append (&command, 01474 all_mechanisms[i].mechanism)) 01475 goto nomem; 01476 01477 ++i; 01478 } 01479 01480 if (!_dbus_string_append (&command, "\r\n")) 01481 goto nomem; 01482 01483 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 01484 _dbus_string_get_length (&auth->outgoing))) 01485 goto nomem; 01486 01487 shutdown_mech (auth); 01488 01489 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 01490 server_auth = DBUS_AUTH_SERVER (auth); 01491 server_auth->failures += 1; 01492 01493 if (server_auth->failures >= server_auth->max_failures) 01494 goto_state (auth, &common_state_need_disconnect); 01495 else 01496 goto_state (auth, &server_state_waiting_for_auth); 01497 01498 _dbus_string_free (&command); 01499 01500 return TRUE; 01501 01502 nomem: 01503 _dbus_string_free (&command); 01504 return FALSE; 01505 } 01506 01507 static dbus_bool_t 01508 send_error (DBusAuth *auth, const char *message) 01509 { 01510 return _dbus_string_append_printf (&auth->outgoing, 01511 "ERROR \"%s\"\r\n", message); 01512 } 01513 01514 static dbus_bool_t 01515 send_ok (DBusAuth *auth) 01516 { 01517 int orig_len; 01518 01519 orig_len = _dbus_string_get_length (&auth->outgoing); 01520 01521 if (_dbus_string_append (&auth->outgoing, "OK ") && 01522 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, 01523 0, 01524 &auth->outgoing, 01525 _dbus_string_get_length (&auth->outgoing)) && 01526 _dbus_string_append (&auth->outgoing, "\r\n")) 01527 { 01528 goto_state (auth, &server_state_waiting_for_begin); 01529 return TRUE; 01530 } 01531 else 01532 { 01533 _dbus_string_set_length (&auth->outgoing, orig_len); 01534 return FALSE; 01535 } 01536 } 01537 01538 static dbus_bool_t 01539 send_begin (DBusAuth *auth) 01540 { 01541 01542 if (!_dbus_string_append (&auth->outgoing, 01543 "BEGIN\r\n")) 01544 return FALSE; 01545 01546 goto_state (auth, &common_state_authenticated); 01547 return TRUE; 01548 } 01549 01550 static dbus_bool_t 01551 process_ok(DBusAuth *auth, 01552 const DBusString *args_from_ok) { 01553 01554 int end_of_hex; 01555 01556 /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ 01557 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); 01558 01559 /* We decode the hex string to binary, using guid_from_server as scratch... */ 01560 01561 end_of_hex = 0; 01562 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, 01563 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) 01564 return FALSE; 01565 01566 /* now clear out the scratch */ 01567 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 01568 01569 if (end_of_hex != _dbus_string_get_length (args_from_ok) || 01570 end_of_hex == 0) 01571 { 01572 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", 01573 end_of_hex, _dbus_string_get_length (args_from_ok)); 01574 goto_state (auth, &common_state_need_disconnect); 01575 return TRUE; 01576 } 01577 01578 if (!_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) { 01579 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 01580 return FALSE; 01581 } 01582 01583 _dbus_verbose ("Got GUID '%s' from the server\n", 01584 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); 01585 01586 if (auth->unix_fd_possible) 01587 return send_negotiate_unix_fd(auth); 01588 01589 _dbus_verbose("Not negotiating unix fd passing, since not possible\n"); 01590 return send_begin (auth); 01591 } 01592 01593 static dbus_bool_t 01594 send_cancel (DBusAuth *auth) 01595 { 01596 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) 01597 { 01598 goto_state (auth, &client_state_waiting_for_reject); 01599 return TRUE; 01600 } 01601 else 01602 return FALSE; 01603 } 01604 01605 static dbus_bool_t 01606 process_data (DBusAuth *auth, 01607 const DBusString *args, 01608 DBusAuthDataFunction data_func) 01609 { 01610 int end; 01611 DBusString decoded; 01612 01613 if (!_dbus_string_init (&decoded)) 01614 return FALSE; 01615 01616 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) 01617 { 01618 _dbus_string_free (&decoded); 01619 return FALSE; 01620 } 01621 01622 if (_dbus_string_get_length (args) != end) 01623 { 01624 _dbus_string_free (&decoded); 01625 if (!send_error (auth, "Invalid hex encoding")) 01626 return FALSE; 01627 01628 return TRUE; 01629 } 01630 01631 #ifdef DBUS_ENABLE_VERBOSE_MODE 01632 if (_dbus_string_validate_ascii (&decoded, 0, 01633 _dbus_string_get_length (&decoded))) 01634 _dbus_verbose ("%s: data: '%s'\n", 01635 DBUS_AUTH_NAME (auth), 01636 _dbus_string_get_const_data (&decoded)); 01637 #endif 01638 01639 if (!(* data_func) (auth, &decoded)) 01640 { 01641 _dbus_string_free (&decoded); 01642 return FALSE; 01643 } 01644 01645 _dbus_string_free (&decoded); 01646 return TRUE; 01647 } 01648 01649 static dbus_bool_t 01650 send_negotiate_unix_fd (DBusAuth *auth) 01651 { 01652 if (!_dbus_string_append (&auth->outgoing, 01653 "NEGOTIATE_UNIX_FD\r\n")) 01654 return FALSE; 01655 01656 goto_state (auth, &client_state_waiting_for_agree_unix_fd); 01657 return TRUE; 01658 } 01659 01660 static dbus_bool_t 01661 send_agree_unix_fd (DBusAuth *auth) 01662 { 01663 _dbus_assert(auth->unix_fd_possible); 01664 01665 auth->unix_fd_negotiated = TRUE; 01666 _dbus_verbose("Agreed to UNIX FD passing\n"); 01667 01668 if (!_dbus_string_append (&auth->outgoing, 01669 "AGREE_UNIX_FD\r\n")) 01670 return FALSE; 01671 01672 goto_state (auth, &server_state_waiting_for_begin); 01673 return TRUE; 01674 } 01675 01676 static dbus_bool_t 01677 handle_auth (DBusAuth *auth, const DBusString *args) 01678 { 01679 if (_dbus_string_get_length (args) == 0) 01680 { 01681 /* No args to the auth, send mechanisms */ 01682 if (!send_rejected (auth)) 01683 return FALSE; 01684 01685 return TRUE; 01686 } 01687 else 01688 { 01689 int i; 01690 DBusString mech; 01691 DBusString hex_response; 01692 01693 _dbus_string_find_blank (args, 0, &i); 01694 01695 if (!_dbus_string_init (&mech)) 01696 return FALSE; 01697 01698 if (!_dbus_string_init (&hex_response)) 01699 { 01700 _dbus_string_free (&mech); 01701 return FALSE; 01702 } 01703 01704 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 01705 goto failed; 01706 01707 _dbus_string_skip_blank (args, i, &i); 01708 if (!_dbus_string_copy (args, i, &hex_response, 0)) 01709 goto failed; 01710 01711 auth->mech = find_mech (&mech, auth->allowed_mechs); 01712 if (auth->mech != NULL) 01713 { 01714 _dbus_verbose ("%s: Trying mechanism %s\n", 01715 DBUS_AUTH_NAME (auth), 01716 auth->mech->mechanism); 01717 01718 if (!process_data (auth, &hex_response, 01719 auth->mech->server_data_func)) 01720 goto failed; 01721 } 01722 else 01723 { 01724 /* Unsupported mechanism */ 01725 _dbus_verbose ("%s: Unsupported mechanism %s\n", 01726 DBUS_AUTH_NAME (auth), 01727 _dbus_string_get_const_data (&mech)); 01728 01729 if (!send_rejected (auth)) 01730 goto failed; 01731 } 01732 01733 _dbus_string_free (&mech); 01734 _dbus_string_free (&hex_response); 01735 01736 return TRUE; 01737 01738 failed: 01739 auth->mech = NULL; 01740 _dbus_string_free (&mech); 01741 _dbus_string_free (&hex_response); 01742 return FALSE; 01743 } 01744 } 01745 01746 static dbus_bool_t 01747 handle_server_state_waiting_for_auth (DBusAuth *auth, 01748 DBusAuthCommand command, 01749 const DBusString *args) 01750 { 01751 switch (command) 01752 { 01753 case DBUS_AUTH_COMMAND_AUTH: 01754 return handle_auth (auth, args); 01755 01756 case DBUS_AUTH_COMMAND_CANCEL: 01757 case DBUS_AUTH_COMMAND_DATA: 01758 return send_error (auth, "Not currently in an auth conversation"); 01759 01760 case DBUS_AUTH_COMMAND_BEGIN: 01761 goto_state (auth, &common_state_need_disconnect); 01762 return TRUE; 01763 01764 case DBUS_AUTH_COMMAND_ERROR: 01765 return send_rejected (auth); 01766 01767 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01768 return send_error (auth, "Need to authenticate first"); 01769 01770 case DBUS_AUTH_COMMAND_REJECTED: 01771 case DBUS_AUTH_COMMAND_OK: 01772 case DBUS_AUTH_COMMAND_UNKNOWN: 01773 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01774 default: 01775 return send_error (auth, "Unknown command"); 01776 } 01777 } 01778 01779 static dbus_bool_t 01780 handle_server_state_waiting_for_data (DBusAuth *auth, 01781 DBusAuthCommand command, 01782 const DBusString *args) 01783 { 01784 switch (command) 01785 { 01786 case DBUS_AUTH_COMMAND_AUTH: 01787 return send_error (auth, "Sent AUTH while another AUTH in progress"); 01788 01789 case DBUS_AUTH_COMMAND_CANCEL: 01790 case DBUS_AUTH_COMMAND_ERROR: 01791 return send_rejected (auth); 01792 01793 case DBUS_AUTH_COMMAND_DATA: 01794 return process_data (auth, args, auth->mech->server_data_func); 01795 01796 case DBUS_AUTH_COMMAND_BEGIN: 01797 goto_state (auth, &common_state_need_disconnect); 01798 return TRUE; 01799 01800 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01801 return send_error (auth, "Need to authenticate first"); 01802 01803 case DBUS_AUTH_COMMAND_REJECTED: 01804 case DBUS_AUTH_COMMAND_OK: 01805 case DBUS_AUTH_COMMAND_UNKNOWN: 01806 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01807 default: 01808 return send_error (auth, "Unknown command"); 01809 } 01810 } 01811 01812 static dbus_bool_t 01813 handle_server_state_waiting_for_begin (DBusAuth *auth, 01814 DBusAuthCommand command, 01815 const DBusString *args) 01816 { 01817 switch (command) 01818 { 01819 case DBUS_AUTH_COMMAND_AUTH: 01820 return send_error (auth, "Sent AUTH while expecting BEGIN"); 01821 01822 case DBUS_AUTH_COMMAND_DATA: 01823 return send_error (auth, "Sent DATA while expecting BEGIN"); 01824 01825 case DBUS_AUTH_COMMAND_BEGIN: 01826 goto_state (auth, &common_state_authenticated); 01827 return TRUE; 01828 01829 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 01830 if (auth->unix_fd_possible) 01831 return send_agree_unix_fd(auth); 01832 else 01833 return send_error(auth, "Unix FD passing not supported, not authenticated or otherwise not possible"); 01834 01835 case DBUS_AUTH_COMMAND_REJECTED: 01836 case DBUS_AUTH_COMMAND_OK: 01837 case DBUS_AUTH_COMMAND_UNKNOWN: 01838 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 01839 default: 01840 return send_error (auth, "Unknown command"); 01841 01842 case DBUS_AUTH_COMMAND_CANCEL: 01843 case DBUS_AUTH_COMMAND_ERROR: 01844 return send_rejected (auth); 01845 } 01846 } 01847 01848 /* return FALSE if no memory, TRUE if all OK */ 01849 static dbus_bool_t 01850 get_word (const DBusString *str, 01851 int *start, 01852 DBusString *word) 01853 { 01854 int i; 01855 01856 _dbus_string_skip_blank (str, *start, start); 01857 _dbus_string_find_blank (str, *start, &i); 01858 01859 if (i > *start) 01860 { 01861 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) 01862 return FALSE; 01863 01864 *start = i; 01865 } 01866 01867 return TRUE; 01868 } 01869 01870 static dbus_bool_t 01871 record_mechanisms (DBusAuth *auth, 01872 const DBusString *args) 01873 { 01874 int next; 01875 int len; 01876 01877 if (auth->already_got_mechanisms) 01878 return TRUE; 01879 01880 len = _dbus_string_get_length (args); 01881 01882 next = 0; 01883 while (next < len) 01884 { 01885 DBusString m; 01886 const DBusAuthMechanismHandler *mech; 01887 01888 if (!_dbus_string_init (&m)) 01889 goto nomem; 01890 01891 if (!get_word (args, &next, &m)) 01892 { 01893 _dbus_string_free (&m); 01894 goto nomem; 01895 } 01896 01897 mech = find_mech (&m, auth->allowed_mechs); 01898 01899 if (mech != NULL) 01900 { 01901 /* FIXME right now we try mechanisms in the order 01902 * the server lists them; should we do them in 01903 * some more deterministic order? 01904 * 01905 * Probably in all_mechanisms order, our order of 01906 * preference. Of course when the server is us, 01907 * it lists things in that order anyhow. 01908 */ 01909 01910 if (mech != &all_mechanisms[0]) 01911 { 01912 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", 01913 DBUS_AUTH_NAME (auth), mech->mechanism); 01914 01915 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 01916 (void*) mech)) 01917 { 01918 _dbus_string_free (&m); 01919 goto nomem; 01920 } 01921 } 01922 else 01923 { 01924 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", 01925 DBUS_AUTH_NAME (auth), mech->mechanism); 01926 } 01927 } 01928 else 01929 { 01930 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", 01931 DBUS_AUTH_NAME (auth), 01932 _dbus_string_get_const_data (&m)); 01933 } 01934 01935 _dbus_string_free (&m); 01936 } 01937 01938 auth->already_got_mechanisms = TRUE; 01939 01940 return TRUE; 01941 01942 nomem: 01943 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 01944 01945 return FALSE; 01946 } 01947 01948 static dbus_bool_t 01949 process_rejected (DBusAuth *auth, const DBusString *args) 01950 { 01951 const DBusAuthMechanismHandler *mech; 01952 DBusAuthClient *client; 01953 01954 client = DBUS_AUTH_CLIENT (auth); 01955 01956 if (!auth->already_got_mechanisms) 01957 { 01958 if (!record_mechanisms (auth, args)) 01959 return FALSE; 01960 } 01961 01962 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 01963 { 01964 mech = client->mechs_to_try->data; 01965 01966 if (!send_auth (auth, mech)) 01967 return FALSE; 01968 01969 _dbus_list_pop_first (&client->mechs_to_try); 01970 01971 _dbus_verbose ("%s: Trying mechanism %s\n", 01972 DBUS_AUTH_NAME (auth), 01973 mech->mechanism); 01974 } 01975 else 01976 { 01977 /* Give up */ 01978 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", 01979 DBUS_AUTH_NAME (auth)); 01980 goto_state (auth, &common_state_need_disconnect); 01981 } 01982 01983 return TRUE; 01984 } 01985 01986 01987 static dbus_bool_t 01988 handle_client_state_waiting_for_data (DBusAuth *auth, 01989 DBusAuthCommand command, 01990 const DBusString *args) 01991 { 01992 _dbus_assert (auth->mech != NULL); 01993 01994 switch (command) 01995 { 01996 case DBUS_AUTH_COMMAND_DATA: 01997 return process_data (auth, args, auth->mech->client_data_func); 01998 01999 case DBUS_AUTH_COMMAND_REJECTED: 02000 return process_rejected (auth, args); 02001 02002 case DBUS_AUTH_COMMAND_OK: 02003 return process_ok(auth, args); 02004 02005 case DBUS_AUTH_COMMAND_ERROR: 02006 return send_cancel (auth); 02007 02008 case DBUS_AUTH_COMMAND_AUTH: 02009 case DBUS_AUTH_COMMAND_CANCEL: 02010 case DBUS_AUTH_COMMAND_BEGIN: 02011 case DBUS_AUTH_COMMAND_UNKNOWN: 02012 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02013 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02014 default: 02015 return send_error (auth, "Unknown command"); 02016 } 02017 } 02018 02019 static dbus_bool_t 02020 handle_client_state_waiting_for_ok (DBusAuth *auth, 02021 DBusAuthCommand command, 02022 const DBusString *args) 02023 { 02024 switch (command) 02025 { 02026 case DBUS_AUTH_COMMAND_REJECTED: 02027 return process_rejected (auth, args); 02028 02029 case DBUS_AUTH_COMMAND_OK: 02030 return process_ok(auth, args); 02031 02032 case DBUS_AUTH_COMMAND_DATA: 02033 case DBUS_AUTH_COMMAND_ERROR: 02034 return send_cancel (auth); 02035 02036 case DBUS_AUTH_COMMAND_AUTH: 02037 case DBUS_AUTH_COMMAND_CANCEL: 02038 case DBUS_AUTH_COMMAND_BEGIN: 02039 case DBUS_AUTH_COMMAND_UNKNOWN: 02040 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02041 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02042 default: 02043 return send_error (auth, "Unknown command"); 02044 } 02045 } 02046 02047 static dbus_bool_t 02048 handle_client_state_waiting_for_reject (DBusAuth *auth, 02049 DBusAuthCommand command, 02050 const DBusString *args) 02051 { 02052 switch (command) 02053 { 02054 case DBUS_AUTH_COMMAND_REJECTED: 02055 return process_rejected (auth, args); 02056 02057 case DBUS_AUTH_COMMAND_AUTH: 02058 case DBUS_AUTH_COMMAND_CANCEL: 02059 case DBUS_AUTH_COMMAND_DATA: 02060 case DBUS_AUTH_COMMAND_BEGIN: 02061 case DBUS_AUTH_COMMAND_OK: 02062 case DBUS_AUTH_COMMAND_ERROR: 02063 case DBUS_AUTH_COMMAND_UNKNOWN: 02064 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02065 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02066 default: 02067 goto_state (auth, &common_state_need_disconnect); 02068 return TRUE; 02069 } 02070 } 02071 02072 static dbus_bool_t 02073 handle_client_state_waiting_for_agree_unix_fd(DBusAuth *auth, 02074 DBusAuthCommand command, 02075 const DBusString *args) 02076 { 02077 switch (command) 02078 { 02079 case DBUS_AUTH_COMMAND_AGREE_UNIX_FD: 02080 _dbus_assert(auth->unix_fd_possible); 02081 auth->unix_fd_negotiated = TRUE; 02082 _dbus_verbose("Sucessfully negotiated UNIX FD passing\n"); 02083 return send_begin (auth); 02084 02085 case DBUS_AUTH_COMMAND_ERROR: 02086 _dbus_assert(auth->unix_fd_possible); 02087 auth->unix_fd_negotiated = FALSE; 02088 _dbus_verbose("Failed to negotiate UNIX FD passing\n"); 02089 return send_begin (auth); 02090 02091 case DBUS_AUTH_COMMAND_OK: 02092 case DBUS_AUTH_COMMAND_DATA: 02093 case DBUS_AUTH_COMMAND_REJECTED: 02094 case DBUS_AUTH_COMMAND_AUTH: 02095 case DBUS_AUTH_COMMAND_CANCEL: 02096 case DBUS_AUTH_COMMAND_BEGIN: 02097 case DBUS_AUTH_COMMAND_UNKNOWN: 02098 case DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD: 02099 default: 02100 return send_error (auth, "Unknown command"); 02101 } 02102 } 02103 02107 typedef struct { 02108 const char *name; 02109 DBusAuthCommand command; 02110 } DBusAuthCommandName; 02111 02112 static const DBusAuthCommandName auth_command_names[] = { 02113 { "AUTH", DBUS_AUTH_COMMAND_AUTH }, 02114 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, 02115 { "DATA", DBUS_AUTH_COMMAND_DATA }, 02116 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, 02117 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, 02118 { "OK", DBUS_AUTH_COMMAND_OK }, 02119 { "ERROR", DBUS_AUTH_COMMAND_ERROR }, 02120 { "NEGOTIATE_UNIX_FD", DBUS_AUTH_COMMAND_NEGOTIATE_UNIX_FD }, 02121 { "AGREE_UNIX_FD", DBUS_AUTH_COMMAND_AGREE_UNIX_FD } 02122 }; 02123 02124 static DBusAuthCommand 02125 lookup_command_from_name (DBusString *command) 02126 { 02127 int i; 02128 02129 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) 02130 { 02131 if (_dbus_string_equal_c_str (command, 02132 auth_command_names[i].name)) 02133 return auth_command_names[i].command; 02134 } 02135 02136 return DBUS_AUTH_COMMAND_UNKNOWN; 02137 } 02138 02139 static void 02140 goto_state (DBusAuth *auth, 02141 const DBusAuthStateData *state) 02142 { 02143 _dbus_verbose ("%s: going from state %s to state %s\n", 02144 DBUS_AUTH_NAME (auth), 02145 auth->state->name, 02146 state->name); 02147 02148 auth->state = state; 02149 } 02150 02151 /* returns whether to call it again right away */ 02152 static dbus_bool_t 02153 process_command (DBusAuth *auth) 02154 { 02155 DBusAuthCommand command; 02156 DBusString line; 02157 DBusString args; 02158 int eol; 02159 int i, j; 02160 dbus_bool_t retval; 02161 02162 /* _dbus_verbose ("%s: trying process_command()\n"); */ 02163 02164 retval = FALSE; 02165 02166 eol = 0; 02167 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 02168 return FALSE; 02169 02170 if (!_dbus_string_init (&line)) 02171 { 02172 auth->needed_memory = TRUE; 02173 return FALSE; 02174 } 02175 02176 if (!_dbus_string_init (&args)) 02177 { 02178 _dbus_string_free (&line); 02179 auth->needed_memory = TRUE; 02180 return FALSE; 02181 } 02182 02183 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) 02184 goto out; 02185 02186 if (!_dbus_string_validate_ascii (&line, 0, 02187 _dbus_string_get_length (&line))) 02188 { 02189 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", 02190 DBUS_AUTH_NAME (auth)); 02191 if (!send_error (auth, "Command contained non-ASCII")) 02192 goto out; 02193 else 02194 goto next_command; 02195 } 02196 02197 _dbus_verbose ("%s: got command \"%s\"\n", 02198 DBUS_AUTH_NAME (auth), 02199 _dbus_string_get_const_data (&line)); 02200 02201 _dbus_string_find_blank (&line, 0, &i); 02202 _dbus_string_skip_blank (&line, i, &j); 02203 02204 if (j > i) 02205 _dbus_string_delete (&line, i, j - i); 02206 02207 if (!_dbus_string_move (&line, i, &args, 0)) 02208 goto out; 02209 02210 /* FIXME 1.0 we should probably validate that only the allowed 02211 * chars are in the command name 02212 */ 02213 02214 command = lookup_command_from_name (&line); 02215 if (!(* auth->state->handler) (auth, command, &args)) 02216 goto out; 02217 02218 next_command: 02219 02220 /* We've succeeded in processing the whole command so drop it out 02221 * of the incoming buffer and return TRUE to try another command. 02222 */ 02223 02224 _dbus_string_delete (&auth->incoming, 0, eol); 02225 02226 /* kill the \r\n */ 02227 _dbus_string_delete (&auth->incoming, 0, 2); 02228 02229 retval = TRUE; 02230 02231 out: 02232 _dbus_string_free (&args); 02233 _dbus_string_free (&line); 02234 02235 if (!retval) 02236 auth->needed_memory = TRUE; 02237 else 02238 auth->needed_memory = FALSE; 02239 02240 return retval; 02241 } 02242 02243 02258 DBusAuth* 02259 _dbus_auth_server_new (const DBusString *guid) 02260 { 02261 DBusAuth *auth; 02262 DBusAuthServer *server_auth; 02263 DBusString guid_copy; 02264 02265 if (!_dbus_string_init (&guid_copy)) 02266 return NULL; 02267 02268 if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) 02269 { 02270 _dbus_string_free (&guid_copy); 02271 return NULL; 02272 } 02273 02274 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 02275 if (auth == NULL) 02276 { 02277 _dbus_string_free (&guid_copy); 02278 return NULL; 02279 } 02280 02281 auth->side = auth_side_server; 02282 auth->state = &server_state_waiting_for_auth; 02283 02284 server_auth = DBUS_AUTH_SERVER (auth); 02285 02286 server_auth->guid = guid_copy; 02287 02288 /* perhaps this should be per-mechanism with a lower 02289 * max 02290 */ 02291 server_auth->failures = 0; 02292 server_auth->max_failures = 6; 02293 02294 return auth; 02295 } 02296 02304 DBusAuth* 02305 _dbus_auth_client_new (void) 02306 { 02307 DBusAuth *auth; 02308 DBusString guid_str; 02309 02310 if (!_dbus_string_init (&guid_str)) 02311 return NULL; 02312 02313 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 02314 if (auth == NULL) 02315 { 02316 _dbus_string_free (&guid_str); 02317 return NULL; 02318 } 02319 02320 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; 02321 02322 auth->side = auth_side_client; 02323 auth->state = &client_state_need_send_auth; 02324 02325 /* Start the auth conversation by sending AUTH for our default 02326 * mechanism */ 02327 if (!send_auth (auth, &all_mechanisms[0])) 02328 { 02329 _dbus_auth_unref (auth); 02330 return NULL; 02331 } 02332 02333 return auth; 02334 } 02335 02342 DBusAuth * 02343 _dbus_auth_ref (DBusAuth *auth) 02344 { 02345 _dbus_assert (auth != NULL); 02346 02347 auth->refcount += 1; 02348 02349 return auth; 02350 } 02351 02357 void 02358 _dbus_auth_unref (DBusAuth *auth) 02359 { 02360 _dbus_assert (auth != NULL); 02361 _dbus_assert (auth->refcount > 0); 02362 02363 auth->refcount -= 1; 02364 if (auth->refcount == 0) 02365 { 02366 shutdown_mech (auth); 02367 02368 if (DBUS_AUTH_IS_CLIENT (auth)) 02369 { 02370 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 02371 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 02372 } 02373 else 02374 { 02375 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 02376 02377 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); 02378 } 02379 02380 if (auth->keyring) 02381 _dbus_keyring_unref (auth->keyring); 02382 02383 _dbus_string_free (&auth->context); 02384 _dbus_string_free (&auth->challenge); 02385 _dbus_string_free (&auth->identity); 02386 _dbus_string_free (&auth->incoming); 02387 _dbus_string_free (&auth->outgoing); 02388 02389 dbus_free_string_array (auth->allowed_mechs); 02390 02391 _dbus_credentials_unref (auth->credentials); 02392 _dbus_credentials_unref (auth->authorized_identity); 02393 _dbus_credentials_unref (auth->desired_identity); 02394 02395 dbus_free (auth); 02396 } 02397 } 02398 02407 dbus_bool_t 02408 _dbus_auth_set_mechanisms (DBusAuth *auth, 02409 const char **mechanisms) 02410 { 02411 char **copy; 02412 02413 if (mechanisms != NULL) 02414 { 02415 copy = _dbus_dup_string_array (mechanisms); 02416 if (copy == NULL) 02417 return FALSE; 02418 } 02419 else 02420 copy = NULL; 02421 02422 dbus_free_string_array (auth->allowed_mechs); 02423 02424 auth->allowed_mechs = copy; 02425 02426 return TRUE; 02427 } 02428 02433 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) 02434 02442 DBusAuthState 02443 _dbus_auth_do_work (DBusAuth *auth) 02444 { 02445 auth->needed_memory = FALSE; 02446 02447 /* Max amount we'll buffer up before deciding someone's on crack */ 02448 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 02449 02450 do 02451 { 02452 if (DBUS_AUTH_IN_END_STATE (auth)) 02453 break; 02454 02455 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 02456 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 02457 { 02458 goto_state (auth, &common_state_need_disconnect); 02459 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", 02460 DBUS_AUTH_NAME (auth)); 02461 break; 02462 } 02463 } 02464 while (process_command (auth)); 02465 02466 if (auth->needed_memory) 02467 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 02468 else if (_dbus_string_get_length (&auth->outgoing) > 0) 02469 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 02470 else if (auth->state == &common_state_need_disconnect) 02471 return DBUS_AUTH_STATE_NEED_DISCONNECT; 02472 else if (auth->state == &common_state_authenticated) 02473 return DBUS_AUTH_STATE_AUTHENTICATED; 02474 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 02475 } 02476 02486 dbus_bool_t 02487 _dbus_auth_get_bytes_to_send (DBusAuth *auth, 02488 const DBusString **str) 02489 { 02490 _dbus_assert (auth != NULL); 02491 _dbus_assert (str != NULL); 02492 02493 *str = NULL; 02494 02495 if (_dbus_string_get_length (&auth->outgoing) == 0) 02496 return FALSE; 02497 02498 *str = &auth->outgoing; 02499 02500 return TRUE; 02501 } 02502 02511 void 02512 _dbus_auth_bytes_sent (DBusAuth *auth, 02513 int bytes_sent) 02514 { 02515 _dbus_verbose ("%s: Sent %d bytes of: %s\n", 02516 DBUS_AUTH_NAME (auth), 02517 bytes_sent, 02518 _dbus_string_get_const_data (&auth->outgoing)); 02519 02520 _dbus_string_delete (&auth->outgoing, 02521 0, bytes_sent); 02522 } 02523 02531 void 02532 _dbus_auth_get_buffer (DBusAuth *auth, 02533 DBusString **buffer) 02534 { 02535 _dbus_assert (auth != NULL); 02536 _dbus_assert (!auth->buffer_outstanding); 02537 02538 *buffer = &auth->incoming; 02539 02540 auth->buffer_outstanding = TRUE; 02541 } 02542 02550 void 02551 _dbus_auth_return_buffer (DBusAuth *auth, 02552 DBusString *buffer, 02553 int bytes_read) 02554 { 02555 _dbus_assert (buffer == &auth->incoming); 02556 _dbus_assert (auth->buffer_outstanding); 02557 02558 auth->buffer_outstanding = FALSE; 02559 } 02560 02570 void 02571 _dbus_auth_get_unused_bytes (DBusAuth *auth, 02572 const DBusString **str) 02573 { 02574 if (!DBUS_AUTH_IN_END_STATE (auth)) 02575 return; 02576 02577 *str = &auth->incoming; 02578 } 02579 02580 02587 void 02588 _dbus_auth_delete_unused_bytes (DBusAuth *auth) 02589 { 02590 if (!DBUS_AUTH_IN_END_STATE (auth)) 02591 return; 02592 02593 _dbus_string_set_length (&auth->incoming, 0); 02594 } 02595 02604 dbus_bool_t 02605 _dbus_auth_needs_encoding (DBusAuth *auth) 02606 { 02607 if (auth->state != &common_state_authenticated) 02608 return FALSE; 02609 02610 if (auth->mech != NULL) 02611 { 02612 if (DBUS_AUTH_IS_CLIENT (auth)) 02613 return auth->mech->client_encode_func != NULL; 02614 else 02615 return auth->mech->server_encode_func != NULL; 02616 } 02617 else 02618 return FALSE; 02619 } 02620 02631 dbus_bool_t 02632 _dbus_auth_encode_data (DBusAuth *auth, 02633 const DBusString *plaintext, 02634 DBusString *encoded) 02635 { 02636 _dbus_assert (plaintext != encoded); 02637 02638 if (auth->state != &common_state_authenticated) 02639 return FALSE; 02640 02641 if (_dbus_auth_needs_encoding (auth)) 02642 { 02643 if (DBUS_AUTH_IS_CLIENT (auth)) 02644 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 02645 else 02646 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 02647 } 02648 else 02649 { 02650 return _dbus_string_copy (plaintext, 0, encoded, 02651 _dbus_string_get_length (encoded)); 02652 } 02653 } 02654 02663 dbus_bool_t 02664 _dbus_auth_needs_decoding (DBusAuth *auth) 02665 { 02666 if (auth->state != &common_state_authenticated) 02667 return FALSE; 02668 02669 if (auth->mech != NULL) 02670 { 02671 if (DBUS_AUTH_IS_CLIENT (auth)) 02672 return auth->mech->client_decode_func != NULL; 02673 else 02674 return auth->mech->server_decode_func != NULL; 02675 } 02676 else 02677 return FALSE; 02678 } 02679 02680 02694 dbus_bool_t 02695 _dbus_auth_decode_data (DBusAuth *auth, 02696 const DBusString *encoded, 02697 DBusString *plaintext) 02698 { 02699 _dbus_assert (plaintext != encoded); 02700 02701 if (auth->state != &common_state_authenticated) 02702 return FALSE; 02703 02704 if (_dbus_auth_needs_decoding (auth)) 02705 { 02706 if (DBUS_AUTH_IS_CLIENT (auth)) 02707 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 02708 else 02709 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 02710 } 02711 else 02712 { 02713 return _dbus_string_copy (encoded, 0, plaintext, 02714 _dbus_string_get_length (plaintext)); 02715 } 02716 } 02717 02726 dbus_bool_t 02727 _dbus_auth_set_credentials (DBusAuth *auth, 02728 DBusCredentials *credentials) 02729 { 02730 _dbus_credentials_clear (auth->credentials); 02731 return _dbus_credentials_add_credentials (auth->credentials, 02732 credentials); 02733 } 02734 02744 DBusCredentials* 02745 _dbus_auth_get_identity (DBusAuth *auth) 02746 { 02747 if (auth->state == &common_state_authenticated) 02748 { 02749 return auth->authorized_identity; 02750 } 02751 else 02752 { 02753 /* FIXME instead of this, keep an empty credential around that 02754 * doesn't require allocation or something 02755 */ 02756 /* return empty credentials */ 02757 _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); 02758 return auth->authorized_identity; 02759 } 02760 } 02761 02768 const char* 02769 _dbus_auth_get_guid_from_server (DBusAuth *auth) 02770 { 02771 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); 02772 02773 if (auth->state == &common_state_authenticated) 02774 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 02775 else 02776 return NULL; 02777 } 02778 02787 dbus_bool_t 02788 _dbus_auth_set_context (DBusAuth *auth, 02789 const DBusString *context) 02790 { 02791 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), 02792 &auth->context, 0, _dbus_string_get_length (context)); 02793 } 02794 02802 void 02803 _dbus_auth_set_unix_fd_possible(DBusAuth *auth, dbus_bool_t b) 02804 { 02805 auth->unix_fd_possible = b; 02806 } 02807 02814 dbus_bool_t 02815 _dbus_auth_get_unix_fd_negotiated(DBusAuth *auth) 02816 { 02817 return auth->unix_fd_negotiated; 02818 } 02819 02822 /* tests in dbus-auth-util.c */