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-userdb.h"
00030
#include "dbus-protocol.h"
00031
00072 typedef dbus_bool_t (*
DBusInitialResponseFunction) (
DBusAuth *auth,
00073
DBusString *response);
00074
00079 typedef dbus_bool_t (*
DBusAuthDataFunction) (
DBusAuth *auth,
00080
const DBusString *data);
00081
00085 typedef dbus_bool_t (*
DBusAuthEncodeFunction) (
DBusAuth *auth,
00086
const DBusString *data,
00087
DBusString *encoded);
00088
00092 typedef dbus_bool_t (*
DBusAuthDecodeFunction) (
DBusAuth *auth,
00093
const DBusString *data,
00094
DBusString *decoded);
00095
00099 typedef void (*
DBusAuthShutdownFunction) (
DBusAuth *auth);
00100
00104 typedef struct
00105
{
00106 const char *mechanism;
00107 DBusAuthDataFunction server_data_func;
00108 DBusAuthEncodeFunction server_encode_func;
00109 DBusAuthDecodeFunction server_decode_func;
00110 DBusAuthShutdownFunction server_shutdown_func;
00111 DBusInitialResponseFunction client_initial_response_func;
00112 DBusAuthDataFunction client_data_func;
00113 DBusAuthEncodeFunction client_encode_func;
00114 DBusAuthDecodeFunction client_decode_func;
00115 DBusAuthShutdownFunction client_shutdown_func;
00116 }
DBusAuthMechanismHandler;
00117
00121 typedef enum {
00122 DBUS_AUTH_COMMAND_AUTH,
00123 DBUS_AUTH_COMMAND_CANCEL,
00124 DBUS_AUTH_COMMAND_DATA,
00125 DBUS_AUTH_COMMAND_BEGIN,
00126 DBUS_AUTH_COMMAND_REJECTED,
00127 DBUS_AUTH_COMMAND_OK,
00128 DBUS_AUTH_COMMAND_ERROR,
00129 DBUS_AUTH_COMMAND_UNKNOWN
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;
00173 DBusCredentials authorized_identity;
00175 DBusCredentials desired_identity;
00177 DBusString context;
00178 DBusKeyring *
keyring;
00179 int cookie_id;
00180 DBusString challenge;
00182 char **
allowed_mechs;
00186 unsigned int needed_memory : 1;
00189 unsigned int already_got_mechanisms : 1;
00190 unsigned int already_asked_for_initial_response : 1;
00191 unsigned int buffer_outstanding : 1;
00192 };
00193
00197 typedef struct
00198
{
00199 DBusAuth base;
00201 DBusList *mechs_to_try;
00203 }
DBusAuthClient;
00204
00208 typedef struct
00209
{
00210 DBusAuth base;
00212 int failures;
00213 int max_failures;
00215 }
DBusAuthServer;
00216
00217
static void goto_state (
DBusAuth *auth,
00218
const DBusAuthStateData *new_state);
00219
static dbus_bool_t send_auth (
DBusAuth *auth,
00220
const DBusAuthMechanismHandler *mech);
00221
static dbus_bool_t send_data (
DBusAuth *auth,
00222
DBusString *data);
00223
static dbus_bool_t send_rejected (
DBusAuth *auth);
00224
static dbus_bool_t send_error (
DBusAuth *auth,
00225
const char *message);
00226
static dbus_bool_t send_ok (
DBusAuth *auth);
00227
static dbus_bool_t send_begin (
DBusAuth *auth);
00228
static dbus_bool_t send_cancel (
DBusAuth *auth);
00229
00234
static dbus_bool_t handle_server_state_waiting_for_auth (
DBusAuth *auth,
00235 DBusAuthCommand command,
00236
const DBusString *args);
00237
static dbus_bool_t handle_server_state_waiting_for_data (
DBusAuth *auth,
00238 DBusAuthCommand command,
00239
const DBusString *args);
00240
static dbus_bool_t handle_server_state_waiting_for_begin (
DBusAuth *auth,
00241 DBusAuthCommand command,
00242
const DBusString *args);
00243
00244
static const DBusAuthStateData server_state_waiting_for_auth = {
00245
"WaitingForAuth", handle_server_state_waiting_for_auth
00246 };
00247
static const DBusAuthStateData server_state_waiting_for_data = {
00248
"WaitingForData", handle_server_state_waiting_for_data
00249 };
00250
static const DBusAuthStateData server_state_waiting_for_begin = {
00251
"WaitingForBegin", handle_server_state_waiting_for_begin
00252 };
00253
00258
static dbus_bool_t handle_client_state_waiting_for_data (
DBusAuth *auth,
00259 DBusAuthCommand command,
00260
const DBusString *args);
00261
static dbus_bool_t handle_client_state_waiting_for_ok (
DBusAuth *auth,
00262 DBusAuthCommand command,
00263
const DBusString *args);
00264
static dbus_bool_t handle_client_state_waiting_for_reject (
DBusAuth *auth,
00265 DBusAuthCommand command,
00266
const DBusString *args);
00267
00268
static const DBusAuthStateData client_state_need_send_auth = {
00269
"NeedSendAuth",
NULL
00270 };
00271
static const DBusAuthStateData client_state_waiting_for_data = {
00272
"WaitingForData", handle_client_state_waiting_for_data
00273 };
00274
static const DBusAuthStateData client_state_waiting_for_ok = {
00275
"WaitingForOK", handle_client_state_waiting_for_ok
00276 };
00277
static const DBusAuthStateData client_state_waiting_for_reject = {
00278
"WaitingForReject", handle_client_state_waiting_for_reject
00279 };
00280
00285
static const DBusAuthStateData common_state_authenticated = {
00286
"Authenticated",
NULL
00287 };
00288
00289
static const DBusAuthStateData common_state_need_disconnect = {
00290
"NeedDisconnect",
NULL
00291 };
00292
00293
static const char auth_side_client[] =
"client";
00294
static const char auth_side_server[] =
"server";
00299 #define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server)
00300
00304 #define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client)
00305
00309 #define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth))
00310
00314 #define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth))
00315
00321 #define DBUS_AUTH_NAME(auth) ((auth)->side)
00322
00323
static DBusAuth*
00324 _dbus_auth_new (
int size)
00325 {
00326
DBusAuth *auth;
00327
00328 auth =
dbus_malloc0 (size);
00329
if (auth ==
NULL)
00330
return NULL;
00331
00332 auth->
refcount = 1;
00333
00334
_dbus_credentials_clear (&auth->
credentials);
00335
_dbus_credentials_clear (&auth->
authorized_identity);
00336
_dbus_credentials_clear (&auth->
desired_identity);
00337
00338 auth->
keyring =
NULL;
00339 auth->
cookie_id = -1;
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
if (!
_dbus_string_init (&auth->
incoming))
00350
goto enomem_0;
00351
00352
if (!
_dbus_string_init (&auth->
outgoing))
00353
goto enomem_1;
00354
00355
if (!
_dbus_string_init (&auth->
identity))
00356
goto enomem_2;
00357
00358
if (!
_dbus_string_init (&auth->
context))
00359
goto enomem_3;
00360
00361
if (!
_dbus_string_init (&auth->
challenge))
00362
goto enomem_4;
00363
00364
00365
if (!
_dbus_string_append (&auth->
context,
"org_freedesktop_general"))
00366
goto enomem_5;
00367
00368
return auth;
00369
00370 enomem_5:
00371
_dbus_string_free (&auth->
challenge);
00372 enomem_4:
00373
_dbus_string_free (&auth->
context);
00374 enomem_3:
00375
_dbus_string_free (&auth->
identity);
00376 enomem_2:
00377
_dbus_string_free (&auth->
outgoing);
00378 enomem_1:
00379
_dbus_string_free (&auth->
incoming);
00380 enomem_0:
00381
dbus_free (auth);
00382
return NULL;
00383 }
00384
00385
static void
00386 shutdown_mech (
DBusAuth *auth)
00387 {
00388
00389 auth->
already_asked_for_initial_response =
FALSE;
00390
_dbus_string_set_length (&auth->
identity, 0);
00391
00392
_dbus_credentials_clear (&auth->
authorized_identity);
00393
_dbus_credentials_clear (&auth->
desired_identity);
00394
00395
if (auth->
mech !=
NULL)
00396 {
00397 _dbus_verbose (
"%s: Shutting down mechanism %s\n",
00398 DBUS_AUTH_NAME (auth), auth->mech->mechanism);
00399
00400
if (
DBUS_AUTH_IS_CLIENT (auth))
00401 (* auth->
mech->
client_shutdown_func) (auth);
00402
else
00403 (* auth->
mech->
server_shutdown_func) (auth);
00404
00405 auth->
mech =
NULL;
00406 }
00407 }
00408
00409
00410
00411
00412
00413
static dbus_bool_t
00414 sha1_compute_hash (
DBusAuth *auth,
00415
int cookie_id,
00416
const DBusString *server_challenge,
00417
const DBusString *client_challenge,
00418
DBusString *hash)
00419 {
00420
DBusString cookie;
00421
DBusString to_hash;
00422
dbus_bool_t retval;
00423
00424
_dbus_assert (auth->
keyring != NULL);
00425
00426 retval =
FALSE;
00427
00428
if (!
_dbus_string_init (&cookie))
00429
return FALSE;
00430
00431
if (!
_dbus_keyring_get_hex_key (auth->
keyring, cookie_id,
00432 &cookie))
00433
goto out_0;
00434
00435
if (
_dbus_string_get_length (&cookie) == 0)
00436 {
00437 retval =
TRUE;
00438
goto out_0;
00439 }
00440
00441
if (!
_dbus_string_init (&to_hash))
00442
goto out_0;
00443
00444
if (!
_dbus_string_copy (server_challenge, 0,
00445 &to_hash, _dbus_string_get_length (&to_hash)))
00446
goto out_1;
00447
00448
if (!
_dbus_string_append (&to_hash,
":"))
00449
goto out_1;
00450
00451
if (!
_dbus_string_copy (client_challenge, 0,
00452 &to_hash, _dbus_string_get_length (&to_hash)))
00453
goto out_1;
00454
00455
if (!
_dbus_string_append (&to_hash,
":"))
00456
goto out_1;
00457
00458
if (!
_dbus_string_copy (&cookie, 0,
00459 &to_hash, _dbus_string_get_length (&to_hash)))
00460
goto out_1;
00461
00462
if (!
_dbus_sha_compute (&to_hash, hash))
00463
goto out_1;
00464
00465 retval =
TRUE;
00466
00467 out_1:
00468
_dbus_string_zero (&to_hash);
00469
_dbus_string_free (&to_hash);
00470 out_0:
00471
_dbus_string_zero (&cookie);
00472
_dbus_string_free (&cookie);
00473
return retval;
00474 }
00475
00480 #define N_CHALLENGE_BYTES (128/8)
00481
00482
static dbus_bool_t
00483 sha1_handle_first_client_response (
DBusAuth *auth,
00484
const DBusString *data)
00485 {
00486
00487
00488
00489
DBusString tmp;
00490
DBusString tmp2;
00491
dbus_bool_t retval;
00492
DBusError error;
00493
00494 retval =
FALSE;
00495
00496
_dbus_string_set_length (&auth->
challenge, 0);
00497
00498
if (
_dbus_string_get_length (data) > 0)
00499 {
00500
if (
_dbus_string_get_length (&auth->
identity) > 0)
00501 {
00502
00503 _dbus_verbose (
"%s: client tried to send auth identity, but we already have one\n",
00504
DBUS_AUTH_NAME (auth));
00505
return send_rejected (auth);
00506 }
00507
else
00508 {
00509
00510
if (!
_dbus_string_copy (data, 0, &auth->
identity, 0))
00511
return FALSE;
00512 }
00513 }
00514
00515
if (!
_dbus_credentials_from_username (data, &auth->
desired_identity))
00516 {
00517 _dbus_verbose (
"%s: Did not get a valid username from client\n",
00518
DBUS_AUTH_NAME (auth));
00519
return send_rejected (auth);
00520 }
00521
00522
if (!
_dbus_string_init (&tmp))
00523
return FALSE;
00524
00525
if (!
_dbus_string_init (&tmp2))
00526 {
00527
_dbus_string_free (&tmp);
00528
return FALSE;
00529 }
00530
00531
00532
00533
00534
00535
if (auth->
keyring &&
00536 !
_dbus_keyring_is_for_user (auth->
keyring,
00537 data))
00538 {
00539
_dbus_keyring_unref (auth->
keyring);
00540 auth->
keyring =
NULL;
00541 }
00542
00543
if (auth->
keyring ==
NULL)
00544 {
00545
DBusError error;
00546
00547
dbus_error_init (&error);
00548 auth->
keyring =
_dbus_keyring_new_homedir (data,
00549 &auth->
context,
00550 &error);
00551
00552
if (auth->
keyring ==
NULL)
00553 {
00554
if (
dbus_error_has_name (&error,
00555 DBUS_ERROR_NO_MEMORY))
00556 {
00557
dbus_error_free (&error);
00558
goto out;
00559 }
00560
else
00561 {
00562 _DBUS_ASSERT_ERROR_IS_SET (&error);
00563 _dbus_verbose (
"%s: Error loading keyring: %s\n",
00564
DBUS_AUTH_NAME (auth), error.
message);
00565
if (send_rejected (auth))
00566 retval =
TRUE;
00567
dbus_error_free (&error);
00568
goto out;
00569 }
00570 }
00571
else
00572 {
00573
_dbus_assert (!
dbus_error_is_set (&error));
00574 }
00575 }
00576
00577
_dbus_assert (auth->
keyring !=
NULL);
00578
00579
dbus_error_init (&error);
00580 auth->
cookie_id =
_dbus_keyring_get_best_key (auth->
keyring, &error);
00581
if (auth->
cookie_id < 0)
00582 {
00583 _DBUS_ASSERT_ERROR_IS_SET (&error);
00584 _dbus_verbose (
"%s: Could not get a cookie ID to send to client: %s\n",
00585
DBUS_AUTH_NAME (auth), error.
message);
00586
if (send_rejected (auth))
00587 retval =
TRUE;
00588
dbus_error_free (&error);
00589
goto out;
00590 }
00591
else
00592 {
00593
_dbus_assert (!
dbus_error_is_set (&error));
00594 }
00595
00596
if (!
_dbus_string_copy (&auth->
context, 0,
00597 &tmp2,
_dbus_string_get_length (&tmp2)))
00598
goto out;
00599
00600
if (!
_dbus_string_append (&tmp2,
" "))
00601
goto out;
00602
00603
if (!
_dbus_string_append_int (&tmp2, auth->
cookie_id))
00604
goto out;
00605
00606
if (!
_dbus_string_append (&tmp2,
" "))
00607
goto out;
00608
00609
if (!
_dbus_generate_random_bytes (&tmp,
N_CHALLENGE_BYTES))
00610
goto out;
00611
00612
_dbus_string_set_length (&auth->
challenge, 0);
00613
if (!
_dbus_string_hex_encode (&tmp, 0, &auth->
challenge, 0))
00614
goto out;
00615
00616
if (!
_dbus_string_hex_encode (&tmp, 0, &tmp2,
00617
_dbus_string_get_length (&tmp2)))
00618
goto out;
00619
00620
if (!send_data (auth, &tmp2))
00621
goto out;
00622
00623 goto_state (auth, &server_state_waiting_for_data);
00624 retval =
TRUE;
00625
00626 out:
00627
_dbus_string_zero (&tmp);
00628
_dbus_string_free (&tmp);
00629
_dbus_string_zero (&tmp2);
00630
_dbus_string_free (&tmp2);
00631
00632
return retval;
00633 }
00634
00635
static dbus_bool_t
00636 sha1_handle_second_client_response (
DBusAuth *auth,
00637
const DBusString *data)
00638 {
00639
00640
00641
00642
00643
00644
int i;
00645
DBusString client_challenge;
00646
DBusString client_hash;
00647
dbus_bool_t retval;
00648
DBusString correct_hash;
00649
00650 retval =
FALSE;
00651
00652
if (!
_dbus_string_find_blank (data, 0, &i))
00653 {
00654 _dbus_verbose (
"%s: no space separator in client response\n",
00655 DBUS_AUTH_NAME (auth));
00656
return send_rejected (auth);
00657 }
00658
00659
if (!
_dbus_string_init (&client_challenge))
00660
goto out_0;
00661
00662
if (!
_dbus_string_init (&client_hash))
00663
goto out_1;
00664
00665
if (!
_dbus_string_copy_len (data, 0, i, &client_challenge,
00666 0))
00667
goto out_2;
00668
00669
_dbus_string_skip_blank (data, i, &i);
00670
00671
if (!
_dbus_string_copy_len (data, i,
00672 _dbus_string_get_length (data) - i,
00673 &client_hash,
00674 0))
00675
goto out_2;
00676
00677
if (
_dbus_string_get_length (&client_challenge) == 0 ||
00678
_dbus_string_get_length (&client_hash) == 0)
00679 {
00680 _dbus_verbose (
"%s: zero-length client challenge or hash\n",
00681 DBUS_AUTH_NAME (auth));
00682
if (send_rejected (auth))
00683 retval =
TRUE;
00684
goto out_2;
00685 }
00686
00687
if (!
_dbus_string_init (&correct_hash))
00688
goto out_2;
00689
00690
if (!sha1_compute_hash (auth, auth->
cookie_id,
00691 &auth->
challenge,
00692 &client_challenge,
00693 &correct_hash))
00694
goto out_3;
00695
00696
00697
if (
_dbus_string_get_length (&correct_hash) == 0)
00698 {
00699
if (send_rejected (auth))
00700 retval =
TRUE;
00701
goto out_3;
00702 }
00703
00704
if (!
_dbus_string_equal (&client_hash, &correct_hash))
00705 {
00706
if (send_rejected (auth))
00707 retval =
TRUE;
00708
goto out_3;
00709 }
00710
00711
if (!send_ok (auth))
00712
goto out_3;
00713
00714 _dbus_verbose (
"%s: authenticated client with UID "DBUS_UID_FORMAT
" using DBUS_COOKIE_SHA1\n",
00715 DBUS_AUTH_NAME (auth), auth->desired_identity.uid);
00716
00717 auth->
authorized_identity = auth->
desired_identity;
00718 retval =
TRUE;
00719
00720 out_3:
00721
_dbus_string_zero (&correct_hash);
00722
_dbus_string_free (&correct_hash);
00723 out_2:
00724
_dbus_string_zero (&client_hash);
00725
_dbus_string_free (&client_hash);
00726 out_1:
00727
_dbus_string_free (&client_challenge);
00728 out_0:
00729
return retval;
00730 }
00731
00732
static dbus_bool_t
00733 handle_server_data_cookie_sha1_mech (
DBusAuth *auth,
00734
const DBusString *data)
00735 {
00736
if (auth->
cookie_id < 0)
00737
return sha1_handle_first_client_response (auth, data);
00738
else
00739
return sha1_handle_second_client_response (auth, data);
00740 }
00741
00742
static void
00743 handle_server_shutdown_cookie_sha1_mech (
DBusAuth *auth)
00744 {
00745 auth->
cookie_id = -1;
00746
_dbus_string_set_length (&auth->
challenge, 0);
00747 }
00748
00749
static dbus_bool_t
00750 handle_client_initial_response_cookie_sha1_mech (
DBusAuth *auth,
00751
DBusString *response)
00752 {
00753
const DBusString *username;
00754
dbus_bool_t retval;
00755
00756 retval =
FALSE;
00757
00758
if (!
_dbus_username_from_current_process (&username))
00759
goto out_0;
00760
00761
if (!
_dbus_string_hex_encode (username, 0,
00762 response,
00763 _dbus_string_get_length (response)))
00764
goto out_0;
00765
00766 retval =
TRUE;
00767
00768 out_0:
00769
return retval;
00770 }
00771
00772
static dbus_bool_t
00773 handle_client_data_cookie_sha1_mech (
DBusAuth *auth,
00774
const DBusString *data)
00775 {
00776
00777
00778
00779
00780
dbus_bool_t retval;
00781
DBusString context;
00782
DBusString cookie_id_str;
00783
DBusString server_challenge;
00784
DBusString client_challenge;
00785
DBusString correct_hash;
00786
DBusString tmp;
00787
int i, j;
00788
long val;
00789
00790 retval =
FALSE;
00791
00792
if (!
_dbus_string_find_blank (data, 0, &i))
00793 {
00794
if (send_error (auth,
00795
"Server did not send context/ID/challenge properly"))
00796 retval =
TRUE;
00797
goto out_0;
00798 }
00799
00800
if (!
_dbus_string_init (&context))
00801
goto out_0;
00802
00803
if (!
_dbus_string_copy_len (data, 0, i,
00804 &context, 0))
00805
goto out_1;
00806
00807
_dbus_string_skip_blank (data, i, &i);
00808
if (!
_dbus_string_find_blank (data, i, &j))
00809 {
00810
if (send_error (auth,
00811
"Server did not send context/ID/challenge properly"))
00812 retval =
TRUE;
00813
goto out_1;
00814 }
00815
00816
if (!
_dbus_string_init (&cookie_id_str))
00817
goto out_1;
00818
00819
if (!
_dbus_string_copy_len (data, i, j - i,
00820 &cookie_id_str, 0))
00821
goto out_2;
00822
00823
if (!
_dbus_string_init (&server_challenge))
00824
goto out_2;
00825
00826 i = j;
00827
_dbus_string_skip_blank (data, i, &i);
00828 j =
_dbus_string_get_length (data);
00829
00830
if (!
_dbus_string_copy_len (data, i, j - i,
00831 &server_challenge, 0))
00832
goto out_3;
00833
00834
if (!
_dbus_keyring_validate_context (&context))
00835 {
00836
if (send_error (auth,
"Server sent invalid cookie context"))
00837 retval =
TRUE;
00838
goto out_3;
00839 }
00840
00841
if (!
_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL))
00842 {
00843
if (send_error (auth,
"Could not parse cookie ID as an integer"))
00844 retval =
TRUE;
00845
goto out_3;
00846 }
00847
00848
if (
_dbus_string_get_length (&server_challenge) == 0)
00849 {
00850
if (send_error (auth,
"Empty server challenge string"))
00851 retval =
TRUE;
00852
goto out_3;
00853 }
00854
00855
if (auth->
keyring ==
NULL)
00856 {
00857
DBusError error;
00858
00859
dbus_error_init (&error);
00860 auth->
keyring =
_dbus_keyring_new_homedir (NULL,
00861 &context,
00862 &error);
00863
00864
if (auth->
keyring ==
NULL)
00865 {
00866
if (
dbus_error_has_name (&error,
00867 DBUS_ERROR_NO_MEMORY))
00868 {
00869
dbus_error_free (&error);
00870
goto out_3;
00871 }
00872
else
00873 {
00874 _DBUS_ASSERT_ERROR_IS_SET (&error);
00875
00876 _dbus_verbose (
"%s: Error loading keyring: %s\n",
00877 DBUS_AUTH_NAME (auth), error.
message);
00878
00879
if (send_error (auth,
"Could not load cookie file"))
00880 retval =
TRUE;
00881
00882
dbus_error_free (&error);
00883
goto out_3;
00884 }
00885 }
00886
else
00887 {
00888
_dbus_assert (!dbus_error_is_set (&error));
00889 }
00890 }
00891
00892
_dbus_assert (auth->
keyring != NULL);
00893
00894
if (!
_dbus_string_init (&tmp))
00895
goto out_3;
00896
00897
if (!
_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES))
00898
goto out_4;
00899
00900
if (!
_dbus_string_init (&client_challenge))
00901
goto out_4;
00902
00903
if (!
_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0))
00904
goto out_5;
00905
00906
if (!
_dbus_string_init (&correct_hash))
00907
goto out_5;
00908
00909
if (!sha1_compute_hash (auth, val,
00910 &server_challenge,
00911 &client_challenge,
00912 &correct_hash))
00913
goto out_6;
00914
00915
if (
_dbus_string_get_length (&correct_hash) == 0)
00916 {
00917
00918
if (send_error (auth,
"Don't have the requested cookie ID"))
00919 retval =
TRUE;
00920
goto out_6;
00921 }
00922
00923
_dbus_string_set_length (&tmp, 0);
00924
00925
if (!
_dbus_string_copy (&client_challenge, 0, &tmp,
00926 _dbus_string_get_length (&tmp)))
00927
goto out_6;
00928
00929
if (!
_dbus_string_append (&tmp,
" "))
00930
goto out_6;
00931
00932
if (!
_dbus_string_copy (&correct_hash, 0, &tmp,
00933 _dbus_string_get_length (&tmp)))
00934
goto out_6;
00935
00936
if (!send_data (auth, &tmp))
00937
goto out_6;
00938
00939 retval =
TRUE;
00940
00941 out_6:
00942
_dbus_string_zero (&correct_hash);
00943
_dbus_string_free (&correct_hash);
00944 out_5:
00945
_dbus_string_free (&client_challenge);
00946 out_4:
00947
_dbus_string_zero (&tmp);
00948
_dbus_string_free (&tmp);
00949 out_3:
00950
_dbus_string_free (&server_challenge);
00951 out_2:
00952
_dbus_string_free (&cookie_id_str);
00953 out_1:
00954
_dbus_string_free (&context);
00955 out_0:
00956
return retval;
00957 }
00958
00959
static void
00960 handle_client_shutdown_cookie_sha1_mech (
DBusAuth *auth)
00961 {
00962 auth->
cookie_id = -1;
00963
_dbus_string_set_length (&auth->
challenge, 0);
00964 }
00965
00966
static dbus_bool_t
00967 handle_server_data_external_mech (
DBusAuth *auth,
00968
const DBusString *data)
00969 {
00970
if (auth->
credentials.
uid == DBUS_UID_UNSET)
00971 {
00972 _dbus_verbose (
"%s: no credentials, mechanism EXTERNAL can't authenticate\n",
00973 DBUS_AUTH_NAME (auth));
00974
return send_rejected (auth);
00975 }
00976
00977
if (
_dbus_string_get_length (data) > 0)
00978 {
00979
if (
_dbus_string_get_length (&auth->
identity) > 0)
00980 {
00981
00982 _dbus_verbose (
"%s: client tried to send auth identity, but we already have one\n",
00983 DBUS_AUTH_NAME (auth));
00984
return send_rejected (auth);
00985 }
00986
else
00987 {
00988
00989
if (!
_dbus_string_copy (data, 0, &auth->
identity, 0))
00990
return FALSE;
00991 }
00992 }
00993
00994
00995
if (
_dbus_string_get_length (&auth->
identity) == 0 &&
00996 !auth->
already_asked_for_initial_response)
00997 {
00998
if (send_data (auth, NULL))
00999 {
01000 _dbus_verbose (
"%s: sending empty challenge asking client for auth identity\n",
01001 DBUS_AUTH_NAME (auth));
01002 auth->
already_asked_for_initial_response =
TRUE;
01003
return TRUE;
01004 }
01005
else
01006
return FALSE;
01007 }
01008
01009
_dbus_credentials_clear (&auth->
desired_identity);
01010
01011
01012
01013
01014
01015
01016
if (
_dbus_string_get_length (&auth->
identity) == 0)
01017 {
01018 auth->
desired_identity.
uid = auth->
credentials.
uid;
01019 }
01020
else
01021 {
01022
if (!
_dbus_uid_from_string (&auth->
identity,
01023 &auth->
desired_identity.
uid))
01024 {
01025 _dbus_verbose (
"%s: could not get credentials from uid string\n",
01026 DBUS_AUTH_NAME (auth));
01027
return send_rejected (auth);
01028 }
01029 }
01030
01031
if (auth->
desired_identity.
uid == DBUS_UID_UNSET)
01032 {
01033 _dbus_verbose (
"%s: desired user %s is no good\n",
01034 DBUS_AUTH_NAME (auth),
01035 _dbus_string_get_const_data (&auth->identity));
01036
return send_rejected (auth);
01037 }
01038
01039
if (
_dbus_credentials_match (&auth->
desired_identity,
01040 &auth->
credentials))
01041 {
01042
01043
if (!send_ok (auth))
01044
return FALSE;
01045
01046 _dbus_verbose (
"%s: authenticated client with UID "DBUS_UID_FORMAT
01047
" matching socket credentials UID "DBUS_UID_FORMAT
"\n",
01048 DBUS_AUTH_NAME (auth),
01049 auth->desired_identity.uid,
01050 auth->credentials.uid);
01051
01052 auth->
authorized_identity.
pid = auth->
credentials.
pid;
01053 auth->
authorized_identity.
uid = auth->
desired_identity.
uid;
01054
return TRUE;
01055 }
01056
else
01057 {
01058 _dbus_verbose (
"%s: credentials uid="DBUS_UID_FORMAT
01059
" gid="DBUS_GID_FORMAT
01060
" do not allow uid="DBUS_UID_FORMAT
01061
" gid="DBUS_GID_FORMAT
"\n",
01062 DBUS_AUTH_NAME (auth),
01063 auth->credentials.uid, auth->credentials.gid,
01064 auth->desired_identity.uid, auth->desired_identity.gid);
01065
return send_rejected (auth);
01066 }
01067 }
01068
01069
static void
01070 handle_server_shutdown_external_mech (
DBusAuth *auth)
01071 {
01072
01073 }
01074
01075
static dbus_bool_t
01076 handle_client_initial_response_external_mech (
DBusAuth *auth,
01077
DBusString *response)
01078 {
01079
01080
01081
01082
01083
01084
DBusString plaintext;
01085
01086
if (!
_dbus_string_init (&plaintext))
01087
return FALSE;
01088
01089
if (!
_dbus_string_append_uint (&plaintext,
01090 _dbus_getuid ()))
01091
goto failed;
01092
01093
if (!
_dbus_string_hex_encode (&plaintext, 0,
01094 response,
01095 _dbus_string_get_length (response)))
01096
goto failed;
01097
01098
_dbus_string_free (&plaintext);
01099
01100
return TRUE;
01101
01102 failed:
01103
_dbus_string_free (&plaintext);
01104
return FALSE;
01105 }
01106
01107
static dbus_bool_t
01108 handle_client_data_external_mech (
DBusAuth *auth,
01109
const DBusString *data)
01110 {
01111
01112
return TRUE;
01113 }
01114
01115
static void
01116 handle_client_shutdown_external_mech (
DBusAuth *auth)
01117 {
01118
01119 }
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
static const DBusAuthMechanismHandler
01131 all_mechanisms[] = {
01132 {
"EXTERNAL",
01133 handle_server_data_external_mech,
01134
NULL,
NULL,
01135 handle_server_shutdown_external_mech,
01136 handle_client_initial_response_external_mech,
01137 handle_client_data_external_mech,
01138
NULL,
NULL,
01139 handle_client_shutdown_external_mech },
01140 {
"DBUS_COOKIE_SHA1",
01141 handle_server_data_cookie_sha1_mech,
01142
NULL,
NULL,
01143 handle_server_shutdown_cookie_sha1_mech,
01144 handle_client_initial_response_cookie_sha1_mech,
01145 handle_client_data_cookie_sha1_mech,
01146
NULL,
NULL,
01147 handle_client_shutdown_cookie_sha1_mech },
01148 {
NULL,
NULL }
01149 };
01150
01151
static const DBusAuthMechanismHandler*
01152 find_mech (
const DBusString *name,
01153
char **allowed_mechs)
01154 {
01155
int i;
01156
01157
if (allowed_mechs !=
NULL &&
01158 !
_dbus_string_array_contains ((
const char**) allowed_mechs,
01159 _dbus_string_get_const_data (name)))
01160
return NULL;
01161
01162 i = 0;
01163
while (all_mechanisms[i].
mechanism !=
NULL)
01164 {
01165
if (
_dbus_string_equal_c_str (name,
01166 all_mechanisms[i].mechanism))
01167
01168
return &all_mechanisms[i];
01169
01170 ++i;
01171 }
01172
01173
return NULL;
01174 }
01175
01176
static dbus_bool_t
01177 send_auth (
DBusAuth *auth,
const DBusAuthMechanismHandler *mech)
01178 {
01179
DBusString auth_command;
01180
01181
if (!
_dbus_string_init (&auth_command))
01182
return FALSE;
01183
01184
if (!
_dbus_string_append (&auth_command,
01185
"AUTH "))
01186 {
01187
_dbus_string_free (&auth_command);
01188
return FALSE;
01189 }
01190
01191
if (!
_dbus_string_append (&auth_command,
01192 mech->
mechanism))
01193 {
01194
_dbus_string_free (&auth_command);
01195
return FALSE;
01196 }
01197
01198
if (mech->
client_initial_response_func !=
NULL)
01199 {
01200
if (!
_dbus_string_append (&auth_command,
" "))
01201 {
01202
_dbus_string_free (&auth_command);
01203
return FALSE;
01204 }
01205
01206
if (!(* mech->
client_initial_response_func) (auth, &auth_command))
01207 {
01208
_dbus_string_free (&auth_command);
01209
return FALSE;
01210 }
01211 }
01212
01213
if (!
_dbus_string_append (&auth_command,
01214
"\r\n"))
01215 {
01216
_dbus_string_free (&auth_command);
01217
return FALSE;
01218 }
01219
01220
if (!
_dbus_string_copy (&auth_command, 0,
01221 &auth->
outgoing,
01222
_dbus_string_get_length (&auth->
outgoing)))
01223 {
01224
_dbus_string_free (&auth_command);
01225
return FALSE;
01226 }
01227
01228
_dbus_string_free (&auth_command);
01229 shutdown_mech (auth);
01230 auth->
mech = mech;
01231 goto_state (auth, &client_state_waiting_for_data);
01232
01233
return TRUE;
01234 }
01235
01236
static dbus_bool_t
01237 send_data (
DBusAuth *auth,
DBusString *data)
01238 {
01239
int old_len;
01240
01241
if (data ==
NULL ||
_dbus_string_get_length (data) == 0)
01242
return _dbus_string_append (&auth->
outgoing,
"DATA\r\n");
01243
else
01244 {
01245 old_len =
_dbus_string_get_length (&auth->
outgoing);
01246
if (!
_dbus_string_append (&auth->
outgoing,
"DATA "))
01247
goto out;
01248
01249
if (!
_dbus_string_hex_encode (data, 0, &auth->
outgoing,
01250
_dbus_string_get_length (&auth->
outgoing)))
01251
goto out;
01252
01253
if (!
_dbus_string_append (&auth->
outgoing,
"\r\n"))
01254
goto out;
01255
01256
return TRUE;
01257
01258 out:
01259
_dbus_string_set_length (&auth->
outgoing, old_len);
01260
01261
return FALSE;
01262 }
01263 }
01264
01265
static dbus_bool_t
01266 send_rejected (
DBusAuth *auth)
01267 {
01268
DBusString command;
01269
DBusAuthServer *server_auth;
01270
int i;
01271
01272
if (!
_dbus_string_init (&command))
01273
return FALSE;
01274
01275
if (!
_dbus_string_append (&command,
01276
"REJECTED"))
01277
goto nomem;
01278
01279 i = 0;
01280
while (all_mechanisms[i].
mechanism !=
NULL)
01281 {
01282
if (!
_dbus_string_append (&command,
01283
" "))
01284
goto nomem;
01285
01286
if (!
_dbus_string_append (&command,
01287 all_mechanisms[i].mechanism))
01288
goto nomem;
01289
01290 ++i;
01291 }
01292
01293
if (!
_dbus_string_append (&command,
"\r\n"))
01294
goto nomem;
01295
01296
if (!
_dbus_string_copy (&command, 0, &auth->
outgoing,
01297
_dbus_string_get_length (&auth->
outgoing)))
01298
goto nomem;
01299
01300 shutdown_mech (auth);
01301
01302
_dbus_assert (DBUS_AUTH_IS_SERVER (auth));
01303 server_auth =
DBUS_AUTH_SERVER (auth);
01304 server_auth->
failures += 1;
01305
01306
if (server_auth->
failures >= server_auth->
max_failures)
01307 goto_state (auth, &common_state_need_disconnect);
01308
else
01309 goto_state (auth, &server_state_waiting_for_auth);
01310
01311
_dbus_string_free (&command);
01312
01313
return TRUE;
01314
01315 nomem:
01316
_dbus_string_free (&command);
01317
return FALSE;
01318 }
01319
01320
static dbus_bool_t
01321 send_error (
DBusAuth *auth,
const char *message)
01322 {
01323
return _dbus_string_append_printf (&auth->
outgoing,
01324
"ERROR \"%s\"\r\n", message);
01325 }
01326
01327
static dbus_bool_t
01328 send_ok (
DBusAuth *auth)
01329 {
01330
if (
_dbus_string_append (&auth->
outgoing,
"OK\r\n"))
01331 {
01332 goto_state (auth, &server_state_waiting_for_begin);
01333
return TRUE;
01334 }
01335
else
01336
return FALSE;
01337 }
01338
01339
static dbus_bool_t
01340 send_begin (
DBusAuth *auth)
01341 {
01342
if (
_dbus_string_append (&auth->
outgoing,
"BEGIN\r\n"))
01343 {
01344 goto_state (auth, &common_state_authenticated);
01345
return TRUE;
01346 }
01347
else
01348
return FALSE;
01349 }
01350
01351
static dbus_bool_t
01352 send_cancel (
DBusAuth *auth)
01353 {
01354
if (
_dbus_string_append (&auth->
outgoing,
"CANCEL\r\n"))
01355 {
01356 goto_state (auth, &client_state_waiting_for_reject);
01357
return TRUE;
01358 }
01359
else
01360
return FALSE;
01361 }
01362
01363
static dbus_bool_t
01364 process_data (
DBusAuth *auth,
01365
const DBusString *args,
01366 DBusAuthDataFunction data_func)
01367 {
01368
int end;
01369
DBusString decoded;
01370
01371
if (!
_dbus_string_init (&decoded))
01372
return FALSE;
01373
01374
if (!
_dbus_string_hex_decode (args, 0, &end, &decoded, 0))
01375 {
01376
_dbus_string_free (&decoded);
01377
return FALSE;
01378 }
01379
01380
if (
_dbus_string_get_length (args) != end)
01381 {
01382
_dbus_string_free (&decoded);
01383
if (!send_error (auth,
"Invalid hex encoding"))
01384
return FALSE;
01385
01386
return TRUE;
01387 }
01388
01389
#ifdef DBUS_ENABLE_VERBOSE_MODE
01390
if (
_dbus_string_validate_ascii (&decoded, 0,
01391 _dbus_string_get_length (&decoded)))
01392 _dbus_verbose (
"%s: data: '%s'\n",
01393 DBUS_AUTH_NAME (auth),
01394 _dbus_string_get_const_data (&decoded));
01395
#endif
01396
01397
if (!(* data_func) (auth, &decoded))
01398 {
01399
_dbus_string_free (&decoded);
01400
return FALSE;
01401 }
01402
01403
_dbus_string_free (&decoded);
01404
return TRUE;
01405 }
01406
01407
static dbus_bool_t
01408 handle_auth (
DBusAuth *auth,
const DBusString *args)
01409 {
01410
if (
_dbus_string_get_length (args) == 0)
01411 {
01412
01413
if (!send_rejected (auth))
01414
return FALSE;
01415
01416
return TRUE;
01417 }
01418
else
01419 {
01420
int i;
01421
DBusString mech;
01422
DBusString hex_response;
01423
01424
_dbus_string_find_blank (args, 0, &i);
01425
01426
if (!
_dbus_string_init (&mech))
01427
return FALSE;
01428
01429
if (!
_dbus_string_init (&hex_response))
01430 {
01431
_dbus_string_free (&mech);
01432
return FALSE;
01433 }
01434
01435
if (!
_dbus_string_copy_len (args, 0, i, &mech, 0))
01436
goto failed;
01437
01438
_dbus_string_skip_blank (args, i, &i);
01439
if (!
_dbus_string_copy (args, i, &hex_response, 0))
01440
goto failed;
01441
01442 auth->
mech = find_mech (&mech, auth->
allowed_mechs);
01443
if (auth->
mech !=
NULL)
01444 {
01445 _dbus_verbose (
"%s: Trying mechanism %s\n",
01446 DBUS_AUTH_NAME (auth),
01447 auth->mech->mechanism);
01448
01449
if (!process_data (auth, &hex_response,
01450 auth->
mech->
server_data_func))
01451
goto failed;
01452 }
01453
else
01454 {
01455
01456 _dbus_verbose (
"%s: Unsupported mechanism %s\n",
01457 DBUS_AUTH_NAME (auth),
01458 _dbus_string_get_const_data (&mech));
01459
01460
if (!send_rejected (auth))
01461
goto failed;
01462 }
01463
01464
_dbus_string_free (&mech);
01465
_dbus_string_free (&hex_response);
01466
01467
return TRUE;
01468
01469 failed:
01470 auth->
mech =
NULL;
01471
_dbus_string_free (&mech);
01472
_dbus_string_free (&hex_response);
01473
return FALSE;
01474 }
01475 }
01476
01477
static dbus_bool_t
01478 handle_server_state_waiting_for_auth (
DBusAuth *auth,
01479 DBusAuthCommand command,
01480
const DBusString *args)
01481 {
01482
switch (command)
01483 {
01484
case DBUS_AUTH_COMMAND_AUTH:
01485
return handle_auth (auth, args);
01486
01487
case DBUS_AUTH_COMMAND_CANCEL:
01488
case DBUS_AUTH_COMMAND_DATA:
01489
return send_error (auth,
"Not currently in an auth conversation");
01490
01491
case DBUS_AUTH_COMMAND_BEGIN:
01492 goto_state (auth, &common_state_need_disconnect);
01493
return TRUE;
01494
01495
case DBUS_AUTH_COMMAND_ERROR:
01496
return send_rejected (auth);
01497
01498
case DBUS_AUTH_COMMAND_REJECTED:
01499
case DBUS_AUTH_COMMAND_OK:
01500
case DBUS_AUTH_COMMAND_UNKNOWN:
01501
default:
01502
return send_error (auth,
"Unknown command");
01503 }
01504 }
01505
01506
static dbus_bool_t
01507 handle_server_state_waiting_for_data (
DBusAuth *auth,
01508 DBusAuthCommand command,
01509
const DBusString *args)
01510 {
01511
switch (command)
01512 {
01513
case DBUS_AUTH_COMMAND_AUTH:
01514
return send_error (auth,
"Sent AUTH while another AUTH in progress");
01515
01516
case DBUS_AUTH_COMMAND_CANCEL:
01517
case DBUS_AUTH_COMMAND_ERROR:
01518
return send_rejected (auth);
01519
01520
case DBUS_AUTH_COMMAND_DATA:
01521
return process_data (auth, args, auth->
mech->
server_data_func);
01522
01523
case DBUS_AUTH_COMMAND_BEGIN:
01524 goto_state (auth, &common_state_need_disconnect);
01525
return TRUE;
01526
01527
case DBUS_AUTH_COMMAND_REJECTED:
01528
case DBUS_AUTH_COMMAND_OK:
01529
case DBUS_AUTH_COMMAND_UNKNOWN:
01530
default:
01531
return send_error (auth,
"Unknown command");
01532 }
01533 }
01534
01535
static dbus_bool_t
01536 handle_server_state_waiting_for_begin (
DBusAuth *auth,
01537 DBusAuthCommand command,
01538
const DBusString *args)
01539 {
01540
switch (command)
01541 {
01542
case DBUS_AUTH_COMMAND_AUTH:
01543
return send_error (auth,
"Sent AUTH while expecting BEGIN");
01544
01545
case DBUS_AUTH_COMMAND_DATA:
01546
return send_error (auth,
"Sent DATA while expecting BEGIN");
01547
01548
case DBUS_AUTH_COMMAND_BEGIN:
01549 goto_state (auth, &common_state_authenticated);
01550
return TRUE;
01551
01552
case DBUS_AUTH_COMMAND_REJECTED:
01553
case DBUS_AUTH_COMMAND_OK:
01554
case DBUS_AUTH_COMMAND_UNKNOWN:
01555
default:
01556
return send_error (auth,
"Unknown command");
01557
01558
case DBUS_AUTH_COMMAND_CANCEL:
01559
case DBUS_AUTH_COMMAND_ERROR:
01560
return send_rejected (auth);
01561 }
01562 }
01563
01564
01565
static dbus_bool_t
01566 get_word (
const DBusString *str,
01567
int *start,
01568
DBusString *word)
01569 {
01570
int i;
01571
01572
_dbus_string_skip_blank (str, *start, start);
01573
_dbus_string_find_blank (str, *start, &i);
01574
01575
if (i > *start)
01576 {
01577
if (!
_dbus_string_copy_len (str, *start, i - *start, word, 0))
01578
return FALSE;
01579
01580 *start = i;
01581 }
01582
01583
return TRUE;
01584 }
01585
01586
static dbus_bool_t
01587 record_mechanisms (
DBusAuth *auth,
01588
const DBusString *args)
01589 {
01590
int next;
01591
int len;
01592
01593
if (auth->
already_got_mechanisms)
01594
return TRUE;
01595
01596 len =
_dbus_string_get_length (args);
01597
01598 next = 0;
01599
while (next < len)
01600 {
01601
DBusString m;
01602
const DBusAuthMechanismHandler *mech;
01603
01604
if (!
_dbus_string_init (&m))
01605
goto nomem;
01606
01607
if (!get_word (args, &next, &m))
01608 {
01609
_dbus_string_free (&m);
01610
goto nomem;
01611 }
01612
01613 mech = find_mech (&m, auth->
allowed_mechs);
01614
01615
if (mech !=
NULL)
01616 {
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626 _dbus_verbose (
"%s: Adding mechanism %s to list we will try\n",
01627 DBUS_AUTH_NAME (auth), mech->
mechanism);
01628
01629
if (!
_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try,
01630 (
void*) mech))
01631 {
01632
_dbus_string_free (&m);
01633
goto nomem;
01634 }
01635 }
01636
else
01637 {
01638 _dbus_verbose (
"%s: Server offered mechanism \"%s\" that we don't know how to use\n",
01639 DBUS_AUTH_NAME (auth),
01640 _dbus_string_get_const_data (&m));
01641 }
01642
01643
_dbus_string_free (&m);
01644 }
01645
01646 auth->
already_got_mechanisms =
TRUE;
01647
01648
return TRUE;
01649
01650 nomem:
01651
_dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try);
01652
01653
return FALSE;
01654 }
01655
01656
static dbus_bool_t
01657 process_rejected (
DBusAuth *auth,
const DBusString *args)
01658 {
01659
const DBusAuthMechanismHandler *mech;
01660
DBusAuthClient *client;
01661
01662 client =
DBUS_AUTH_CLIENT (auth);
01663
01664
if (!auth->
already_got_mechanisms)
01665 {
01666
if (!record_mechanisms (auth, args))
01667
return FALSE;
01668 }
01669
01670
if (
DBUS_AUTH_CLIENT (auth)->mechs_to_try !=
NULL)
01671 {
01672 mech = client->
mechs_to_try->
data;
01673
01674
if (!send_auth (auth, mech))
01675
return FALSE;
01676
01677
_dbus_list_pop_first (&client->
mechs_to_try);
01678
01679 _dbus_verbose (
"%s: Trying mechanism %s\n",
01680 DBUS_AUTH_NAME (auth),
01681 mech->
mechanism);
01682 }
01683
else
01684 {
01685
01686 _dbus_verbose (
"%s: Disconnecting because we are out of mechanisms to try using\n",
01687 DBUS_AUTH_NAME (auth));
01688 goto_state (auth, &common_state_need_disconnect);
01689 }
01690
01691
return TRUE;
01692 }
01693
01694
01695
static dbus_bool_t
01696 handle_client_state_waiting_for_data (
DBusAuth *auth,
01697 DBusAuthCommand command,
01698
const DBusString *args)
01699 {
01700
_dbus_assert (auth->
mech != NULL);
01701
01702
switch (command)
01703 {
01704
case DBUS_AUTH_COMMAND_DATA:
01705
return process_data (auth, args, auth->
mech->
client_data_func);
01706
01707
case DBUS_AUTH_COMMAND_REJECTED:
01708
return process_rejected (auth, args);
01709
01710
case DBUS_AUTH_COMMAND_OK:
01711
return send_begin (auth);
01712
01713
case DBUS_AUTH_COMMAND_ERROR:
01714
return send_cancel (auth);
01715
01716
case DBUS_AUTH_COMMAND_AUTH:
01717
case DBUS_AUTH_COMMAND_CANCEL:
01718
case DBUS_AUTH_COMMAND_BEGIN:
01719
case DBUS_AUTH_COMMAND_UNKNOWN:
01720
default:
01721
return send_error (auth,
"Unknown command");
01722 }
01723 }
01724
01725
static dbus_bool_t
01726 handle_client_state_waiting_for_ok (
DBusAuth *auth,
01727 DBusAuthCommand command,
01728
const DBusString *args)
01729 {
01730
switch (command)
01731 {
01732
case DBUS_AUTH_COMMAND_REJECTED:
01733
return process_rejected (auth, args);
01734
01735
case DBUS_AUTH_COMMAND_OK:
01736
return send_begin (auth);
01737
01738
case DBUS_AUTH_COMMAND_DATA:
01739
case DBUS_AUTH_COMMAND_ERROR:
01740
return send_cancel (auth);
01741
01742
case DBUS_AUTH_COMMAND_AUTH:
01743
case DBUS_AUTH_COMMAND_CANCEL:
01744
case DBUS_AUTH_COMMAND_BEGIN:
01745
case DBUS_AUTH_COMMAND_UNKNOWN:
01746
default:
01747
return send_error (auth,
"Unknown command");
01748 }
01749 }
01750
01751
static dbus_bool_t
01752 handle_client_state_waiting_for_reject (
DBusAuth *auth,
01753 DBusAuthCommand command,
01754
const DBusString *args)
01755 {
01756
switch (command)
01757 {
01758
case DBUS_AUTH_COMMAND_REJECTED:
01759
return process_rejected (auth, args);
01760
01761
case DBUS_AUTH_COMMAND_AUTH:
01762
case DBUS_AUTH_COMMAND_CANCEL:
01763
case DBUS_AUTH_COMMAND_DATA:
01764
case DBUS_AUTH_COMMAND_BEGIN:
01765
case DBUS_AUTH_COMMAND_OK:
01766
case DBUS_AUTH_COMMAND_ERROR:
01767
case DBUS_AUTH_COMMAND_UNKNOWN:
01768
default:
01769 goto_state (auth, &common_state_need_disconnect);
01770
return TRUE;
01771 }
01772 }
01773
01777 typedef struct {
01778 const char *name;
01779 DBusAuthCommand command;
01780 }
DBusAuthCommandName;
01781
01782
static DBusAuthCommandName auth_command_names[] = {
01783 {
"AUTH", DBUS_AUTH_COMMAND_AUTH },
01784 {
"CANCEL", DBUS_AUTH_COMMAND_CANCEL },
01785 {
"DATA", DBUS_AUTH_COMMAND_DATA },
01786 {
"BEGIN", DBUS_AUTH_COMMAND_BEGIN },
01787 {
"REJECTED", DBUS_AUTH_COMMAND_REJECTED },
01788 {
"OK", DBUS_AUTH_COMMAND_OK },
01789 {
"ERROR", DBUS_AUTH_COMMAND_ERROR }
01790 };
01791
01792
static DBusAuthCommand
01793 lookup_command_from_name (
DBusString *command)
01794 {
01795
int i;
01796
01797
for (i = 0; i <
_DBUS_N_ELEMENTS (auth_command_names); i++)
01798 {
01799
if (
_dbus_string_equal_c_str (command,
01800 auth_command_names[i].name))
01801
return auth_command_names[i].
command;
01802 }
01803
01804
return DBUS_AUTH_COMMAND_UNKNOWN;
01805 }
01806
01807
static void
01808 goto_state (
DBusAuth *auth,
const DBusAuthStateData *state)
01809 {
01810 _dbus_verbose (
"%s: going from state %s to state %s\n",
01811 DBUS_AUTH_NAME (auth),
01812 auth->state->name,
01813 state->
name);
01814
01815 auth->
state = state;
01816 }
01817
01818
01819
static dbus_bool_t
01820 process_command (
DBusAuth *auth)
01821 {
01822
DBusAuthCommand command;
01823
DBusString line;
01824
DBusString args;
01825
int eol;
01826
int i, j;
01827
dbus_bool_t retval;
01828
01829
01830
01831 retval =
FALSE;
01832
01833 eol = 0;
01834
if (!
_dbus_string_find (&auth->
incoming, 0,
"\r\n", &eol))
01835
return FALSE;
01836
01837
if (!
_dbus_string_init (&line))
01838 {
01839 auth->
needed_memory =
TRUE;
01840
return FALSE;
01841 }
01842
01843
if (!
_dbus_string_init (&args))
01844 {
01845
_dbus_string_free (&line);
01846 auth->
needed_memory =
TRUE;
01847
return FALSE;
01848 }
01849
01850
if (!
_dbus_string_copy_len (&auth->
incoming, 0, eol, &line, 0))
01851
goto out;
01852
01853
if (!
_dbus_string_validate_ascii (&line, 0,
01854 _dbus_string_get_length (&line)))
01855 {
01856 _dbus_verbose (
"%s: Command contained non-ASCII chars or embedded nul\n",
01857 DBUS_AUTH_NAME (auth));
01858
if (!send_error (auth,
"Command contained non-ASCII"))
01859
goto out;
01860
else
01861
goto next_command;
01862 }
01863
01864 _dbus_verbose (
"%s: got command \"%s\"\n",
01865 DBUS_AUTH_NAME (auth),
01866 _dbus_string_get_const_data (&line));
01867
01868
_dbus_string_find_blank (&line, 0, &i);
01869
_dbus_string_skip_blank (&line, i, &j);
01870
01871
if (j > i)
01872
_dbus_string_delete (&line, i, j - i);
01873
01874
if (!
_dbus_string_move (&line, i, &args, 0))
01875
goto out;
01876
01877 command = lookup_command_from_name (&line);
01878
if (!(* auth->state->handler) (auth, command, &args))
01879
goto out;
01880
01881 next_command:
01882
01883
01884
01885
01886
01887
_dbus_string_delete (&auth->incoming, 0, eol);
01888
01889
01890
_dbus_string_delete (&auth->incoming, 0, 2);
01891
01892 retval =
TRUE;
01893
01894 out:
01895
_dbus_string_free (&args);
01896
_dbus_string_free (&line);
01897
01898
if (!retval)
01899 auth->needed_memory =
TRUE;
01900
else
01901 auth->needed_memory =
FALSE;
01902
01903
return retval;
01904 }
01905
01906
01921
DBusAuth*
01922 _dbus_auth_server_new (
void)
01923 {
01924
DBusAuth *auth;
01925
DBusAuthServer *server_auth;
01926
01927 auth = _dbus_auth_new (
sizeof (
DBusAuthServer));
01928
if (auth ==
NULL)
01929
return NULL;
01930
01931 auth->
side = auth_side_server;
01932 auth->
state = &server_state_waiting_for_auth;
01933
01934 server_auth =
DBUS_AUTH_SERVER (auth);
01935
01936
01937
01938
01939 server_auth->
failures = 0;
01940 server_auth->
max_failures = 6;
01941
01942
return auth;
01943 }
01944
01952
DBusAuth*
01953 _dbus_auth_client_new (
void)
01954 {
01955
DBusAuth *auth;
01956
01957 auth = _dbus_auth_new (
sizeof (
DBusAuthClient));
01958
if (auth ==
NULL)
01959
return NULL;
01960
01961 auth->
side = auth_side_client;
01962 auth->
state = &client_state_need_send_auth;
01963
01964
01965
01966
if (!send_auth (auth, &all_mechanisms[0]))
01967 {
01968
_dbus_auth_unref (auth);
01969
return NULL;
01970 }
01971
01972
return auth;
01973 }
01974
01981
DBusAuth *
01982 _dbus_auth_ref (
DBusAuth *auth)
01983 {
01984
_dbus_assert (auth !=
NULL);
01985
01986 auth->
refcount += 1;
01987
01988
return auth;
01989 }
01990
01996
void
01997 _dbus_auth_unref (
DBusAuth *auth)
01998 {
01999
_dbus_assert (auth !=
NULL);
02000
_dbus_assert (auth->
refcount > 0);
02001
02002 auth->
refcount -= 1;
02003
if (auth->
refcount == 0)
02004 {
02005 shutdown_mech (auth);
02006
02007
if (
DBUS_AUTH_IS_CLIENT (auth))
02008 {
02009
_dbus_list_clear (&
DBUS_AUTH_CLIENT (auth)->mechs_to_try);
02010 }
02011
02012
if (auth->
keyring)
02013
_dbus_keyring_unref (auth->
keyring);
02014
02015
_dbus_string_free (&auth->
context);
02016
_dbus_string_free (&auth->
challenge);
02017
_dbus_string_free (&auth->
identity);
02018
_dbus_string_free (&auth->
incoming);
02019
_dbus_string_free (&auth->
outgoing);
02020
02021
dbus_free_string_array (auth->
allowed_mechs);
02022
02023
dbus_free (auth);
02024 }
02025 }
02026
02035
dbus_bool_t
02036 _dbus_auth_set_mechanisms (
DBusAuth *auth,
02037
const char **mechanisms)
02038 {
02039
char **copy;
02040
02041
if (mechanisms !=
NULL)
02042 {
02043 copy =
_dbus_dup_string_array (mechanisms);
02044
if (copy ==
NULL)
02045
return FALSE;
02046 }
02047
else
02048 copy =
NULL;
02049
02050
dbus_free_string_array (auth->
allowed_mechs);
02051
02052 auth->
allowed_mechs = copy;
02053
02054
return TRUE;
02055 }
02056
02061 #define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL)
02062
02070 DBusAuthState
02071 _dbus_auth_do_work (
DBusAuth *auth)
02072 {
02073 auth->
needed_memory =
FALSE;
02074
02075
02076
#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE)
02077
02078
do
02079 {
02080
if (
DBUS_AUTH_IN_END_STATE (auth))
02081
break;
02082
02083
if (
_dbus_string_get_length (&auth->
incoming) > MAX_BUFFER ||
02084
_dbus_string_get_length (&auth->
outgoing) > MAX_BUFFER)
02085 {
02086 goto_state (auth, &common_state_need_disconnect);
02087 _dbus_verbose (
"%s: Disconnecting due to excessive data buffered in auth phase\n",
02088
DBUS_AUTH_NAME (auth));
02089
break;
02090 }
02091 }
02092
while (process_command (auth));
02093
02094
if (auth->
needed_memory)
02095
return DBUS_AUTH_STATE_WAITING_FOR_MEMORY;
02096
else if (
_dbus_string_get_length (&auth->
outgoing) > 0)
02097
return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
02098
else if (auth->
state == &common_state_need_disconnect)
02099
return DBUS_AUTH_STATE_NEED_DISCONNECT;
02100
else if (auth->
state == &common_state_authenticated)
02101
return DBUS_AUTH_STATE_AUTHENTICATED;
02102
else return DBUS_AUTH_STATE_WAITING_FOR_INPUT;
02103 }
02104
02114
dbus_bool_t
02115 _dbus_auth_get_bytes_to_send (
DBusAuth *auth,
02116
const DBusString **str)
02117 {
02118
_dbus_assert (auth !=
NULL);
02119
_dbus_assert (str !=
NULL);
02120
02121 *str =
NULL;
02122
02123
if (
_dbus_string_get_length (&auth->
outgoing) == 0)
02124
return FALSE;
02125
02126 *str = &auth->
outgoing;
02127
02128
return TRUE;
02129 }
02130
02139
void
02140 _dbus_auth_bytes_sent (
DBusAuth *auth,
02141
int bytes_sent)
02142 {
02143 _dbus_verbose (
"%s: Sent %d bytes of: %s\n",
02144
DBUS_AUTH_NAME (auth),
02145 bytes_sent,
02146
_dbus_string_get_const_data (&auth->outgoing));
02147
02148
_dbus_string_delete (&auth->outgoing,
02149 0, bytes_sent);
02150 }
02151
02159
void
02160 _dbus_auth_get_buffer (
DBusAuth *auth,
02161
DBusString **buffer)
02162 {
02163
_dbus_assert (auth !=
NULL);
02164
_dbus_assert (!auth->
buffer_outstanding);
02165
02166 *buffer = &auth->
incoming;
02167
02168 auth->
buffer_outstanding =
TRUE;
02169 }
02170
02178
void
02179 _dbus_auth_return_buffer (
DBusAuth *auth,
02180
DBusString *buffer,
02181
int bytes_read)
02182 {
02183
_dbus_assert (buffer == &auth->
incoming);
02184
_dbus_assert (auth->
buffer_outstanding);
02185
02186 auth->
buffer_outstanding =
FALSE;
02187 }
02188
02198
void
02199 _dbus_auth_get_unused_bytes (
DBusAuth *auth,
02200
const DBusString **str)
02201 {
02202
if (!
DBUS_AUTH_IN_END_STATE (auth))
02203
return;
02204
02205 *str = &auth->
incoming;
02206 }
02207
02208
02215
void
02216 _dbus_auth_delete_unused_bytes (
DBusAuth *auth)
02217 {
02218
if (!
DBUS_AUTH_IN_END_STATE (auth))
02219
return;
02220
02221
_dbus_string_set_length (&auth->
incoming, 0);
02222 }
02223
02232
dbus_bool_t
02233 _dbus_auth_needs_encoding (
DBusAuth *auth)
02234 {
02235
if (auth->
state != &common_state_authenticated)
02236
return FALSE;
02237
02238
if (auth->
mech !=
NULL)
02239 {
02240
if (
DBUS_AUTH_IS_CLIENT (auth))
02241
return auth->
mech->
client_encode_func !=
NULL;
02242
else
02243
return auth->
mech->
server_encode_func !=
NULL;
02244 }
02245
else
02246
return FALSE;
02247 }
02248
02259
dbus_bool_t
02260 _dbus_auth_encode_data (
DBusAuth *auth,
02261
const DBusString *plaintext,
02262
DBusString *encoded)
02263 {
02264
_dbus_assert (plaintext != encoded);
02265
02266
if (auth->
state != &common_state_authenticated)
02267
return FALSE;
02268
02269
if (
_dbus_auth_needs_encoding (auth))
02270 {
02271
if (
DBUS_AUTH_IS_CLIENT (auth))
02272
return (* auth->
mech->
client_encode_func) (auth, plaintext, encoded);
02273
else
02274
return (* auth->
mech->
server_encode_func) (auth, plaintext, encoded);
02275 }
02276
else
02277 {
02278
return _dbus_string_copy (plaintext, 0, encoded,
02279
_dbus_string_get_length (encoded));
02280 }
02281 }
02282
02291
dbus_bool_t
02292 _dbus_auth_needs_decoding (
DBusAuth *auth)
02293 {
02294
if (auth->
state != &common_state_authenticated)
02295
return FALSE;
02296
02297
if (auth->
mech !=
NULL)
02298 {
02299
if (
DBUS_AUTH_IS_CLIENT (auth))
02300
return auth->
mech->
client_decode_func !=
NULL;
02301
else
02302
return auth->
mech->
server_decode_func !=
NULL;
02303 }
02304
else
02305
return FALSE;
02306 }
02307
02308
02322
dbus_bool_t
02323 _dbus_auth_decode_data (
DBusAuth *auth,
02324
const DBusString *encoded,
02325
DBusString *plaintext)
02326 {
02327
_dbus_assert (plaintext != encoded);
02328
02329
if (auth->
state != &common_state_authenticated)
02330
return FALSE;
02331
02332
if (
_dbus_auth_needs_decoding (auth))
02333 {
02334
if (
DBUS_AUTH_IS_CLIENT (auth))
02335
return (* auth->
mech->
client_decode_func) (auth, encoded, plaintext);
02336
else
02337
return (* auth->
mech->
server_decode_func) (auth, encoded, plaintext);
02338 }
02339
else
02340 {
02341
return _dbus_string_copy (encoded, 0, plaintext,
02342
_dbus_string_get_length (plaintext));
02343 }
02344 }
02345
02353
void
02354 _dbus_auth_set_credentials (
DBusAuth *auth,
02355
const DBusCredentials *credentials)
02356 {
02357 auth->
credentials = *credentials;
02358 }
02359
02367
void
02368 _dbus_auth_get_identity (
DBusAuth *auth,
02369
DBusCredentials *credentials)
02370 {
02371
if (auth->
state == &common_state_authenticated)
02372 *credentials = auth->
authorized_identity;
02373
else
02374
_dbus_credentials_clear (credentials);
02375 }
02376
02385
dbus_bool_t
02386 _dbus_auth_set_context (
DBusAuth *auth,
02387
const DBusString *context)
02388 {
02389
return _dbus_string_replace_len (context, 0,
_dbus_string_get_length (context),
02390 &auth->
context, 0,
_dbus_string_get_length (context));
02391 }
02392
02395
#ifdef DBUS_BUILD_TESTS
02396
#include "dbus-test.h"
02397
#include "dbus-auth-script.h"
02398
#include <stdio.h>
02399
02400
static dbus_bool_t
02401 process_test_subdir (
const DBusString *test_base_dir,
02402
const char *subdir)
02403 {
02404
DBusString test_directory;
02405
DBusString filename;
02406
DBusDirIter *dir;
02407
dbus_bool_t retval;
02408
DBusError error;
02409
02410 retval =
FALSE;
02411 dir =
NULL;
02412
02413
if (!
_dbus_string_init (&test_directory))
02414
_dbus_assert_not_reached (
"didn't allocate test_directory\n");
02415
02416
_dbus_string_init_const (&filename, subdir);
02417
02418
if (!
_dbus_string_copy (test_base_dir, 0,
02419 &test_directory, 0))
02420
_dbus_assert_not_reached (
"couldn't copy test_base_dir to test_directory");
02421
02422
if (!
_dbus_concat_dir_and_file (&test_directory, &filename))
02423
_dbus_assert_not_reached (
"couldn't allocate full path");
02424
02425
_dbus_string_free (&filename);
02426
if (!
_dbus_string_init (&filename))
02427
_dbus_assert_not_reached (
"didn't allocate filename string\n");
02428
02429
dbus_error_init (&error);
02430 dir =
_dbus_directory_open (&test_directory, &error);
02431
if (dir ==
NULL)
02432 {
02433
_dbus_warn (
"Could not open %s: %s\n",
02434 _dbus_string_get_const_data (&test_directory),
02435 error.
message);
02436
dbus_error_free (&error);
02437
goto failed;
02438 }
02439
02440 printf (
"Testing %s:\n", subdir);
02441
02442 next:
02443
while (
_dbus_directory_get_next_file (dir, &filename, &error))
02444 {
02445
DBusString full_path;
02446
02447
if (!
_dbus_string_init (&full_path))
02448
_dbus_assert_not_reached (
"couldn't init string");
02449
02450
if (!
_dbus_string_copy (&test_directory, 0, &full_path, 0))
02451
_dbus_assert_not_reached (
"couldn't copy dir to full_path");
02452
02453
if (!
_dbus_concat_dir_and_file (&full_path, &filename))
02454
_dbus_assert_not_reached (
"couldn't concat file to dir");
02455
02456
if (!
_dbus_string_ends_with_c_str (&filename,
".auth-script"))
02457 {
02458 _dbus_verbose (
"Skipping non-.auth-script file %s\n",
02459 _dbus_string_get_const_data (&filename));
02460
_dbus_string_free (&full_path);
02461
goto next;
02462 }
02463
02464 printf (
" %s\n", _dbus_string_get_const_data (&filename));
02465
02466
if (!_dbus_auth_script_run (&full_path))
02467 {
02468
_dbus_string_free (&full_path);
02469
goto failed;
02470 }
02471
else
02472
_dbus_string_free (&full_path);
02473 }
02474
02475
if (
dbus_error_is_set (&error))
02476 {
02477
_dbus_warn (
"Could not get next file in %s: %s\n",
02478 _dbus_string_get_const_data (&test_directory), error.
message);
02479
dbus_error_free (&error);
02480
goto failed;
02481 }
02482
02483 retval =
TRUE;
02484
02485 failed:
02486
02487
if (dir)
02488
_dbus_directory_close (dir);
02489
_dbus_string_free (&test_directory);
02490
_dbus_string_free (&filename);
02491
02492
return retval;
02493 }
02494
02495
static dbus_bool_t
02496 process_test_dirs (
const char *test_data_dir)
02497 {
02498
DBusString test_directory;
02499
dbus_bool_t retval;
02500
02501 retval =
FALSE;
02502
02503
_dbus_string_init_const (&test_directory, test_data_dir);
02504
02505
if (!process_test_subdir (&test_directory,
"auth"))
02506
goto failed;
02507
02508 retval =
TRUE;
02509
02510 failed:
02511
02512
_dbus_string_free (&test_directory);
02513
02514
return retval;
02515 }
02516
02517
dbus_bool_t
02518 _dbus_auth_test (
const char *test_data_dir)
02519 {
02520
02521
if (test_data_dir ==
NULL)
02522
return TRUE;
02523
02524
if (!process_test_dirs (test_data_dir))
02525
return FALSE;
02526
02527
return TRUE;
02528 }
02529
02530
#endif