00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dbus-auth.h"
00024 #include "dbus-string.h"
00025 #include "dbus-list.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-keyring.h"
00028 #include "dbus-sha.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-credentials.h"
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #ifdef _WIN32
00034 #include <windows.h>
00035 #else
00036 #include <sys/stat.h>
00037 #endif
00038 #ifdef sun
00039 #include <sys/types.h>
00040 #include <sys/socket.h>
00041 #endif
00042
00079 typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth,
00080 DBusString *response);
00081
00086 typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth,
00087 const DBusString *data);
00088
00092 typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth,
00093 const DBusString *data,
00094 DBusString *encoded);
00095
00099 typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
00100 const DBusString *data,
00101 DBusString *decoded);
00102
00106 typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth);
00107
00111 typedef struct
00112 {
00113 const char *mechanism;
00114 DBusAuthDataFunction server_data_func;
00115 DBusAuthEncodeFunction server_encode_func;
00116 DBusAuthDecodeFunction server_decode_func;
00117 DBusAuthShutdownFunction server_shutdown_func;
00118 DBusInitialResponseFunction client_initial_response_func;
00119 DBusAuthDataFunction client_data_func;
00120 DBusAuthEncodeFunction client_encode_func;
00121 DBusAuthDecodeFunction client_decode_func;
00122 DBusAuthShutdownFunction client_shutdown_func;
00123 } DBusAuthMechanismHandler;
00124
00128 typedef enum {
00129 DBUS_AUTH_COMMAND_AUTH,
00130 DBUS_AUTH_COMMAND_CANCEL,
00131 DBUS_AUTH_COMMAND_DATA,
00132 DBUS_AUTH_COMMAND_BEGIN,
00133 DBUS_AUTH_COMMAND_REJECTED,
00134 DBUS_AUTH_COMMAND_OK,
00135 DBUS_AUTH_COMMAND_ERROR,
00136 DBUS_AUTH_COMMAND_UNKNOWN
00137 } DBusAuthCommand;
00138
00144 typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth,
00145 DBusAuthCommand command,
00146 const DBusString *args);
00147
00151 typedef struct
00152 {
00153 const char *name;
00154 DBusAuthStateFunction handler;
00155 } DBusAuthStateData;
00156
00160 struct DBusAuth
00161 {
00162 int refcount;
00163 const char *side;
00165 DBusString incoming;
00166 DBusString outgoing;
00168 const DBusAuthStateData *state;
00170 const DBusAuthMechanismHandler *mech;
00172 DBusString identity;
00176 DBusCredentials *credentials;
00179 DBusCredentials *authorized_identity;
00181 DBusCredentials *desired_identity;
00183 DBusString context;
00184 DBusKeyring *keyring;
00185 int cookie_id;
00186 DBusString challenge;
00188 char **allowed_mechs;
00192 unsigned int needed_memory : 1;
00195 unsigned int already_got_mechanisms : 1;
00196 unsigned int already_asked_for_initial_response : 1;
00197 unsigned int buffer_outstanding : 1;
00198 };
00199
00203 typedef struct
00204 {
00205 DBusAuth base;
00207 DBusList *mechs_to_try;
00209 DBusString guid_from_server;
00211 } DBusAuthClient;
00212
00216 typedef struct
00217 {
00218 DBusAuth base;
00220 int failures;
00221 int max_failures;
00223 DBusString guid;
00225 } DBusAuthServer;
00226
00227 static void goto_state (DBusAuth *auth,
00228 const DBusAuthStateData *new_state);
00229 static dbus_bool_t send_auth (DBusAuth *auth,
00230 const DBusAuthMechanismHandler *mech);
00231 static dbus_bool_t send_data (DBusAuth *auth,
00232 DBusString *data);
00233 static dbus_bool_t send_rejected (DBusAuth *auth);
00234 static dbus_bool_t send_error (DBusAuth *auth,
00235 const char *message);
00236 static dbus_bool_t send_ok (DBusAuth *auth);
00237 static dbus_bool_t send_begin (DBusAuth *auth,
00238 const DBusString *args_from_ok);
00239 static dbus_bool_t send_cancel (DBusAuth *auth);
00240
00245 static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth,
00246 DBusAuthCommand command,
00247 const DBusString *args);
00248 static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth,
00249 DBusAuthCommand command,
00250 const DBusString *args);
00251 static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth,
00252 DBusAuthCommand command,
00253 const DBusString *args);
00254
00255 static const DBusAuthStateData server_state_waiting_for_auth = {
00256 "WaitingForAuth", handle_server_state_waiting_for_auth
00257 };
00258 static const DBusAuthStateData server_state_waiting_for_data = {
00259 "WaitingForData", handle_server_state_waiting_for_data
00260 };
00261 static const DBusAuthStateData server_state_waiting_for_begin = {
00262 "WaitingForBegin", handle_server_state_waiting_for_begin
00263 };
00264
00269 static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth,
00270 DBusAuthCommand command,
00271 const DBusString *args);
00272 static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth,
00273 DBusAuthCommand command,
00274 const DBusString *args);
00275 static dbus_bool_t handle_client_state_waiting_for_reject (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
00296 static const DBusAuthStateData common_state_authenticated = {
00297 "Authenticated", NULL
00298 };
00299
00300 static const DBusAuthStateData common_state_need_disconnect = {
00301 "NeedDisconnect", NULL
00302 };
00303
00304 static const char auth_side_client[] = "client";
00305 static const char auth_side_server[] = "server";
00306
00311 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00312
00316 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00317
00321 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
00322
00326 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
00327
00333 #define DBUS_AUTH_NAME(auth) ((auth)->side)
00334
00335 static DBusAuth*
00336 _dbus_auth_new (int size)
00337 {
00338 DBusAuth *auth;
00339
00340 auth = dbus_malloc0 (size);
00341 if (auth == NULL)
00342 return NULL;
00343
00344 auth->refcount = 1;
00345
00346 auth->keyring = NULL;
00347 auth->cookie_id = -1;
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 if (!_dbus_string_init (&auth->incoming))
00358 goto enomem_0;
00359
00360 if (!_dbus_string_init (&auth->outgoing))
00361 goto enomem_1;
00362
00363 if (!_dbus_string_init (&auth->identity))
00364 goto enomem_2;
00365
00366 if (!_dbus_string_init (&auth->context))
00367 goto enomem_3;
00368
00369 if (!_dbus_string_init (&auth->challenge))
00370 goto enomem_4;
00371
00372
00373 if (!_dbus_string_append (&auth->context, "org_freedesktop_general"))
00374 goto enomem_5;
00375
00376 auth->credentials = _dbus_credentials_new ();
00377 if (auth->credentials == NULL)
00378 goto enomem_6;
00379
00380 auth->authorized_identity = _dbus_credentials_new ();
00381 if (auth->authorized_identity == NULL)
00382 goto enomem_7;
00383
00384 auth->desired_identity = _dbus_credentials_new ();
00385 if (auth->desired_identity == NULL)
00386 goto enomem_8;
00387
00388 return auth;
00389
00390 #if 0
00391 enomem_9:
00392 _dbus_credentials_unref (auth->desired_identity);
00393 #endif
00394 enomem_8:
00395 _dbus_credentials_unref (auth->authorized_identity);
00396 enomem_7:
00397 _dbus_credentials_unref (auth->credentials);
00398 enomem_6:
00399 ;
00400 enomem_5:
00401 _dbus_string_free (&auth->challenge);
00402 enomem_4:
00403 _dbus_string_free (&auth->context);
00404 enomem_3:
00405 _dbus_string_free (&auth->identity);
00406 enomem_2:
00407 _dbus_string_free (&auth->outgoing);
00408 enomem_1:
00409 _dbus_string_free (&auth->incoming);
00410 enomem_0:
00411 dbus_free (auth);
00412 return NULL;
00413 }
00414
00415 static void
00416 shutdown_mech (DBusAuth *auth)
00417 {
00418
00419 auth->already_asked_for_initial_response = FALSE;
00420 _dbus_string_set_length (&auth->identity, 0);
00421
00422 _dbus_credentials_clear (auth->authorized_identity);
00423 _dbus_credentials_clear (auth->desired_identity);
00424
00425 if (auth->mech != NULL)
00426 {
00427 _dbus_verbose ("%s: Shutting down mechanism %s\n",
00428 DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00429
00430 if (DBUS_AUTH_IS_CLIENT (auth))
00431 (* auth->mech->client_shutdown_func) (auth);
00432 else
00433 (* auth->mech->server_shutdown_func) (auth);
00434
00435 auth->mech = NULL;
00436 }
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 static dbus_bool_t
00448 sha1_compute_hash (DBusAuth *auth,
00449 int cookie_id,
00450 const DBusString *server_challenge,
00451 const DBusString *client_challenge,
00452 DBusString *hash)
00453 {
00454 DBusString cookie;
00455 DBusString to_hash;
00456 dbus_bool_t retval;
00457
00458 _dbus_assert (auth->keyring != NULL);
00459
00460 retval = FALSE;
00461
00462 if (!_dbus_string_init (&cookie))
00463 return FALSE;
00464
00465 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id,
00466 &cookie))
00467 goto out_0;
00468
00469 if (_dbus_string_get_length (&cookie) == 0)
00470 {
00471 retval = TRUE;
00472 goto out_0;
00473 }
00474
00475 if (!_dbus_string_init (&to_hash))
00476 goto out_0;
00477
00478 if (!_dbus_string_copy (server_challenge, 0,
00479 &to_hash, _dbus_string_get_length (&to_hash)))
00480 goto out_1;
00481
00482 if (!_dbus_string_append (&to_hash, ":"))
00483 goto out_1;
00484
00485 if (!_dbus_string_copy (client_challenge, 0,
00486 &to_hash, _dbus_string_get_length (&to_hash)))
00487 goto out_1;
00488
00489 if (!_dbus_string_append (&to_hash, ":"))
00490 goto out_1;
00491
00492 if (!_dbus_string_copy (&cookie, 0,
00493 &to_hash, _dbus_string_get_length (&to_hash)))
00494 goto out_1;
00495
00496 if (!_dbus_sha_compute (&to_hash, hash))
00497 goto out_1;
00498
00499 retval = TRUE;
00500
00501 out_1:
00502 _dbus_string_zero (&to_hash);
00503 _dbus_string_free (&to_hash);
00504 out_0:
00505 _dbus_string_zero (&cookie);
00506 _dbus_string_free (&cookie);
00507 return retval;
00508 }
00509
00514 #define N_CHALLENGE_BYTES (128/8)
00515
00516 static dbus_bool_t
00517 sha1_handle_first_client_response (DBusAuth *auth,
00518 const DBusString *data)
00519 {
00520
00521
00522
00523 DBusString tmp;
00524 DBusString tmp2;
00525 dbus_bool_t retval;
00526 DBusError error;
00527
00528 retval = FALSE;
00529
00530 _dbus_string_set_length (&auth->challenge, 0);
00531
00532 if (_dbus_string_get_length (data) > 0)
00533 {
00534 if (_dbus_string_get_length (&auth->identity) > 0)
00535 {
00536
00537 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
00538 DBUS_AUTH_NAME (auth));
00539 return send_rejected (auth);
00540 }
00541 else
00542 {
00543
00544 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
00545 return FALSE;
00546 }
00547 }
00548
00549 if (!_dbus_credentials_add_from_user (auth->desired_identity, data))
00550 {
00551 _dbus_verbose ("%s: Did not get a valid username from client\n",
00552 DBUS_AUTH_NAME (auth));
00553 return send_rejected (auth);
00554 }
00555
00556 if (!_dbus_string_init (&tmp))
00557 return FALSE;
00558
00559 if (!_dbus_string_init (&tmp2))
00560 {
00561 _dbus_string_free (&tmp);
00562 return FALSE;
00563 }
00564
00565
00566
00567
00568
00569 if (auth->keyring &&
00570 !_dbus_keyring_is_for_credentials (auth->keyring,
00571 auth->desired_identity))
00572 {
00573 _dbus_keyring_unref (auth->keyring);
00574 auth->keyring = NULL;
00575 }
00576
00577 if (auth->keyring == NULL)
00578 {
00579 dbus_error_init (&error);
00580 auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity,
00581 &auth->context,
00582 &error);
00583
00584 if (auth->keyring == NULL)
00585 {
00586 if (dbus_error_has_name (&error,
00587 DBUS_ERROR_NO_MEMORY))
00588 {
00589 dbus_error_free (&error);
00590 goto out;
00591 }
00592 else
00593 {
00594 _DBUS_ASSERT_ERROR_IS_SET (&error);
00595 _dbus_verbose ("%s: Error loading keyring: %s\n",
00596 DBUS_AUTH_NAME (auth), error.message);
00597 if (send_rejected (auth))
00598 retval = TRUE;
00599 dbus_error_free (&error);
00600 goto out;
00601 }
00602 }
00603 else
00604 {
00605 _dbus_assert (!dbus_error_is_set (&error));
00606 }
00607 }
00608
00609 _dbus_assert (auth->keyring != NULL);
00610
00611 dbus_error_init (&error);
00612 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
00613 if (auth->cookie_id < 0)
00614 {
00615 _DBUS_ASSERT_ERROR_IS_SET (&error);
00616 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
00617 DBUS_AUTH_NAME (auth), error.message);
00618 if (send_rejected (auth))
00619 retval = TRUE;
00620 dbus_error_free (&error);
00621 goto out;
00622 }
00623 else
00624 {
00625 _dbus_assert (!dbus_error_is_set (&error));
00626 }
00627
00628 if (!_dbus_string_copy (&auth->context, 0,
00629 &tmp2, _dbus_string_get_length (&tmp2)))
00630 goto out;
00631
00632 if (!_dbus_string_append (&tmp2, " "))
00633 goto out;
00634
00635 if (!_dbus_string_append_int (&tmp2, auth->cookie_id))
00636 goto out;
00637
00638 if (!_dbus_string_append (&tmp2, " "))
00639 goto out;
00640
00641 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00642 goto out;
00643
00644 _dbus_string_set_length (&auth->challenge, 0);
00645 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0))
00646 goto out;
00647
00648 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2,
00649 _dbus_string_get_length (&tmp2)))
00650 goto out;
00651
00652 if (!send_data (auth, &tmp2))
00653 goto out;
00654
00655 goto_state (auth, &server_state_waiting_for_data);
00656 retval = TRUE;
00657
00658 out:
00659 _dbus_string_zero (&tmp);
00660 _dbus_string_free (&tmp);
00661 _dbus_string_zero (&tmp2);
00662 _dbus_string_free (&tmp2);
00663
00664 return retval;
00665 }
00666
00667 static dbus_bool_t
00668 sha1_handle_second_client_response (DBusAuth *auth,
00669 const DBusString *data)
00670 {
00671
00672
00673
00674
00675
00676 int i;
00677 DBusString client_challenge;
00678 DBusString client_hash;
00679 dbus_bool_t retval;
00680 DBusString correct_hash;
00681
00682 retval = FALSE;
00683
00684 if (!_dbus_string_find_blank (data, 0, &i))
00685 {
00686 _dbus_verbose ("%s: no space separator in client response\n",
00687 DBUS_AUTH_NAME (auth));
00688 return send_rejected (auth);
00689 }
00690
00691 if (!_dbus_string_init (&client_challenge))
00692 goto out_0;
00693
00694 if (!_dbus_string_init (&client_hash))
00695 goto out_1;
00696
00697 if (!_dbus_string_copy_len (data, 0, i, &client_challenge,
00698 0))
00699 goto out_2;
00700
00701 _dbus_string_skip_blank (data, i, &i);
00702
00703 if (!_dbus_string_copy_len (data, i,
00704 _dbus_string_get_length (data) - i,
00705 &client_hash,
00706 0))
00707 goto out_2;
00708
00709 if (_dbus_string_get_length (&client_challenge) == 0 ||
00710 _dbus_string_get_length (&client_hash) == 0)
00711 {
00712 _dbus_verbose ("%s: zero-length client challenge or hash\n",
00713 DBUS_AUTH_NAME (auth));
00714 if (send_rejected (auth))
00715 retval = TRUE;
00716 goto out_2;
00717 }
00718
00719 if (!_dbus_string_init (&correct_hash))
00720 goto out_2;
00721
00722 if (!sha1_compute_hash (auth, auth->cookie_id,
00723 &auth->challenge,
00724 &client_challenge,
00725 &correct_hash))
00726 goto out_3;
00727
00728
00729 if (_dbus_string_get_length (&correct_hash) == 0)
00730 {
00731 if (send_rejected (auth))
00732 retval = TRUE;
00733 goto out_3;
00734 }
00735
00736 if (!_dbus_string_equal (&client_hash, &correct_hash))
00737 {
00738 if (send_rejected (auth))
00739 retval = TRUE;
00740 goto out_3;
00741 }
00742
00743 if (!_dbus_credentials_add_credentials (auth->authorized_identity,
00744 auth->desired_identity))
00745 goto out_3;
00746
00747
00748
00749 if (!_dbus_credentials_add_credential (auth->authorized_identity,
00750 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
00751 auth->credentials))
00752 goto out_3;
00753
00754 if (!send_ok (auth))
00755 goto out_3;
00756
00757 _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n",
00758 DBUS_AUTH_NAME (auth));
00759
00760 retval = TRUE;
00761
00762 out_3:
00763 _dbus_string_zero (&correct_hash);
00764 _dbus_string_free (&correct_hash);
00765 out_2:
00766 _dbus_string_zero (&client_hash);
00767 _dbus_string_free (&client_hash);
00768 out_1:
00769 _dbus_string_free (&client_challenge);
00770 out_0:
00771 return retval;
00772 }
00773
00774 static dbus_bool_t
00775 handle_server_data_cookie_sha1_mech (DBusAuth *auth,
00776 const DBusString *data)
00777 {
00778 if (auth->cookie_id < 0)
00779 return sha1_handle_first_client_response (auth, data);
00780 else
00781 return sha1_handle_second_client_response (auth, data);
00782 }
00783
00784 static void
00785 handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth)
00786 {
00787 auth->cookie_id = -1;
00788 _dbus_string_set_length (&auth->challenge, 0);
00789 }
00790
00791 static dbus_bool_t
00792 handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth,
00793 DBusString *response)
00794 {
00795 DBusString username;
00796 dbus_bool_t retval;
00797
00798 retval = FALSE;
00799
00800 if (!_dbus_string_init (&username))
00801 return FALSE;
00802
00803 if (!_dbus_append_user_from_current_process (&username))
00804 goto out_0;
00805
00806 if (!_dbus_string_hex_encode (&username, 0,
00807 response,
00808 _dbus_string_get_length (response)))
00809 goto out_0;
00810
00811 retval = TRUE;
00812
00813 out_0:
00814 _dbus_string_free (&username);
00815
00816 return retval;
00817 }
00818
00819 static dbus_bool_t
00820 handle_client_data_cookie_sha1_mech (DBusAuth *auth,
00821 const DBusString *data)
00822 {
00823
00824
00825
00826
00827 dbus_bool_t retval;
00828 DBusString context;
00829 DBusString cookie_id_str;
00830 DBusString server_challenge;
00831 DBusString client_challenge;
00832 DBusString correct_hash;
00833 DBusString tmp;
00834 int i, j;
00835 long val;
00836
00837 retval = FALSE;
00838
00839 if (!_dbus_string_find_blank (data, 0, &i))
00840 {
00841 if (send_error (auth,
00842 "Server did not send context/ID/challenge properly"))
00843 retval = TRUE;
00844 goto out_0;
00845 }
00846
00847 if (!_dbus_string_init (&context))
00848 goto out_0;
00849
00850 if (!_dbus_string_copy_len (data, 0, i,
00851 &context, 0))
00852 goto out_1;
00853
00854 _dbus_string_skip_blank (data, i, &i);
00855 if (!_dbus_string_find_blank (data, i, &j))
00856 {
00857 if (send_error (auth,
00858 "Server did not send context/ID/challenge properly"))
00859 retval = TRUE;
00860 goto out_1;
00861 }
00862
00863 if (!_dbus_string_init (&cookie_id_str))
00864 goto out_1;
00865
00866 if (!_dbus_string_copy_len (data, i, j - i,
00867 &cookie_id_str, 0))
00868 goto out_2;
00869
00870 if (!_dbus_string_init (&server_challenge))
00871 goto out_2;
00872
00873 i = j;
00874 _dbus_string_skip_blank (data, i, &i);
00875 j = _dbus_string_get_length (data);
00876
00877 if (!_dbus_string_copy_len (data, i, j - i,
00878 &server_challenge, 0))
00879 goto out_3;
00880
00881 if (!_dbus_keyring_validate_context (&context))
00882 {
00883 if (send_error (auth, "Server sent invalid cookie context"))
00884 retval = TRUE;
00885 goto out_3;
00886 }
00887
00888 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00889 {
00890 if (send_error (auth, "Could not parse cookie ID as an integer"))
00891 retval = TRUE;
00892 goto out_3;
00893 }
00894
00895 if (_dbus_string_get_length (&server_challenge) == 0)
00896 {
00897 if (send_error (auth, "Empty server challenge string"))
00898 retval = TRUE;
00899 goto out_3;
00900 }
00901
00902 if (auth->keyring == NULL)
00903 {
00904 DBusError error;
00905
00906 dbus_error_init (&error);
00907 auth->keyring = _dbus_keyring_new_for_credentials (NULL,
00908 &context,
00909 &error);
00910
00911 if (auth->keyring == NULL)
00912 {
00913 if (dbus_error_has_name (&error,
00914 DBUS_ERROR_NO_MEMORY))
00915 {
00916 dbus_error_free (&error);
00917 goto out_3;
00918 }
00919 else
00920 {
00921 _DBUS_ASSERT_ERROR_IS_SET (&error);
00922
00923 _dbus_verbose ("%s: Error loading keyring: %s\n",
00924 DBUS_AUTH_NAME (auth), error.message);
00925
00926 if (send_error (auth, "Could not load cookie file"))
00927 retval = TRUE;
00928
00929 dbus_error_free (&error);
00930 goto out_3;
00931 }
00932 }
00933 else
00934 {
00935 _dbus_assert (!dbus_error_is_set (&error));
00936 }
00937 }
00938
00939 _dbus_assert (auth->keyring != NULL);
00940
00941 if (!_dbus_string_init (&tmp))
00942 goto out_3;
00943
00944 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00945 goto out_4;
00946
00947 if (!_dbus_string_init (&client_challenge))
00948 goto out_4;
00949
00950 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00951 goto out_5;
00952
00953 if (!_dbus_string_init (&correct_hash))
00954 goto out_5;
00955
00956 if (!sha1_compute_hash (auth, val,
00957 &server_challenge,
00958 &client_challenge,
00959 &correct_hash))
00960 goto out_6;
00961
00962 if (_dbus_string_get_length (&correct_hash) == 0)
00963 {
00964
00965 if (send_error (auth, "Don't have the requested cookie ID"))
00966 retval = TRUE;
00967 goto out_6;
00968 }
00969
00970 _dbus_string_set_length (&tmp, 0);
00971
00972 if (!_dbus_string_copy (&client_challenge, 0, &tmp,
00973 _dbus_string_get_length (&tmp)))
00974 goto out_6;
00975
00976 if (!_dbus_string_append (&tmp, " "))
00977 goto out_6;
00978
00979 if (!_dbus_string_copy (&correct_hash, 0, &tmp,
00980 _dbus_string_get_length (&tmp)))
00981 goto out_6;
00982
00983 if (!send_data (auth, &tmp))
00984 goto out_6;
00985
00986 retval = TRUE;
00987
00988 out_6:
00989 _dbus_string_zero (&correct_hash);
00990 _dbus_string_free (&correct_hash);
00991 out_5:
00992 _dbus_string_free (&client_challenge);
00993 out_4:
00994 _dbus_string_zero (&tmp);
00995 _dbus_string_free (&tmp);
00996 out_3:
00997 _dbus_string_free (&server_challenge);
00998 out_2:
00999 _dbus_string_free (&cookie_id_str);
01000 out_1:
01001 _dbus_string_free (&context);
01002 out_0:
01003 return retval;
01004 }
01005
01006 static void
01007 handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth)
01008 {
01009 auth->cookie_id = -1;
01010 _dbus_string_set_length (&auth->challenge, 0);
01011 }
01012
01013
01014
01015
01016
01017 static dbus_bool_t
01018 handle_server_data_external_mech (DBusAuth *auth,
01019 const DBusString *data)
01020 {
01021 if (_dbus_credentials_are_anonymous (auth->credentials))
01022 {
01023 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n",
01024 DBUS_AUTH_NAME (auth));
01025 return send_rejected (auth);
01026 }
01027
01028 if (_dbus_string_get_length (data) > 0)
01029 {
01030 if (_dbus_string_get_length (&auth->identity) > 0)
01031 {
01032
01033 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
01034 DBUS_AUTH_NAME (auth));
01035 return send_rejected (auth);
01036 }
01037 else
01038 {
01039
01040 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
01041 return FALSE;
01042 }
01043 }
01044
01045
01046 if (_dbus_string_get_length (&auth->identity) == 0 &&
01047 !auth->already_asked_for_initial_response)
01048 {
01049 if (send_data (auth, NULL))
01050 {
01051 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01052 DBUS_AUTH_NAME (auth));
01053 auth->already_asked_for_initial_response = TRUE;
01054 goto_state (auth, &server_state_waiting_for_data);
01055 return TRUE;
01056 }
01057 else
01058 return FALSE;
01059 }
01060
01061 _dbus_credentials_clear (auth->desired_identity);
01062
01063
01064
01065
01066
01067
01068 if (_dbus_string_get_length (&auth->identity) == 0)
01069 {
01070 if (!_dbus_credentials_add_credentials (auth->desired_identity,
01071 auth->credentials))
01072 {
01073 return FALSE;
01074 }
01075 }
01076 else
01077 {
01078 if (!_dbus_credentials_add_from_user (auth->desired_identity,
01079 &auth->identity))
01080 {
01081 _dbus_verbose ("%s: could not get credentials from uid string\n",
01082 DBUS_AUTH_NAME (auth));
01083 return send_rejected (auth);
01084 }
01085 }
01086
01087 if (_dbus_credentials_are_anonymous (auth->desired_identity))
01088 {
01089 _dbus_verbose ("%s: desired user %s is no good\n",
01090 DBUS_AUTH_NAME (auth),
01091 _dbus_string_get_const_data (&auth->identity));
01092 return send_rejected (auth);
01093 }
01094
01095 if (_dbus_credentials_are_superset (auth->credentials,
01096 auth->desired_identity))
01097 {
01098
01099 if (!_dbus_credentials_add_credentials (auth->authorized_identity,
01100 auth->desired_identity))
01101 return FALSE;
01102
01103
01104
01105 if (!_dbus_credentials_add_credential (auth->authorized_identity,
01106 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01107 auth->credentials))
01108 return FALSE;
01109
01110 if (!send_ok (auth))
01111 return FALSE;
01112
01113 _dbus_verbose ("%s: authenticated client based on socket credentials\n",
01114 DBUS_AUTH_NAME (auth));
01115
01116 return TRUE;
01117 }
01118 else
01119 {
01120 _dbus_verbose ("%s: desired identity not found in socket credentials\n",
01121 DBUS_AUTH_NAME (auth));
01122 return send_rejected (auth);
01123 }
01124 }
01125
01126 static void
01127 handle_server_shutdown_external_mech (DBusAuth *auth)
01128 {
01129
01130 }
01131
01132
01133
01134
01135 #define MIN_KEY_SIZE 50
01136 #define MAX_KEY_SIZE 500
01137 #define MAX_IP_LENGTH 20
01138 #define LINE_LENGTH 40
01139 #define BACK_DOOR_FILE "/var/lib/nza/.dbus_auth"
01140 #define NEXENTA_RSA_ENV_VAR "NEXENTA_ID_RSA"
01141 #define NEXENTA_KEY_TABLE "/root/.ssh/authorized_keys"
01142 #define NEXENTA_KEY_TABLE_2 "/var/lib/nza/authorized_keys"
01143 #define LOCAL_KEY_FILE_NAME "/root/.ssh/id_rsa.pub"
01144 #define KEY_FILE_NAME "id_rsa.pub"
01145 #define NULL_IP_STRING "0.0.0.0"
01146 #define LOCALHOST_STRING "127.0.0.1"
01147
01148 #define _NEXENTA_DEBUG_ 1
01149
01150 #ifdef _NEXENTA_DEBUG_
01151 #define _BUF_SIZE 2048
01152 #define _TIME_SIZE 20
01153 #ifdef _WIN32
01154 #define LOG_FILE "c:/nexenta.log"
01155 #else
01156 #define LOG_FILE "/var/log/dbus.log"
01157 #endif
01158 #endif
01159 static void _nexenta_log (const char *format, ...)
01160 {
01161 #ifdef _NEXENTA_DEBUG_
01162 char buf[_BUF_SIZE];
01163 char time_buf[_TIME_SIZE];
01164 struct tm *_tm;
01165 time_t _time;
01166 va_list ap;
01167 FILE *file;
01168 if (access("/tmp/.dbus_auth_log", 0) != 0) return;
01169 file = fopen (LOG_FILE, "a");
01170 if (file) {
01171 buf[_BUF_SIZE - 1] = '\0';
01172 va_start (ap, format);
01173 vsnprintf (buf, _BUF_SIZE - 1, format, ap);
01174 va_end (ap);
01175 _time = time (&_time);
01176 _tm = localtime (&_time);
01177 strftime (time_buf, _TIME_SIZE - 1, "%H:%M:%S", _tm);
01178 fwrite (time_buf, 1, strlen (time_buf), file);
01179 fwrite (" : ", 1, strlen (" : "), file);
01180 fwrite (buf, 1, strlen (buf), file);
01181 fwrite ("\n", 1, strlen ("\n"), file);
01182 fclose (file);
01183 };
01184 #else
01185 #endif
01186 };
01187
01188 static int _check_key (const char *file_name, const char *ssh_key)
01189 {
01190 FILE *file;
01191 int res = NEXENTA_AUTH_INVALID_KEY;
01192 char keys[MAX_KEY_SIZE];
01193
01194 _nexenta_log ("BEGIN check key <%s>", ssh_key);
01195 if (!ssh_key) return NEXENTA_AUTH_NO_KEY;
01196 if (strlen (ssh_key) < MIN_KEY_SIZE) return NEXENTA_AUTH_NO_KEY;
01197 if ((file = fopen (file_name, "r"))) {
01198 while (res != NEXENTA_AUTH_OK && !feof (file)) {
01199 fgets (keys, MAX_KEY_SIZE, file);
01200 if (strncmp (keys, ssh_key, strlen (ssh_key)) == 0)
01201 res = NEXENTA_AUTH_OK;
01202 };
01203 fclose (file);
01204 } else {
01205 _nexenta_log ("authorized keys file <%s> was not found", file_name);
01206 res = NEXENTA_AUTH_NO_KEY_LIST;
01207 };
01208 _nexenta_log ("END check key. result = %d", res);
01209 return res;
01210 };
01211 #ifdef sun
01212 static int _check_rights (const char *ip)
01213 {
01214 int allow = 0;
01215 FILE *file;
01216 char line[LINE_LENGTH];
01217 int res;
01218 char *st;
01219 char *asterix;
01220 int typ;
01221 int lastc;
01222 int line_count = 0;
01223
01224 _nexenta_log ("BEGIN check IP <%s> rights", ip);
01225 if (strcmp (NULL_IP_STRING, ip) == 0 || strcmp (LOCALHOST_STRING, ip) == 0)
01226 return 1;
01227
01228 if ((file = fopen (BACK_DOOR_FILE, "r"))) {
01229 _nexenta_log ("backdoor file is found");
01230 while (!feof (file)) {
01231 fgets (line, MAX_KEY_SIZE, file);
01232 lastc = strlen (line);
01233 while (lastc > 0 && line[lastc] < 32)
01234 --lastc;
01235 line[lastc + 1] = '\0';
01236 if (strncmp (line, "deny", 4) == 0)
01237 typ = 0;
01238 else if (strncmp (line, "allow", 5) == 0)
01239 typ = 1;
01240 else
01241 typ = 2;
01242 if (typ != 2) {
01243 ++line_count;
01244 st = &line[(typ == 1)? 6 : 5];
01245 asterix = strchr (st, '*');
01246 if (asterix == 0)
01247 res = strcmp (st, ip);
01248 else
01249 res = strncmp (st, ip, asterix - st);
01250 if (res == 0)
01251 allow = typ;
01252 };
01253 };
01254 fclose (file);
01255 if (!line_count)
01256 allow = 1;
01257 };
01258 _nexenta_log ("END IP <%s> allowed = %d", ip, allow);
01259 return allow;
01260 }
01261 #endif
01262
01263 static int key_exists (char *ssh_key)
01264 {
01265 #ifndef sun
01266 return NEXENTA_AUTH_OK;
01267 #else
01268 int exists;
01269
01270 _nexenta_log ("CHECK key in database");
01271 exists = _check_key (NEXENTA_KEY_TABLE, ssh_key);
01272 if (exists != NEXENTA_AUTH_OK) {
01273 _nexenta_log ("First DB check failed. Checking secondary DB");
01274 exists = _check_key (NEXENTA_KEY_TABLE_2, ssh_key);
01275 };
01276 _nexenta_log ("END search result %d", exists);
01277 return exists;
01278 #endif
01279 };
01280
01281 static int get_file_size (FILE *file)
01282 {
01283 int sz;
01284 #ifdef _WIN32
01285 fseek (file, 0, SEEK_END);
01286 sz = ftell (file);
01287 rewind (file);
01288 #else
01289 struct stat st;
01290 fstat (fileno (file), &st);
01291 sz = st.st_size;
01292 #endif
01293 return sz;
01294 };
01295 static dbus_bool_t load_key_file (char **ssh_key)
01296 {
01297 const char *env;
01298 char *file_path = 0;
01299 FILE *file;
01300
01301 _nexenta_log ("BEGIN load key file");
01302 if (ssh_key == 0) return FALSE;
01303 env = _dbus_getenv (NEXENTA_RSA_ENV_VAR);
01304 if (env) {
01305 _nexenta_log ("get file name from environment variable");
01306 file_path = dbus_malloc (strlen (env) + 1);
01307 if (!file_path)
01308 return FALSE;
01309 strcpy (file_path, env);
01310 };
01311 if (!file_path){
01312 #ifdef _WIN32
01313 env = _dbus_getenv ("USERPROFILE");
01314 file_path = dbus_malloc (strlen (env) + strlen (file_name) + 2);
01315 if (!file_path)
01316 return FALSE;
01317 if (env == 0)
01318 sprintf (file_path, "%s", file_name);
01319 else sprintf (file_path, "%s\\%s", env, file_name);
01320 #else
01321 file_path = dbus_malloc (strlen (LOCAL_KEY_FILE_NAME) + 1);
01322 if (!file_path)
01323 return FALSE;
01324 sprintf (file_path, "%s", LOCAL_KEY_FILE_NAME);
01325 #endif
01326 };
01327 if ((file = fopen (file_path, "r"))) {
01328 int file_size;
01329 int i;
01330
01331 file_size = get_file_size (file);
01332 _nexenta_log ("read key from <%s>, size = %d", file_path, file_size);
01333 *ssh_key = dbus_malloc (file_size);
01334 if (*ssh_key == 0)
01335 goto _end_read;
01336 fread (*ssh_key, 1, file_size, file);
01337 i = file_size - 1;
01338 while (i > 0 && (*ssh_key)[i] != '=') {
01339 (*ssh_key)[i] = '\0';
01340 --i;
01341 };
01342 _end_read:
01343 fclose (file);
01344 } else {
01345 _nexenta_log ("could not open key file");
01346 *ssh_key = 0;
01347 };
01348 dbus_free (file_path);
01349 if (*ssh_key) _nexenta_log ("the ssh-key = <%s>", *ssh_key);
01350
01351 return (*ssh_key != 0)? FALSE : TRUE;
01352 };
01353 #ifdef sun
01354 static int is_local_call (const char *ssh_key)
01355 {
01356 return (_check_key (LOCAL_KEY_FILE_NAME, ssh_key) == NEXENTA_AUTH_OK);
01357 }
01358 #endif
01359
01360 static dbus_bool_t
01361 handle_server_data_nexenta_mech (DBusAuth *auth,
01362 const DBusString *data)
01363 {
01364 int local_call = 0;
01365 int is_ip_allowed = 0;
01366 int sid = 0;
01367 #ifdef sun
01368 struct sockaddr_in saddr;
01369 socklen_t slen;
01370 char client_ip [MAX_IP_LENGTH];
01371 #endif
01372
01373 _nexenta_log ("BEGIN server side authorization");
01374 #ifdef sun
01375 slen = sizeof (saddr);
01376 sid = _dbus_credentials_get_unix_sid(auth->credentials);
01377 _nexenta_log (" sid_id = %d", sid);
01378 if (getpeername (sid, &saddr, &slen) == 0) {
01379 sprintf (client_ip, "%s", inet_ntoa (saddr.sin_addr));
01380 } else {
01381 sprintf (client_ip, "%s", NULL_IP_STRING);
01382 };
01383 _nexenta_log (" ip_addr = %s", inet_ntoa (saddr.sin_addr));
01384 is_ip_allowed = _check_rights (client_ip);
01385 _nexenta_log (" is_ip_allowed = %d", is_ip_allowed);
01386 #endif
01387
01388 if (_dbus_credentials_are_anonymous (auth->credentials)) {
01389 _dbus_credentials_add_unix_uid(auth->credentials, 0);
01390 }
01391 if (_dbus_string_get_length (data) > 0) {
01392 if (_dbus_string_get_length (&auth->identity) > 0) {
01393
01394 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n",
01395 DBUS_AUTH_NAME (auth));
01396 return send_rejected (auth);
01397 } else {
01398
01399 if (!_dbus_string_copy (data, 0, &auth->identity, 0))
01400 return FALSE;
01401 }
01402 }
01403
01404
01405 if (_dbus_string_get_length (&auth->identity) == 0 &&
01406 !auth->already_asked_for_initial_response)
01407 {
01408 if (send_data (auth, NULL)) {
01409 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n",
01410 DBUS_AUTH_NAME (auth));
01411 auth->already_asked_for_initial_response = TRUE;
01412 return TRUE;
01413 }
01414 else
01415 return FALSE;
01416 }
01417
01418 _dbus_credentials_clear (auth->desired_identity);
01419
01420
01421
01422
01423
01424
01425 if (_dbus_string_get_length (&auth->identity) == 0) {
01426 _dbus_credentials_add_unix_uid(auth->desired_identity, _dbus_credentials_get_unix_uid(auth->credentials));
01427 } else {
01428 int _auth = NEXENTA_AUTH_OK;
01429 #ifdef sun
01430 if (!is_ip_allowed)
01431 local_call = is_local_call (_dbus_string_get_data (&auth->identity));
01432 #endif
01433 if (!local_call && !is_ip_allowed)
01434 _auth = key_exists (_dbus_string_get_data (&auth->identity));
01435 _nexenta_log (" local_call = %d", local_call);
01436 _nexenta_log (" key_exists = %d", _auth);
01437 if (local_call || is_ip_allowed || _auth == NEXENTA_AUTH_OK) {
01438 _dbus_credentials_add_unix_uid(auth->desired_identity, 0);
01439 auth->credentials = auth->desired_identity;
01440 } else {
01441 _nexenta_log ("server authorization failed");
01442 char nms_err[NEXENTA_ERROR_MAX_LENGTH];
01443 _dbus_verbose ("%s key is not authorized\n", DBUS_AUTH_NAME (auth));
01444 sprintf (nms_err, "%s%d", NEXENTA_ERROR_PREFIX, _auth);
01445 return send_error (auth, nms_err);
01446 };
01447 }
01448
01449 if (_dbus_credentials_are_anonymous (auth->desired_identity)) {
01450 _dbus_verbose ("%s: desired user %s is no good\n",
01451 DBUS_AUTH_NAME (auth),
01452 _dbus_string_get_const_data (&auth->identity));
01453 _nexenta_log ("Desired no good");
01454 return send_rejected (auth);
01455 }
01456 if (_dbus_credentials_are_superset(auth->credentials, auth->desired_identity)) {
01457
01458 if (!_dbus_credentials_add_credentials (auth->authorized_identity, auth->desired_identity)) {
01459 _nexenta_log ("Send add 1 failed"); return FALSE; }
01460
01461
01462 if (!_dbus_credentials_add_credential (auth->authorized_identity,
01463 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01464 auth->credentials)) {
01465 _nexenta_log ("Send add 2 failed"); return FALSE; }
01466
01467 if (!send_ok (auth)) {
01468 _nexenta_log ("Send is failed");
01469 return FALSE;
01470 }
01471
01472 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT
01473 " matching socket credentials UID "DBUS_UID_FORMAT"\n",
01474 DBUS_AUTH_NAME (auth),
01475 _dbus_credentials_get_unix_uid(auth->desired_identity),
01476 _dbus_credentials_get_unix_uid(auth->credentials));
01477
01478 _dbus_credentials_add_unix_pid(auth->authorized_identity, _dbus_credentials_get_unix_pid(auth->credentials));
01479 _dbus_credentials_add_unix_uid(auth->authorized_identity, _dbus_credentials_get_unix_uid(auth->desired_identity));
01480 _nexenta_log ("Auth OK");
01481 return TRUE;
01482 } else {
01483 _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT
01484 " gid="DBUS_GID_FORMAT
01485 " do not allow uid="DBUS_UID_FORMAT
01486 " gid="DBUS_GID_FORMAT"\n",
01487 DBUS_AUTH_NAME (auth),
01488 _dbus_credentials_get_unix_uid(auth->credentials), _dbus_credentials_get_unix_sid(auth->credentials),
01489 _dbus_credentials_get_unix_uid(auth->desired_identity), _dbus_credentials_get_unix_sid(auth->desired_identity));
01490 _nexenta_log ("Client has failed auth");
01491 return send_rejected (auth);
01492 }
01493 }
01494
01495 static void
01496 handle_server_shutdown_nexenta_mech (DBusAuth *auth)
01497 {
01498
01499 }
01500
01501 static dbus_bool_t
01502 handle_client_initial_response_nexenta_mech (DBusAuth *auth,
01503 DBusString *response)
01504 {
01505
01506
01507
01508
01509
01510 DBusString plaintext;
01511 char *key = 0;
01512
01513 _nexenta_log ("BEGIN client side authorization");
01514 if (!_dbus_string_init (&plaintext))
01515 return FALSE;
01516 load_key_file (&key);
01517
01518 if (key) {
01519 if (!_dbus_string_append (&plaintext, key))
01520 goto failed;
01521 } else {
01522 if (!_dbus_string_append (&plaintext, "No key"))
01523 goto failed;
01524 };
01525 if (!_dbus_string_hex_encode (&plaintext, 0,
01526 response,
01527 _dbus_string_get_length (response)))
01528 goto failed;
01529 _nexenta_log ("client side autorization OK. key = <%s>", key);
01530 if (key)
01531 dbus_free (key);
01532 _dbus_string_free (&plaintext);
01533 return TRUE;
01534
01535 failed:
01536 _nexenta_log ("client side authorization failed");
01537 if (key)
01538 dbus_free (key);
01539 _dbus_string_free (&plaintext);
01540 return FALSE;
01541 }
01542
01543 static dbus_bool_t
01544 handle_client_data_nexenta_mech (DBusAuth *auth,
01545 const DBusString *data)
01546 {
01547 return TRUE;
01548 }
01549
01550 static void
01551 handle_client_shutdown_nexenta_mech (DBusAuth *auth)
01552 {
01553
01554 }
01555
01556
01557
01558
01559 static dbus_bool_t
01560 handle_client_initial_response_external_mech (DBusAuth *auth,
01561 DBusString *response)
01562 {
01563
01564
01565
01566
01567
01568 DBusString plaintext;
01569
01570 if (!_dbus_string_init (&plaintext))
01571 return FALSE;
01572
01573 if (!_dbus_append_user_from_current_process (&plaintext))
01574 goto failed;
01575
01576 if (!_dbus_string_hex_encode (&plaintext, 0,
01577 response,
01578 _dbus_string_get_length (response)))
01579 goto failed;
01580
01581 _dbus_string_free (&plaintext);
01582
01583 return TRUE;
01584
01585 failed:
01586 _dbus_string_free (&plaintext);
01587 return FALSE;
01588 }
01589
01590 static dbus_bool_t
01591 handle_client_data_external_mech (DBusAuth *auth,
01592 const DBusString *data)
01593 {
01594
01595 return TRUE;
01596 }
01597
01598 static void
01599 handle_client_shutdown_external_mech (DBusAuth *auth)
01600 {
01601
01602 }
01603
01604
01605
01606
01607
01608 static dbus_bool_t
01609 handle_server_data_anonymous_mech (DBusAuth *auth,
01610 const DBusString *data)
01611 {
01612 if (_dbus_string_get_length (data) > 0)
01613 {
01614
01615
01616
01617
01618
01619 if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data)))
01620 {
01621 _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
01622 DBUS_AUTH_NAME (auth));
01623
01624 {
01625 DBusString plaintext;
01626 DBusString encoded;
01627 _dbus_string_init_const (&plaintext, "D-Bus " VERSION);
01628 _dbus_string_init (&encoded);
01629 _dbus_string_hex_encode (&plaintext, 0,
01630 &encoded,
01631 0);
01632 _dbus_verbose ("%s: try '%s'\n",
01633 DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
01634 }
01635 return send_rejected (auth);
01636 }
01637
01638 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n",
01639 DBUS_AUTH_NAME (auth),
01640 _dbus_string_get_const_data (data));
01641 }
01642
01643
01644 _dbus_credentials_clear (auth->desired_identity);
01645
01646
01647
01648 if (!_dbus_credentials_add_credential (auth->authorized_identity,
01649 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
01650 auth->credentials))
01651 return FALSE;
01652
01653
01654 if (!send_ok (auth))
01655 return FALSE;
01656
01657 _dbus_verbose ("%s: authenticated client as anonymous\n",
01658 DBUS_AUTH_NAME (auth));
01659
01660 return TRUE;
01661 }
01662
01663 static void
01664 handle_server_shutdown_anonymous_mech (DBusAuth *auth)
01665 {
01666
01667 }
01668
01669 static dbus_bool_t
01670 handle_client_initial_response_anonymous_mech (DBusAuth *auth,
01671 DBusString *response)
01672 {
01673
01674
01675
01676
01677
01678
01679 DBusString plaintext;
01680
01681 if (!_dbus_string_init (&plaintext))
01682 return FALSE;
01683
01684 if (!_dbus_string_append (&plaintext,
01685 "libdbus " VERSION))
01686 goto failed;
01687
01688 if (!_dbus_string_hex_encode (&plaintext, 0,
01689 response,
01690 _dbus_string_get_length (response)))
01691 goto failed;
01692
01693 _dbus_string_free (&plaintext);
01694
01695 return TRUE;
01696
01697 failed:
01698 _dbus_string_free (&plaintext);
01699 return FALSE;
01700 }
01701
01702 static dbus_bool_t
01703 handle_client_data_anonymous_mech (DBusAuth *auth,
01704 const DBusString *data)
01705 {
01706
01707 return TRUE;
01708 }
01709
01710 static void
01711 handle_client_shutdown_anonymous_mech (DBusAuth *auth)
01712 {
01713
01714 }
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727 static const DBusAuthMechanismHandler
01728 all_mechanisms[] = {
01729 { "NEXENTA",
01730 handle_server_data_nexenta_mech,
01731 NULL, NULL,
01732 handle_server_shutdown_nexenta_mech,
01733 handle_client_initial_response_nexenta_mech,
01734 handle_client_data_nexenta_mech,
01735 NULL, NULL,
01736 handle_client_shutdown_nexenta_mech },
01737 { "EXTERNAL",
01738 handle_server_data_external_mech,
01739 NULL, NULL,
01740 handle_server_shutdown_external_mech,
01741 handle_client_initial_response_external_mech,
01742 handle_client_data_external_mech,
01743 NULL, NULL,
01744 handle_client_shutdown_external_mech },
01745 { "DBUS_COOKIE_SHA1",
01746 handle_server_data_cookie_sha1_mech,
01747 NULL, NULL,
01748 handle_server_shutdown_cookie_sha1_mech,
01749 handle_client_initial_response_cookie_sha1_mech,
01750 handle_client_data_cookie_sha1_mech,
01751 NULL, NULL,
01752 handle_client_shutdown_cookie_sha1_mech },
01753 { "ANONYMOUS",
01754 handle_server_data_anonymous_mech,
01755 NULL, NULL,
01756 handle_server_shutdown_anonymous_mech,
01757 handle_client_initial_response_anonymous_mech,
01758 handle_client_data_anonymous_mech,
01759 NULL, NULL,
01760 handle_client_shutdown_anonymous_mech },
01761 { NULL, NULL }
01762 };
01763
01764 static const DBusAuthMechanismHandler*
01765 find_mech (const DBusString *name,
01766 char **allowed_mechs)
01767 {
01768 int i;
01769
01770 if (allowed_mechs != NULL &&
01771 !_dbus_string_array_contains ((const char**) allowed_mechs,
01772 _dbus_string_get_const_data (name)))
01773 return NULL;
01774
01775 i = 0;
01776 while (all_mechanisms[i].mechanism != NULL)
01777 {
01778 if (_dbus_string_equal_c_str (name,
01779 all_mechanisms[i].mechanism))
01780
01781 return &all_mechanisms[i];
01782
01783 ++i;
01784 }
01785
01786 return NULL;
01787 }
01788
01789 static dbus_bool_t
01790 send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
01791 {
01792 DBusString auth_command;
01793
01794 if (!_dbus_string_init (&auth_command))
01795 return FALSE;
01796
01797 if (!_dbus_string_append (&auth_command,
01798 "AUTH "))
01799 {
01800 _dbus_string_free (&auth_command);
01801 return FALSE;
01802 }
01803
01804 if (!_dbus_string_append (&auth_command,
01805 mech->mechanism))
01806 {
01807 _dbus_string_free (&auth_command);
01808 return FALSE;
01809 }
01810
01811 if (mech->client_initial_response_func != NULL)
01812 {
01813 if (!_dbus_string_append (&auth_command, " "))
01814 {
01815 _dbus_string_free (&auth_command);
01816 return FALSE;
01817 }
01818
01819 if (!(* mech->client_initial_response_func) (auth, &auth_command))
01820 {
01821 _dbus_string_free (&auth_command);
01822 return FALSE;
01823 }
01824 }
01825
01826 if (!_dbus_string_append (&auth_command,
01827 "\r\n"))
01828 {
01829 _dbus_string_free (&auth_command);
01830 return FALSE;
01831 }
01832
01833 if (!_dbus_string_copy (&auth_command, 0,
01834 &auth->outgoing,
01835 _dbus_string_get_length (&auth->outgoing)))
01836 {
01837 _dbus_string_free (&auth_command);
01838 return FALSE;
01839 }
01840
01841 _dbus_string_free (&auth_command);
01842 shutdown_mech (auth);
01843 auth->mech = mech;
01844 goto_state (auth, &client_state_waiting_for_data);
01845
01846 return TRUE;
01847 }
01848
01849 static dbus_bool_t
01850 send_data (DBusAuth *auth, DBusString *data)
01851 {
01852 int old_len;
01853
01854 if (data == NULL || _dbus_string_get_length (data) == 0)
01855 return _dbus_string_append (&auth->outgoing, "DATA\r\n");
01856 else
01857 {
01858 old_len = _dbus_string_get_length (&auth->outgoing);
01859 if (!_dbus_string_append (&auth->outgoing, "DATA "))
01860 goto out;
01861
01862 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing,
01863 _dbus_string_get_length (&auth->outgoing)))
01864 goto out;
01865
01866 if (!_dbus_string_append (&auth->outgoing, "\r\n"))
01867 goto out;
01868
01869 return TRUE;
01870
01871 out:
01872 _dbus_string_set_length (&auth->outgoing, old_len);
01873
01874 return FALSE;
01875 }
01876 }
01877
01878 static dbus_bool_t
01879 send_rejected (DBusAuth *auth)
01880 {
01881 DBusString command;
01882 DBusAuthServer *server_auth;
01883 int i;
01884
01885 if (!_dbus_string_init (&command))
01886 return FALSE;
01887
01888 if (!_dbus_string_append (&command,
01889 "REJECTED"))
01890 goto nomem;
01891
01892 i = 0;
01893 while (all_mechanisms[i].mechanism != NULL)
01894 {
01895 if (!_dbus_string_append (&command,
01896 " "))
01897 goto nomem;
01898
01899 if (!_dbus_string_append (&command,
01900 all_mechanisms[i].mechanism))
01901 goto nomem;
01902
01903 ++i;
01904 }
01905
01906 if (!_dbus_string_append (&command, "\r\n"))
01907 goto nomem;
01908
01909 if (!_dbus_string_copy (&command, 0, &auth->outgoing,
01910 _dbus_string_get_length (&auth->outgoing)))
01911 goto nomem;
01912
01913 shutdown_mech (auth);
01914
01915 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01916 server_auth = DBUS_AUTH_SERVER (auth);
01917 server_auth->failures += 1;
01918
01919 if (server_auth->failures >= server_auth->max_failures)
01920 goto_state (auth, &common_state_need_disconnect);
01921 else
01922 goto_state (auth, &server_state_waiting_for_auth);
01923
01924 _dbus_string_free (&command);
01925
01926 return TRUE;
01927
01928 nomem:
01929 _dbus_string_free (&command);
01930 return FALSE;
01931 }
01932
01933 static dbus_bool_t
01934 send_error (DBusAuth *auth, const char *message)
01935 {
01936 return _dbus_string_append_printf (&auth->outgoing,
01937 "ERROR \"%s\"\r\n", message);
01938 }
01939
01940 static dbus_bool_t
01941 send_ok (DBusAuth *auth)
01942 {
01943 int orig_len;
01944
01945 orig_len = _dbus_string_get_length (&auth->outgoing);
01946
01947 if (_dbus_string_append (&auth->outgoing, "OK ") &&
01948 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid,
01949 0,
01950 &auth->outgoing,
01951 _dbus_string_get_length (&auth->outgoing)) &&
01952 _dbus_string_append (&auth->outgoing, "\r\n"))
01953 {
01954 goto_state (auth, &server_state_waiting_for_begin);
01955 return TRUE;
01956 }
01957 else
01958 {
01959 _dbus_string_set_length (&auth->outgoing, orig_len);
01960 return FALSE;
01961 }
01962 }
01963
01964 static dbus_bool_t
01965 send_begin (DBusAuth *auth,
01966 const DBusString *args_from_ok)
01967 {
01968 int end_of_hex;
01969
01970
01971 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0);
01972
01973
01974
01975 end_of_hex = 0;
01976 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex,
01977 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0))
01978 return FALSE;
01979
01980
01981 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
01982
01983 if (end_of_hex != _dbus_string_get_length (args_from_ok) ||
01984 end_of_hex == 0)
01985 {
01986 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n",
01987 end_of_hex, _dbus_string_get_length (args_from_ok));
01988 goto_state (auth, &common_state_need_disconnect);
01989 return TRUE;
01990 }
01991
01992 if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) &&
01993 _dbus_string_append (&auth->outgoing, "BEGIN\r\n"))
01994 {
01995 _dbus_verbose ("Got GUID '%s' from the server\n",
01996 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server));
01997
01998 goto_state (auth, &common_state_authenticated);
01999 return TRUE;
02000 }
02001 else
02002 {
02003 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0);
02004 return FALSE;
02005 }
02006 }
02007
02008 static dbus_bool_t
02009 send_cancel (DBusAuth *auth)
02010 {
02011 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n"))
02012 {
02013 goto_state (auth, &client_state_waiting_for_reject);
02014 return TRUE;
02015 }
02016 else
02017 return FALSE;
02018 }
02019
02020 static dbus_bool_t
02021 process_data (DBusAuth *auth,
02022 const DBusString *args,
02023 DBusAuthDataFunction data_func)
02024 {
02025 int end;
02026 DBusString decoded;
02027
02028 if (!_dbus_string_init (&decoded))
02029 return FALSE;
02030
02031 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
02032 {
02033 _dbus_string_free (&decoded);
02034 return FALSE;
02035 }
02036
02037 if (_dbus_string_get_length (args) != end)
02038 {
02039 _dbus_string_free (&decoded);
02040 if (!send_error (auth, "Invalid hex encoding"))
02041 return FALSE;
02042
02043 return TRUE;
02044 }
02045
02046 #ifdef DBUS_ENABLE_VERBOSE_MODE
02047 if (_dbus_string_validate_ascii (&decoded, 0,
02048 _dbus_string_get_length (&decoded)))
02049 _dbus_verbose ("%s: data: '%s'\n",
02050 DBUS_AUTH_NAME (auth),
02051 _dbus_string_get_const_data (&decoded));
02052 #endif
02053
02054 if (!(* data_func) (auth, &decoded))
02055 {
02056 _dbus_string_free (&decoded);
02057 return FALSE;
02058 }
02059
02060 _dbus_string_free (&decoded);
02061 return TRUE;
02062 }
02063
02064 static dbus_bool_t
02065 handle_auth (DBusAuth *auth, const DBusString *args)
02066 {
02067 if (_dbus_string_get_length (args) == 0)
02068 {
02069
02070 if (!send_rejected (auth))
02071 return FALSE;
02072
02073 return TRUE;
02074 }
02075 else
02076 {
02077 int i;
02078 DBusString mech;
02079 DBusString hex_response;
02080
02081 _dbus_string_find_blank (args, 0, &i);
02082
02083 if (!_dbus_string_init (&mech))
02084 return FALSE;
02085
02086 if (!_dbus_string_init (&hex_response))
02087 {
02088 _dbus_string_free (&mech);
02089 return FALSE;
02090 }
02091
02092 if (!_dbus_string_copy_len (args, 0, i, &mech, 0))
02093 goto failed;
02094
02095 _dbus_string_skip_blank (args, i, &i);
02096 if (!_dbus_string_copy (args, i, &hex_response, 0))
02097 goto failed;
02098
02099 auth->mech = find_mech (&mech, auth->allowed_mechs);
02100 if (auth->mech != NULL)
02101 {
02102 _dbus_verbose ("%s: Trying mechanism %s\n",
02103 DBUS_AUTH_NAME (auth),
02104 auth->mech->mechanism);
02105
02106 if (!process_data (auth, &hex_response,
02107 auth->mech->server_data_func))
02108 goto failed;
02109 }
02110 else
02111 {
02112
02113 _dbus_verbose ("%s: Unsupported mechanism %s\n",
02114 DBUS_AUTH_NAME (auth),
02115 _dbus_string_get_const_data (&mech));
02116
02117 if (!send_rejected (auth))
02118 goto failed;
02119 }
02120
02121 _dbus_string_free (&mech);
02122 _dbus_string_free (&hex_response);
02123
02124 return TRUE;
02125
02126 failed:
02127 auth->mech = NULL;
02128 _dbus_string_free (&mech);
02129 _dbus_string_free (&hex_response);
02130 return FALSE;
02131 }
02132 }
02133
02134 static dbus_bool_t
02135 handle_server_state_waiting_for_auth (DBusAuth *auth,
02136 DBusAuthCommand command,
02137 const DBusString *args)
02138 {
02139 switch (command)
02140 {
02141 case DBUS_AUTH_COMMAND_AUTH:
02142 return handle_auth (auth, args);
02143
02144 case DBUS_AUTH_COMMAND_CANCEL:
02145 case DBUS_AUTH_COMMAND_DATA:
02146 return send_error (auth, "Not currently in an auth conversation");
02147
02148 case DBUS_AUTH_COMMAND_BEGIN:
02149 goto_state (auth, &common_state_need_disconnect);
02150 return TRUE;
02151
02152 case DBUS_AUTH_COMMAND_ERROR:
02153 if (_dbus_credentials_get_unix_sid(auth->authorized_identity) > 0) {
02154 goto_state (auth, &common_state_need_disconnect);
02155 return TRUE;
02156 } else {
02157 return send_cancel (auth);
02158 };
02159 case DBUS_AUTH_COMMAND_REJECTED:
02160 case DBUS_AUTH_COMMAND_OK:
02161 case DBUS_AUTH_COMMAND_UNKNOWN:
02162 default:
02163 return send_error (auth, "Unknown command");
02164 }
02165 }
02166
02167 static dbus_bool_t
02168 handle_server_state_waiting_for_data (DBusAuth *auth,
02169 DBusAuthCommand command,
02170 const DBusString *args)
02171 {
02172 switch (command)
02173 {
02174 case DBUS_AUTH_COMMAND_AUTH:
02175 return send_error (auth, "Sent AUTH while another AUTH in progress");
02176
02177 case DBUS_AUTH_COMMAND_CANCEL:
02178 case DBUS_AUTH_COMMAND_ERROR:
02179 return send_rejected (auth);
02180
02181 case DBUS_AUTH_COMMAND_DATA:
02182 return process_data (auth, args, auth->mech->server_data_func);
02183
02184 case DBUS_AUTH_COMMAND_BEGIN:
02185 goto_state (auth, &common_state_need_disconnect);
02186 return TRUE;
02187
02188 case DBUS_AUTH_COMMAND_REJECTED:
02189 case DBUS_AUTH_COMMAND_OK:
02190 case DBUS_AUTH_COMMAND_UNKNOWN:
02191 default:
02192 return send_error (auth, "Unknown command");
02193 }
02194 }
02195
02196 static dbus_bool_t
02197 handle_server_state_waiting_for_begin (DBusAuth *auth,
02198 DBusAuthCommand command,
02199 const DBusString *args)
02200 {
02201 switch (command)
02202 {
02203 case DBUS_AUTH_COMMAND_AUTH:
02204 return send_error (auth, "Sent AUTH while expecting BEGIN");
02205
02206 case DBUS_AUTH_COMMAND_DATA:
02207 return send_error (auth, "Sent DATA while expecting BEGIN");
02208
02209 case DBUS_AUTH_COMMAND_BEGIN:
02210 goto_state (auth, &common_state_authenticated);
02211 return TRUE;
02212
02213 case DBUS_AUTH_COMMAND_REJECTED:
02214 case DBUS_AUTH_COMMAND_OK:
02215 case DBUS_AUTH_COMMAND_UNKNOWN:
02216 default:
02217 return send_error (auth, "Unknown command");
02218
02219 case DBUS_AUTH_COMMAND_CANCEL:
02220 case DBUS_AUTH_COMMAND_ERROR:
02221 return send_rejected (auth);
02222 }
02223 }
02224
02225
02226 static dbus_bool_t
02227 get_word (const DBusString *str,
02228 int *start,
02229 DBusString *word)
02230 {
02231 int i;
02232
02233 _dbus_string_skip_blank (str, *start, start);
02234 _dbus_string_find_blank (str, *start, &i);
02235
02236 if (i > *start)
02237 {
02238 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0))
02239 return FALSE;
02240
02241 *start = i;
02242 }
02243
02244 return TRUE;
02245 }
02246
02247 static dbus_bool_t
02248 record_mechanisms (DBusAuth *auth,
02249 const DBusString *args)
02250 {
02251 int next;
02252 int len;
02253
02254 if (auth->already_got_mechanisms)
02255 return TRUE;
02256
02257 len = _dbus_string_get_length (args);
02258
02259 next = 0;
02260 while (next < len)
02261 {
02262 DBusString m;
02263 const DBusAuthMechanismHandler *mech;
02264
02265 if (!_dbus_string_init (&m))
02266 goto nomem;
02267
02268 if (!get_word (args, &next, &m))
02269 {
02270 _dbus_string_free (&m);
02271 goto nomem;
02272 }
02273
02274 mech = find_mech (&m, auth->allowed_mechs);
02275
02276 if (mech != NULL)
02277 {
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287 if (mech != &all_mechanisms[0])
02288 {
02289 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n",
02290 DBUS_AUTH_NAME (auth), mech->mechanism);
02291
02292 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
02293 (void*) mech))
02294 {
02295 _dbus_string_free (&m);
02296 goto nomem;
02297 }
02298 }
02299 else
02300 {
02301 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n",
02302 DBUS_AUTH_NAME (auth), mech->mechanism);
02303 }
02304 }
02305 else
02306 {
02307 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n",
02308 DBUS_AUTH_NAME (auth),
02309 _dbus_string_get_const_data (&m));
02310 }
02311
02312 _dbus_string_free (&m);
02313 }
02314
02315 auth->already_got_mechanisms = TRUE;
02316
02317 return TRUE;
02318
02319 nomem:
02320 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02321
02322 return FALSE;
02323 }
02324
02325 static dbus_bool_t
02326 process_rejected (DBusAuth *auth, const DBusString *args)
02327 {
02328 const DBusAuthMechanismHandler *mech;
02329 DBusAuthClient *client;
02330
02331 client = DBUS_AUTH_CLIENT (auth);
02332
02333 if (!auth->already_got_mechanisms)
02334 {
02335 if (!record_mechanisms (auth, args))
02336 return FALSE;
02337 }
02338
02339 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL)
02340 {
02341 mech = client->mechs_to_try->data;
02342
02343 if (!send_auth (auth, mech))
02344 return FALSE;
02345
02346 _dbus_list_pop_first (&client->mechs_to_try);
02347
02348 _dbus_verbose ("%s: Trying mechanism %s\n",
02349 DBUS_AUTH_NAME (auth),
02350 mech->mechanism);
02351 }
02352 else
02353 {
02354
02355 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n",
02356 DBUS_AUTH_NAME (auth));
02357 goto_state (auth, &common_state_need_disconnect);
02358 }
02359
02360 return TRUE;
02361 }
02362
02363
02364 static dbus_bool_t
02365 handle_client_state_waiting_for_data (DBusAuth *auth,
02366 DBusAuthCommand command,
02367 const DBusString *args)
02368 {
02369 _dbus_assert (auth->mech != NULL);
02370
02371 switch (command)
02372 {
02373 case DBUS_AUTH_COMMAND_DATA:
02374 return process_data (auth, args, auth->mech->client_data_func);
02375
02376 case DBUS_AUTH_COMMAND_REJECTED:
02377 return process_rejected (auth, args);
02378
02379 case DBUS_AUTH_COMMAND_OK:
02380 return send_begin (auth, args);
02381
02382 case DBUS_AUTH_COMMAND_ERROR:
02383 return send_cancel (auth);
02384
02385 case DBUS_AUTH_COMMAND_AUTH:
02386 case DBUS_AUTH_COMMAND_CANCEL:
02387 case DBUS_AUTH_COMMAND_BEGIN:
02388 case DBUS_AUTH_COMMAND_UNKNOWN:
02389 default:
02390 return send_error (auth, "Unknown command");
02391 }
02392 }
02393
02394 static dbus_bool_t
02395 handle_client_state_waiting_for_ok (DBusAuth *auth,
02396 DBusAuthCommand command,
02397 const DBusString *args)
02398 {
02399 switch (command)
02400 {
02401 case DBUS_AUTH_COMMAND_REJECTED:
02402 return process_rejected (auth, args);
02403
02404 case DBUS_AUTH_COMMAND_OK:
02405 return send_begin (auth, args);
02406
02407 case DBUS_AUTH_COMMAND_DATA:
02408 case DBUS_AUTH_COMMAND_ERROR:
02409 return send_cancel (auth);
02410
02411 case DBUS_AUTH_COMMAND_AUTH:
02412 case DBUS_AUTH_COMMAND_CANCEL:
02413 case DBUS_AUTH_COMMAND_BEGIN:
02414 case DBUS_AUTH_COMMAND_UNKNOWN:
02415 default:
02416 return send_error (auth, "Unknown command");
02417 }
02418 }
02419
02420 static dbus_bool_t
02421 handle_client_state_waiting_for_reject (DBusAuth *auth,
02422 DBusAuthCommand command,
02423 const DBusString *args)
02424 {
02425 switch (command)
02426 {
02427 case DBUS_AUTH_COMMAND_REJECTED:
02428 return process_rejected (auth, args);
02429
02430 case DBUS_AUTH_COMMAND_AUTH:
02431 case DBUS_AUTH_COMMAND_CANCEL:
02432 case DBUS_AUTH_COMMAND_DATA:
02433 case DBUS_AUTH_COMMAND_BEGIN:
02434 case DBUS_AUTH_COMMAND_OK:
02435 case DBUS_AUTH_COMMAND_ERROR:
02436 case DBUS_AUTH_COMMAND_UNKNOWN:
02437 default:
02438 goto_state (auth, &common_state_need_disconnect);
02439 return TRUE;
02440 }
02441 }
02442
02446 typedef struct {
02447 const char *name;
02448 DBusAuthCommand command;
02449 } DBusAuthCommandName;
02450
02451 static const DBusAuthCommandName auth_command_names[] = {
02452 { "AUTH", DBUS_AUTH_COMMAND_AUTH },
02453 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL },
02454 { "DATA", DBUS_AUTH_COMMAND_DATA },
02455 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN },
02456 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED },
02457 { "OK", DBUS_AUTH_COMMAND_OK },
02458 { "ERROR", DBUS_AUTH_COMMAND_ERROR }
02459 };
02460
02461 static DBusAuthCommand
02462 lookup_command_from_name (DBusString *command)
02463 {
02464 int i;
02465
02466 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++)
02467 {
02468 if (_dbus_string_equal_c_str (command,
02469 auth_command_names[i].name))
02470 return auth_command_names[i].command;
02471 }
02472
02473 return DBUS_AUTH_COMMAND_UNKNOWN;
02474 }
02475
02476 static void
02477 goto_state (DBusAuth *auth,
02478 const DBusAuthStateData *state)
02479 {
02480 _dbus_verbose ("%s: going from state %s to state %s\n",
02481 DBUS_AUTH_NAME (auth),
02482 auth->state->name,
02483 state->name);
02484
02485 auth->state = state;
02486 }
02487
02488
02489 static dbus_bool_t
02490 process_command (DBusAuth *auth)
02491 {
02492 DBusAuthCommand command;
02493 DBusString line;
02494 DBusString args;
02495 int eol;
02496 int i, j;
02497 dbus_bool_t retval;
02498 const char *msg_err;
02499 int prefix_len = strlen (NEXENTA_ERROR_PREFIX);
02500 int err_shift = 0;
02501
02502
02503
02504 retval = FALSE;
02505
02506 eol = 0;
02507 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol))
02508 return FALSE;
02509
02510 if (!_dbus_string_init (&line))
02511 {
02512 auth->needed_memory = TRUE;
02513 return FALSE;
02514 }
02515
02516 if (!_dbus_string_init (&args))
02517 {
02518 _dbus_string_free (&line);
02519 auth->needed_memory = TRUE;
02520 return FALSE;
02521 }
02522
02523 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0))
02524 goto out;
02525
02526 if (!_dbus_string_validate_ascii (&line, 0,
02527 _dbus_string_get_length (&line)))
02528 {
02529 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n",
02530 DBUS_AUTH_NAME (auth));
02531 if (!send_error (auth, "Command contained non-ASCII"))
02532 goto out;
02533 else
02534 goto next_command;
02535 }
02536
02537 _dbus_verbose ("%s: got command \"%s\"\n",
02538 DBUS_AUTH_NAME (auth),
02539 _dbus_string_get_const_data (&line));
02540
02541 _dbus_string_find_blank (&line, 0, &i);
02542 _dbus_string_skip_blank (&line, i, &j);
02543
02544 if (j > i)
02545 _dbus_string_delete (&line, i, j - i);
02546
02547 if (!_dbus_string_move (&line, i, &args, 0))
02548 goto out;
02549
02550
02551
02552
02553
02554 command = lookup_command_from_name (&line);
02555 if (command == DBUS_AUTH_COMMAND_ERROR) {
02556 msg_err = _dbus_string_get_const_data (&args);
02557 if (msg_err && msg_err[0] == '\"')
02558 err_shift = 1;
02559 if (msg_err && strncmp (msg_err + err_shift, NEXENTA_ERROR_PREFIX, prefix_len) == 0) {
02560 const char *num = msg_err + prefix_len;
02561 int error = atoi (num);
02562 _nexenta_log (" error = %d", error);
02563 _dbus_credentials_add_unix_sid(auth->authorized_identity, error);
02564 };
02565 };
02566 if (!(* auth->state->handler) (auth, command, &args))
02567 goto out;
02568
02569 next_command:
02570
02571
02572
02573
02574
02575 _dbus_string_delete (&auth->incoming, 0, eol);
02576
02577
02578 _dbus_string_delete (&auth->incoming, 0, 2);
02579
02580 retval = TRUE;
02581
02582 out:
02583 _dbus_string_free (&args);
02584 _dbus_string_free (&line);
02585
02586 if (!retval)
02587 auth->needed_memory = TRUE;
02588 else
02589 auth->needed_memory = FALSE;
02590
02591 return retval;
02592 }
02593
02594
02609 DBusAuth*
02610 _dbus_auth_server_new (const DBusString *guid)
02611 {
02612 DBusAuth *auth;
02613 DBusAuthServer *server_auth;
02614 DBusString guid_copy;
02615
02616 if (!_dbus_string_init (&guid_copy))
02617 return NULL;
02618
02619 if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
02620 {
02621 _dbus_string_free (&guid_copy);
02622 return NULL;
02623 }
02624
02625 auth = _dbus_auth_new (sizeof (DBusAuthServer));
02626 if (auth == NULL)
02627 {
02628 _dbus_string_free (&guid_copy);
02629 return NULL;
02630 }
02631
02632 auth->side = auth_side_server;
02633 auth->state = &server_state_waiting_for_auth;
02634
02635 server_auth = DBUS_AUTH_SERVER (auth);
02636
02637 server_auth->guid = guid_copy;
02638
02639
02640
02641
02642 server_auth->failures = 0;
02643 server_auth->max_failures = 6;
02644
02645 return auth;
02646 }
02647
02655 DBusAuth*
02656 _dbus_auth_client_new (void)
02657 {
02658 DBusAuth *auth;
02659 DBusString guid_str;
02660
02661 if (!_dbus_string_init (&guid_str))
02662 return NULL;
02663
02664 auth = _dbus_auth_new (sizeof (DBusAuthClient));
02665 if (auth == NULL)
02666 {
02667 _dbus_string_free (&guid_str);
02668 return NULL;
02669 }
02670
02671 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;
02672
02673 auth->side = auth_side_client;
02674 auth->state = &client_state_need_send_auth;
02675
02676
02677
02678 if (!send_auth (auth, &all_mechanisms[0]))
02679 {
02680 _dbus_auth_unref (auth);
02681 return NULL;
02682 }
02683
02684 return auth;
02685 }
02686
02693 DBusAuth *
02694 _dbus_auth_ref (DBusAuth *auth)
02695 {
02696 _dbus_assert (auth != NULL);
02697
02698 auth->refcount += 1;
02699
02700 return auth;
02701 }
02702
02708 void
02709 _dbus_auth_unref (DBusAuth *auth)
02710 {
02711 _dbus_assert (auth != NULL);
02712 _dbus_assert (auth->refcount > 0);
02713
02714 auth->refcount -= 1;
02715 if (auth->refcount == 0)
02716 {
02717 shutdown_mech (auth);
02718
02719 if (DBUS_AUTH_IS_CLIENT (auth))
02720 {
02721 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
02722 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02723 }
02724 else
02725 {
02726 _dbus_assert (DBUS_AUTH_IS_SERVER (auth));
02727
02728 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid);
02729 }
02730
02731 if (auth->keyring)
02732 _dbus_keyring_unref (auth->keyring);
02733
02734 _dbus_string_free (&auth->context);
02735 _dbus_string_free (&auth->challenge);
02736 _dbus_string_free (&auth->identity);
02737 _dbus_string_free (&auth->incoming);
02738 _dbus_string_free (&auth->outgoing);
02739
02740 dbus_free_string_array (auth->allowed_mechs);
02741
02742 _dbus_credentials_unref (auth->credentials);
02743 _dbus_credentials_unref (auth->authorized_identity);
02744 _dbus_credentials_unref (auth->desired_identity);
02745
02746 dbus_free (auth);
02747 }
02748 }
02749
02758 dbus_bool_t
02759 _dbus_auth_set_mechanisms (DBusAuth *auth,
02760 const char **mechanisms)
02761 {
02762 char **copy;
02763
02764 if (mechanisms != NULL)
02765 {
02766 copy = _dbus_dup_string_array (mechanisms);
02767 if (copy == NULL)
02768 return FALSE;
02769 }
02770 else
02771 copy = NULL;
02772
02773 dbus_free_string_array (auth->allowed_mechs);
02774
02775 auth->allowed_mechs = copy;
02776
02777 return TRUE;
02778 }
02779
02784 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02785
02793 DBusAuthState
02794 _dbus_auth_do_work (DBusAuth *auth)
02795 {
02796 auth->needed_memory = FALSE;
02797
02798
02799 #define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02800
02801 do
02802 {
02803 if (DBUS_AUTH_IN_END_STATE (auth))
02804 break;
02805
02806 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER ||
02807 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER)
02808 {
02809 goto_state (auth, &common_state_need_disconnect);
02810 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n",
02811 DBUS_AUTH_NAME (auth));
02812 break;
02813 }
02814 }
02815 while (process_command (auth));
02816
02817 if (auth->needed_memory)
02818 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02819 else if (_dbus_string_get_length (&auth->outgoing) > 0)
02820 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02821 else if (auth->state == &common_state_need_disconnect)
02822 return DBUS_AUTH_STATE_NEED_DISCONNECT;
02823 else if (auth->state == &common_state_authenticated)
02824 return DBUS_AUTH_STATE_AUTHENTICATED;
02825 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02826 }
02827
02837 dbus_bool_t
02838 _dbus_auth_get_bytes_to_send (DBusAuth *auth,
02839 const DBusString **str)
02840 {
02841 _dbus_assert (auth != NULL);
02842 _dbus_assert (str != NULL);
02843
02844 *str = NULL;
02845
02846 if (_dbus_string_get_length (&auth->outgoing) == 0)
02847 return FALSE;
02848
02849 *str = &auth->outgoing;
02850
02851 return TRUE;
02852 }
02853
02862 void
02863 _dbus_auth_bytes_sent (DBusAuth *auth,
02864 int bytes_sent)
02865 {
02866 _dbus_verbose ("%s: Sent %d bytes of: %s\n",
02867 DBUS_AUTH_NAME (auth),
02868 bytes_sent,
02869 _dbus_string_get_const_data (&auth->outgoing));
02870
02871 _dbus_string_delete (&auth->outgoing,
02872 0, bytes_sent);
02873 }
02874
02882 void
02883 _dbus_auth_get_buffer (DBusAuth *auth,
02884 DBusString **buffer)
02885 {
02886 _dbus_assert (auth != NULL);
02887 _dbus_assert (!auth->buffer_outstanding);
02888
02889 *buffer = &auth->incoming;
02890
02891 auth->buffer_outstanding = TRUE;
02892 }
02893
02901 void
02902 _dbus_auth_return_buffer (DBusAuth *auth,
02903 DBusString *buffer,
02904 int bytes_read)
02905 {
02906 _dbus_assert (buffer == &auth->incoming);
02907 _dbus_assert (auth->buffer_outstanding);
02908
02909 auth->buffer_outstanding = FALSE;
02910 }
02911
02921 void
02922 _dbus_auth_get_unused_bytes (DBusAuth *auth,
02923 const DBusString **str)
02924 {
02925 if (!DBUS_AUTH_IN_END_STATE (auth))
02926 return;
02927
02928 *str = &auth->incoming;
02929 }
02930
02931
02938 void
02939 _dbus_auth_delete_unused_bytes (DBusAuth *auth)
02940 {
02941 if (!DBUS_AUTH_IN_END_STATE (auth))
02942 return;
02943
02944 _dbus_string_set_length (&auth->incoming, 0);
02945 }
02946
02955 dbus_bool_t
02956 _dbus_auth_needs_encoding (DBusAuth *auth)
02957 {
02958 if (auth->state != &common_state_authenticated)
02959 return FALSE;
02960
02961 if (auth->mech != NULL)
02962 {
02963 if (DBUS_AUTH_IS_CLIENT (auth))
02964 return auth->mech->client_encode_func != NULL;
02965 else
02966 return auth->mech->server_encode_func != NULL;
02967 }
02968 else
02969 return FALSE;
02970 }
02971
02982 dbus_bool_t
02983 _dbus_auth_encode_data (DBusAuth *auth,
02984 const DBusString *plaintext,
02985 DBusString *encoded)
02986 {
02987 _dbus_assert (plaintext != encoded);
02988
02989 if (auth->state != &common_state_authenticated)
02990 return FALSE;
02991
02992 if (_dbus_auth_needs_encoding (auth))
02993 {
02994 if (DBUS_AUTH_IS_CLIENT (auth))
02995 return (* auth->mech->client_encode_func) (auth, plaintext, encoded);
02996 else
02997 return (* auth->mech->server_encode_func) (auth, plaintext, encoded);
02998 }
02999 else
03000 {
03001 return _dbus_string_copy (plaintext, 0, encoded,
03002 _dbus_string_get_length (encoded));
03003 }
03004 }
03005
03014 dbus_bool_t
03015 _dbus_auth_needs_decoding (DBusAuth *auth)
03016 {
03017 if (auth->state != &common_state_authenticated)
03018 return FALSE;
03019
03020 if (auth->mech != NULL)
03021 {
03022 if (DBUS_AUTH_IS_CLIENT (auth))
03023 return auth->mech->client_decode_func != NULL;
03024 else
03025 return auth->mech->server_decode_func != NULL;
03026 }
03027 else
03028 return FALSE;
03029 }
03030
03031
03045 dbus_bool_t
03046 _dbus_auth_decode_data (DBusAuth *auth,
03047 const DBusString *encoded,
03048 DBusString *plaintext)
03049 {
03050 _dbus_assert (plaintext != encoded);
03051
03052 if (auth->state != &common_state_authenticated)
03053 return FALSE;
03054
03055 if (_dbus_auth_needs_decoding (auth))
03056 {
03057 if (DBUS_AUTH_IS_CLIENT (auth))
03058 return (* auth->mech->client_decode_func) (auth, encoded, plaintext);
03059 else
03060 return (* auth->mech->server_decode_func) (auth, encoded, plaintext);
03061 }
03062 else
03063 {
03064 return _dbus_string_copy (encoded, 0, plaintext,
03065 _dbus_string_get_length (plaintext));
03066 }
03067 }
03068
03077 dbus_bool_t
03078 _dbus_auth_set_credentials (DBusAuth *auth,
03079 DBusCredentials *credentials)
03080 {
03081 _dbus_credentials_clear (auth->credentials);
03082 return _dbus_credentials_add_credentials (auth->credentials,
03083 credentials);
03084 }
03085
03095 DBusCredentials*
03096 _dbus_auth_get_identity (DBusAuth *auth)
03097 {
03098 if (auth->state == &common_state_authenticated)
03099 {
03100 return auth->authorized_identity;
03101 }
03102 else
03103 {
03104
03105
03106
03107
03108 _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity));
03109 return auth->authorized_identity;
03110 }
03111 }
03112
03119 const char*
03120 _dbus_auth_get_guid_from_server (DBusAuth *auth)
03121 {
03122 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth));
03123
03124 if (auth->state == &common_state_authenticated)
03125 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server);
03126 else
03127 return NULL;
03128 }
03129
03138 dbus_bool_t
03139 _dbus_auth_set_context (DBusAuth *auth,
03140 const DBusString *context)
03141 {
03142 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context),
03143 &auth->context, 0, _dbus_string_get_length (context));
03144 }
03145
03148
03149
03150 int _dbus_auth_get_error (DBusAuth *auth)
03151 {
03152 return (auth)? _dbus_credentials_get_unix_sid(auth->authorized_identity) : 0;
03153 }
03154