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