dbus-auth.c revision 63de4681299428db8be68bab64b969e0c1229273
1/* -*- mode: C; c-file-style: "gnu" -*- */ 2/* dbus-auth.c Authentication 3 * 4 * Copyright (C) 2002, 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.0 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23#include "dbus-auth.h" 24#include "dbus-string.h" 25#include "dbus-list.h" 26#include "dbus-internals.h" 27#include "dbus-keyring.h" 28#include "dbus-sha.h" 29#include "dbus-userdb.h" 30 31/** 32 * @defgroup DBusAuth Authentication 33 * @ingroup DBusInternals 34 * @brief DBusAuth object 35 * 36 * DBusAuth manages the authentication negotiation when a connection 37 * is first established, and also manage any encryption used over a 38 * connection. 39 * 40 * @todo some SASL profiles require sending the empty string as a 41 * challenge/response, but we don't currently allow that in our 42 * protocol. 43 * 44 * @todo DBusAuth really needs to be rewritten as an explicit state 45 * machine. Right now it's too hard to prove to yourself by inspection 46 * that it works. 47 * 48 * @todo right now sometimes both ends will block waiting for input 49 * from the other end, e.g. if there's an error during 50 * DBUS_COOKIE_SHA1. 51 * 52 * @todo the cookie keyring needs to be cached globally not just 53 * per-auth (which raises threadsafety issues too) 54 * 55 * @todo grep FIXME in dbus-auth.c 56 */ 57 58/** 59 * @defgroup DBusAuthInternals Authentication implementation details 60 * @ingroup DBusInternals 61 * @brief DBusAuth implementation details 62 * 63 * Private details of authentication code. 64 * 65 * @{ 66 */ 67 68/** 69 * This function appends an initial client response to the given string 70 */ 71typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth, 72 DBusString *response); 73 74/** 75 * This function processes a block of data received from the peer. 76 * i.e. handles a DATA command. 77 */ 78typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth, 79 const DBusString *data); 80 81/** 82 * This function encodes a block of data from the peer. 83 */ 84typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth, 85 const DBusString *data, 86 DBusString *encoded); 87 88/** 89 * This function decodes a block of data from the peer. 90 */ 91typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, 92 const DBusString *data, 93 DBusString *decoded); 94 95/** 96 * This function is called when the mechanism is abandoned. 97 */ 98typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); 99 100/** 101 * Virtual table representing a particular auth mechanism. 102 */ 103typedef struct 104{ 105 const char *mechanism; /**< Name of the mechanism */ 106 DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */ 107 DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */ 108 DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */ 109 DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */ 110 DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */ 111 DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */ 112 DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */ 113 DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */ 114 DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */ 115} DBusAuthMechanismHandler; 116 117/** 118 * Enumeration for the known authentication commands. 119 */ 120typedef enum { 121 DBUS_AUTH_COMMAND_AUTH, 122 DBUS_AUTH_COMMAND_CANCEL, 123 DBUS_AUTH_COMMAND_DATA, 124 DBUS_AUTH_COMMAND_BEGIN, 125 DBUS_AUTH_COMMAND_REJECTED, 126 DBUS_AUTH_COMMAND_OK, 127 DBUS_AUTH_COMMAND_ERROR, 128 DBUS_AUTH_COMMAND_UNKNOWN 129} DBusAuthCommand; 130 131/** 132 * Auth state function, determines the reaction to incoming events for 133 * a particular state. Returns whether we had enough memory to 134 * complete the operation. 135 */ 136typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth, 137 DBusAuthCommand command, 138 const DBusString *args); 139 140/** 141 * Information about a auth state. 142 */ 143typedef struct 144{ 145 const char *name; /**< Name of the state */ 146 DBusAuthStateFunction handler; /**< State function for this state */ 147} DBusAuthStateData; 148 149/** 150 * Internal members of DBusAuth. 151 */ 152struct DBusAuth 153{ 154 int refcount; /**< reference count */ 155 const char *side; /**< Client or server */ 156 157 DBusString incoming; /**< Incoming data buffer */ 158 DBusString outgoing; /**< Outgoing data buffer */ 159 160 const DBusAuthStateData *state; /**< Current protocol state */ 161 162 const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */ 163 164 DBusString identity; /**< Current identity we're authorizing 165 * as. 166 */ 167 168 DBusCredentials credentials; /**< Credentials read from socket, 169 * fields may be -1 170 */ 171 172 DBusCredentials authorized_identity; /**< Credentials that are authorized */ 173 174 DBusCredentials desired_identity; /**< Identity client has requested */ 175 176 DBusString context; /**< Cookie scope */ 177 DBusKeyring *keyring; /**< Keyring for cookie mechanism. */ 178 int cookie_id; /**< ID of cookie to use */ 179 DBusString challenge; /**< Challenge sent to client */ 180 181 char **allowed_mechs; /**< Mechanisms we're allowed to use, 182 * or #NULL if we can use any 183 */ 184 185 unsigned int needed_memory : 1; /**< We needed memory to continue since last 186 * successful getting something done 187 */ 188 unsigned int already_got_mechanisms : 1; /**< Client already got mech list */ 189 unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */ 190 unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */ 191}; 192 193/** 194 * "Subclass" of DBusAuth for client side 195 */ 196typedef struct 197{ 198 DBusAuth base; /**< Parent class */ 199 200 DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */ 201 202} DBusAuthClient; 203 204/** 205 * "Subclass" of DBusAuth for server side. 206 */ 207typedef struct 208{ 209 DBusAuth base; /**< Parent class */ 210 211 int failures; /**< Number of times client has been rejected */ 212 int max_failures; /**< Number of times we reject before disconnect */ 213 214} DBusAuthServer; 215 216static void goto_state (DBusAuth *auth, 217 const DBusAuthStateData *new_state); 218static dbus_bool_t send_auth (DBusAuth *auth, 219 const DBusAuthMechanismHandler *mech); 220static dbus_bool_t send_data (DBusAuth *auth, 221 DBusString *data); 222static dbus_bool_t send_rejected (DBusAuth *auth); 223static dbus_bool_t send_error (DBusAuth *auth, 224 const char *message); 225static dbus_bool_t send_ok (DBusAuth *auth); 226static dbus_bool_t send_begin (DBusAuth *auth); 227static dbus_bool_t send_cancel (DBusAuth *auth); 228 229/** 230 * Client states 231 */ 232 233static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth, 234 DBusAuthCommand command, 235 const DBusString *args); 236static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth, 237 DBusAuthCommand command, 238 const DBusString *args); 239static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth, 240 DBusAuthCommand command, 241 const DBusString *args); 242 243static const DBusAuthStateData server_state_waiting_for_auth = { 244 "WaitingForAuth", handle_server_state_waiting_for_auth 245}; 246static const DBusAuthStateData server_state_waiting_for_data = { 247 "WaitingForData", handle_server_state_waiting_for_data 248}; 249static const DBusAuthStateData server_state_waiting_for_begin = { 250 "WaitingForBegin", handle_server_state_waiting_for_begin 251}; 252 253/** 254 * Client states 255 */ 256 257static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth, 258 DBusAuthCommand command, 259 const DBusString *args); 260static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth, 261 DBusAuthCommand command, 262 const DBusString *args); 263static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth, 264 DBusAuthCommand command, 265 const DBusString *args); 266 267static const DBusAuthStateData client_state_need_send_auth = { 268 "NeedSendAuth", NULL 269}; 270static const DBusAuthStateData client_state_waiting_for_data = { 271 "WaitingForData", handle_client_state_waiting_for_data 272}; 273static const DBusAuthStateData client_state_waiting_for_ok = { 274 "WaitingForOK", handle_client_state_waiting_for_ok 275}; 276static const DBusAuthStateData client_state_waiting_for_reject = { 277 "WaitingForReject", handle_client_state_waiting_for_reject 278}; 279 280/** 281 * Common terminal states. Terminal states have handler == NULL. 282 */ 283 284static const DBusAuthStateData common_state_authenticated = { 285 "Authenticated", NULL 286}; 287 288static const DBusAuthStateData common_state_need_disconnect = { 289 "NeedDisconnect", NULL 290}; 291 292static const char auth_side_client[] = "client"; 293static const char auth_side_server[] = "server"; 294/** 295 * @param auth the auth conversation 296 * @returns #TRUE if the conversation is the server side 297 */ 298#define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server) 299/** 300 * @param auth the auth conversation 301 * @returns #TRUE if the conversation is the client side 302 */ 303#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client) 304/** 305 * @param auth the auth conversation 306 * @returns auth cast to DBusAuthClient 307 */ 308#define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth)) 309/** 310 * @param auth the auth conversation 311 * @returns auth cast to DBusAuthServer 312 */ 313#define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth)) 314 315/** 316 * The name of the auth ("client" or "server") 317 * @param auth the auth conversation 318 * @returns a string 319 */ 320#define DBUS_AUTH_NAME(auth) ((auth)->side) 321 322static DBusAuth* 323_dbus_auth_new (int size) 324{ 325 DBusAuth *auth; 326 327 auth = dbus_malloc0 (size); 328 if (auth == NULL) 329 return NULL; 330 331 auth->refcount = 1; 332 333 _dbus_credentials_clear (&auth->credentials); 334 _dbus_credentials_clear (&auth->authorized_identity); 335 _dbus_credentials_clear (&auth->desired_identity); 336 337 auth->keyring = NULL; 338 auth->cookie_id = -1; 339 340 /* note that we don't use the max string length feature, 341 * because you can't use that feature if you're going to 342 * try to recover from out-of-memory (it creates 343 * what looks like unrecoverable inability to alloc 344 * more space in the string). But we do handle 345 * overlong buffers in _dbus_auth_do_work(). 346 */ 347 348 if (!_dbus_string_init (&auth->incoming)) 349 goto enomem_0; 350 351 if (!_dbus_string_init (&auth->outgoing)) 352 goto enomem_1; 353 354 if (!_dbus_string_init (&auth->identity)) 355 goto enomem_2; 356 357 if (!_dbus_string_init (&auth->context)) 358 goto enomem_3; 359 360 if (!_dbus_string_init (&auth->challenge)) 361 goto enomem_4; 362 363 /* default context if none is specified */ 364 if (!_dbus_string_append (&auth->context, "org_freedesktop_general")) 365 goto enomem_5; 366 367 return auth; 368 369 enomem_5: 370 _dbus_string_free (&auth->challenge); 371 enomem_4: 372 _dbus_string_free (&auth->context); 373 enomem_3: 374 _dbus_string_free (&auth->identity); 375 enomem_2: 376 _dbus_string_free (&auth->outgoing); 377 enomem_1: 378 _dbus_string_free (&auth->incoming); 379 enomem_0: 380 dbus_free (auth); 381 return NULL; 382} 383 384static void 385shutdown_mech (DBusAuth *auth) 386{ 387 /* Cancel any auth */ 388 auth->already_asked_for_initial_response = FALSE; 389 _dbus_string_set_length (&auth->identity, 0); 390 391 _dbus_credentials_clear (&auth->authorized_identity); 392 _dbus_credentials_clear (&auth->desired_identity); 393 394 if (auth->mech != NULL) 395 { 396 _dbus_verbose ("%s: Shutting down mechanism %s\n", 397 DBUS_AUTH_NAME (auth), auth->mech->mechanism); 398 399 if (DBUS_AUTH_IS_CLIENT (auth)) 400 (* auth->mech->client_shutdown_func) (auth); 401 else 402 (* auth->mech->server_shutdown_func) (auth); 403 404 auth->mech = NULL; 405 } 406} 407 408/* Returns TRUE but with an empty string hash if the 409 * cookie_id isn't known. As with all this code 410 * TRUE just means we had enough memory. 411 */ 412static dbus_bool_t 413sha1_compute_hash (DBusAuth *auth, 414 int cookie_id, 415 const DBusString *server_challenge, 416 const DBusString *client_challenge, 417 DBusString *hash) 418{ 419 DBusString cookie; 420 DBusString to_hash; 421 dbus_bool_t retval; 422 423 _dbus_assert (auth->keyring != NULL); 424 425 retval = FALSE; 426 427 if (!_dbus_string_init (&cookie)) 428 return FALSE; 429 430 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id, 431 &cookie)) 432 goto out_0; 433 434 if (_dbus_string_get_length (&cookie) == 0) 435 { 436 retval = TRUE; 437 goto out_0; 438 } 439 440 if (!_dbus_string_init (&to_hash)) 441 goto out_0; 442 443 if (!_dbus_string_copy (server_challenge, 0, 444 &to_hash, _dbus_string_get_length (&to_hash))) 445 goto out_1; 446 447 if (!_dbus_string_append (&to_hash, ":")) 448 goto out_1; 449 450 if (!_dbus_string_copy (client_challenge, 0, 451 &to_hash, _dbus_string_get_length (&to_hash))) 452 goto out_1; 453 454 if (!_dbus_string_append (&to_hash, ":")) 455 goto out_1; 456 457 if (!_dbus_string_copy (&cookie, 0, 458 &to_hash, _dbus_string_get_length (&to_hash))) 459 goto out_1; 460 461 if (!_dbus_sha_compute (&to_hash, hash)) 462 goto out_1; 463 464 retval = TRUE; 465 466 out_1: 467 _dbus_string_zero (&to_hash); 468 _dbus_string_free (&to_hash); 469 out_0: 470 _dbus_string_zero (&cookie); 471 _dbus_string_free (&cookie); 472 return retval; 473} 474 475/** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of 476 * entropy, we use 128. This is the number of bytes in the random 477 * challenge. 478 */ 479#define N_CHALLENGE_BYTES (128/8) 480 481static dbus_bool_t 482sha1_handle_first_client_response (DBusAuth *auth, 483 const DBusString *data) 484{ 485 /* We haven't sent a challenge yet, we're expecting a desired 486 * username from the client. 487 */ 488 DBusString tmp; 489 DBusString tmp2; 490 dbus_bool_t retval; 491 DBusError error; 492 493 retval = FALSE; 494 495 _dbus_string_set_length (&auth->challenge, 0); 496 497 if (_dbus_string_get_length (data) > 0) 498 { 499 if (_dbus_string_get_length (&auth->identity) > 0) 500 { 501 /* Tried to send two auth identities, wtf */ 502 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 503 DBUS_AUTH_NAME (auth)); 504 return send_rejected (auth); 505 } 506 else 507 { 508 /* this is our auth identity */ 509 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 510 return FALSE; 511 } 512 } 513 514 if (!_dbus_credentials_from_username (data, &auth->desired_identity)) 515 { 516 _dbus_verbose ("%s: Did not get a valid username from client\n", 517 DBUS_AUTH_NAME (auth)); 518 return send_rejected (auth); 519 } 520 521 if (!_dbus_string_init (&tmp)) 522 return FALSE; 523 524 if (!_dbus_string_init (&tmp2)) 525 { 526 _dbus_string_free (&tmp); 527 return FALSE; 528 } 529 530 /* we cache the keyring for speed, so here we drop it if it's the 531 * wrong one. FIXME caching the keyring here is useless since we use 532 * a different DBusAuth for every connection. 533 */ 534 if (auth->keyring && 535 !_dbus_keyring_is_for_user (auth->keyring, 536 data)) 537 { 538 _dbus_keyring_unref (auth->keyring); 539 auth->keyring = NULL; 540 } 541 542 if (auth->keyring == NULL) 543 { 544 DBusError error; 545 546 dbus_error_init (&error); 547 auth->keyring = _dbus_keyring_new_homedir (data, 548 &auth->context, 549 &error); 550 551 if (auth->keyring == NULL) 552 { 553 if (dbus_error_has_name (&error, 554 DBUS_ERROR_NO_MEMORY)) 555 { 556 dbus_error_free (&error); 557 goto out; 558 } 559 else 560 { 561 _DBUS_ASSERT_ERROR_IS_SET (&error); 562 _dbus_verbose ("%s: Error loading keyring: %s\n", 563 DBUS_AUTH_NAME (auth), error.message); 564 if (send_rejected (auth)) 565 retval = TRUE; /* retval is only about mem */ 566 dbus_error_free (&error); 567 goto out; 568 } 569 } 570 else 571 { 572 _dbus_assert (!dbus_error_is_set (&error)); 573 } 574 } 575 576 _dbus_assert (auth->keyring != NULL); 577 578 dbus_error_init (&error); 579 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); 580 if (auth->cookie_id < 0) 581 { 582 _DBUS_ASSERT_ERROR_IS_SET (&error); 583 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n", 584 DBUS_AUTH_NAME (auth), error.message); 585 if (send_rejected (auth)) 586 retval = TRUE; 587 dbus_error_free (&error); 588 goto out; 589 } 590 else 591 { 592 _dbus_assert (!dbus_error_is_set (&error)); 593 } 594 595 if (!_dbus_string_copy (&auth->context, 0, 596 &tmp2, _dbus_string_get_length (&tmp2))) 597 goto out; 598 599 if (!_dbus_string_append (&tmp2, " ")) 600 goto out; 601 602 if (!_dbus_string_append_int (&tmp2, auth->cookie_id)) 603 goto out; 604 605 if (!_dbus_string_append (&tmp2, " ")) 606 goto out; 607 608 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) 609 goto out; 610 611 _dbus_string_set_length (&auth->challenge, 0); 612 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0)) 613 goto out; 614 615 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2, 616 _dbus_string_get_length (&tmp2))) 617 goto out; 618 619 if (!send_data (auth, &tmp2)) 620 goto out; 621 622 goto_state (auth, &server_state_waiting_for_data); 623 retval = TRUE; 624 625 out: 626 _dbus_string_zero (&tmp); 627 _dbus_string_free (&tmp); 628 _dbus_string_zero (&tmp2); 629 _dbus_string_free (&tmp2); 630 631 return retval; 632} 633 634static dbus_bool_t 635sha1_handle_second_client_response (DBusAuth *auth, 636 const DBusString *data) 637{ 638 /* We are expecting a response which is the hex-encoded client 639 * challenge, space, then SHA-1 hash of the concatenation of our 640 * challenge, ":", client challenge, ":", secret key, all 641 * hex-encoded. 642 */ 643 int i; 644 DBusString client_challenge; 645 DBusString client_hash; 646 dbus_bool_t retval; 647 DBusString correct_hash; 648 649 retval = FALSE; 650 651 if (!_dbus_string_find_blank (data, 0, &i)) 652 { 653 _dbus_verbose ("%s: no space separator in client response\n", 654 DBUS_AUTH_NAME (auth)); 655 return send_rejected (auth); 656 } 657 658 if (!_dbus_string_init (&client_challenge)) 659 goto out_0; 660 661 if (!_dbus_string_init (&client_hash)) 662 goto out_1; 663 664 if (!_dbus_string_copy_len (data, 0, i, &client_challenge, 665 0)) 666 goto out_2; 667 668 _dbus_string_skip_blank (data, i, &i); 669 670 if (!_dbus_string_copy_len (data, i, 671 _dbus_string_get_length (data) - i, 672 &client_hash, 673 0)) 674 goto out_2; 675 676 if (_dbus_string_get_length (&client_challenge) == 0 || 677 _dbus_string_get_length (&client_hash) == 0) 678 { 679 _dbus_verbose ("%s: zero-length client challenge or hash\n", 680 DBUS_AUTH_NAME (auth)); 681 if (send_rejected (auth)) 682 retval = TRUE; 683 goto out_2; 684 } 685 686 if (!_dbus_string_init (&correct_hash)) 687 goto out_2; 688 689 if (!sha1_compute_hash (auth, auth->cookie_id, 690 &auth->challenge, 691 &client_challenge, 692 &correct_hash)) 693 goto out_3; 694 695 /* if cookie_id was invalid, then we get an empty hash */ 696 if (_dbus_string_get_length (&correct_hash) == 0) 697 { 698 if (send_rejected (auth)) 699 retval = TRUE; 700 goto out_3; 701 } 702 703 if (!_dbus_string_equal (&client_hash, &correct_hash)) 704 { 705 if (send_rejected (auth)) 706 retval = TRUE; 707 goto out_3; 708 } 709 710 if (!send_ok (auth)) 711 goto out_3; 712 713 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT" using DBUS_COOKIE_SHA1\n", 714 DBUS_AUTH_NAME (auth), auth->desired_identity.uid); 715 716 auth->authorized_identity = auth->desired_identity; 717 retval = TRUE; 718 719 out_3: 720 _dbus_string_zero (&correct_hash); 721 _dbus_string_free (&correct_hash); 722 out_2: 723 _dbus_string_zero (&client_hash); 724 _dbus_string_free (&client_hash); 725 out_1: 726 _dbus_string_free (&client_challenge); 727 out_0: 728 return retval; 729} 730 731static dbus_bool_t 732handle_server_data_cookie_sha1_mech (DBusAuth *auth, 733 const DBusString *data) 734{ 735 if (auth->cookie_id < 0) 736 return sha1_handle_first_client_response (auth, data); 737 else 738 return sha1_handle_second_client_response (auth, data); 739} 740 741static void 742handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth) 743{ 744 auth->cookie_id = -1; 745 _dbus_string_set_length (&auth->challenge, 0); 746} 747 748static dbus_bool_t 749handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth, 750 DBusString *response) 751{ 752 const DBusString *username; 753 dbus_bool_t retval; 754 755 retval = FALSE; 756 757 if (!_dbus_username_from_current_process (&username)) 758 goto out_0; 759 760 if (!_dbus_string_hex_encode (username, 0, 761 response, 762 _dbus_string_get_length (response))) 763 goto out_0; 764 765 retval = TRUE; 766 767 out_0: 768 return retval; 769} 770 771static dbus_bool_t 772handle_client_data_cookie_sha1_mech (DBusAuth *auth, 773 const DBusString *data) 774{ 775 /* The data we get from the server should be the cookie context 776 * name, the cookie ID, and the server challenge, separated by 777 * spaces. We send back our challenge string and the correct hash. 778 */ 779 dbus_bool_t retval; 780 DBusString context; 781 DBusString cookie_id_str; 782 DBusString server_challenge; 783 DBusString client_challenge; 784 DBusString correct_hash; 785 DBusString tmp; 786 int i, j; 787 long val; 788 789 retval = FALSE; 790 791 if (!_dbus_string_find_blank (data, 0, &i)) 792 { 793 if (send_error (auth, 794 "Server did not send context/ID/challenge properly")) 795 retval = TRUE; 796 goto out_0; 797 } 798 799 if (!_dbus_string_init (&context)) 800 goto out_0; 801 802 if (!_dbus_string_copy_len (data, 0, i, 803 &context, 0)) 804 goto out_1; 805 806 _dbus_string_skip_blank (data, i, &i); 807 if (!_dbus_string_find_blank (data, i, &j)) 808 { 809 if (send_error (auth, 810 "Server did not send context/ID/challenge properly")) 811 retval = TRUE; 812 goto out_1; 813 } 814 815 if (!_dbus_string_init (&cookie_id_str)) 816 goto out_1; 817 818 if (!_dbus_string_copy_len (data, i, j - i, 819 &cookie_id_str, 0)) 820 goto out_2; 821 822 if (!_dbus_string_init (&server_challenge)) 823 goto out_2; 824 825 i = j; 826 _dbus_string_skip_blank (data, i, &i); 827 j = _dbus_string_get_length (data); 828 829 if (!_dbus_string_copy_len (data, i, j - i, 830 &server_challenge, 0)) 831 goto out_3; 832 833 if (!_dbus_keyring_validate_context (&context)) 834 { 835 if (send_error (auth, "Server sent invalid cookie context")) 836 retval = TRUE; 837 goto out_3; 838 } 839 840 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL)) 841 { 842 if (send_error (auth, "Could not parse cookie ID as an integer")) 843 retval = TRUE; 844 goto out_3; 845 } 846 847 if (_dbus_string_get_length (&server_challenge) == 0) 848 { 849 if (send_error (auth, "Empty server challenge string")) 850 retval = TRUE; 851 goto out_3; 852 } 853 854 if (auth->keyring == NULL) 855 { 856 DBusError error; 857 858 dbus_error_init (&error); 859 auth->keyring = _dbus_keyring_new_homedir (NULL, 860 &context, 861 &error); 862 863 if (auth->keyring == NULL) 864 { 865 if (dbus_error_has_name (&error, 866 DBUS_ERROR_NO_MEMORY)) 867 { 868 dbus_error_free (&error); 869 goto out_3; 870 } 871 else 872 { 873 _DBUS_ASSERT_ERROR_IS_SET (&error); 874 875 _dbus_verbose ("%s: Error loading keyring: %s\n", 876 DBUS_AUTH_NAME (auth), error.message); 877 878 if (send_error (auth, "Could not load cookie file")) 879 retval = TRUE; /* retval is only about mem */ 880 881 dbus_error_free (&error); 882 goto out_3; 883 } 884 } 885 else 886 { 887 _dbus_assert (!dbus_error_is_set (&error)); 888 } 889 } 890 891 _dbus_assert (auth->keyring != NULL); 892 893 if (!_dbus_string_init (&tmp)) 894 goto out_3; 895 896 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) 897 goto out_4; 898 899 if (!_dbus_string_init (&client_challenge)) 900 goto out_4; 901 902 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0)) 903 goto out_5; 904 905 if (!_dbus_string_init (&correct_hash)) 906 goto out_5; 907 908 if (!sha1_compute_hash (auth, val, 909 &server_challenge, 910 &client_challenge, 911 &correct_hash)) 912 goto out_6; 913 914 if (_dbus_string_get_length (&correct_hash) == 0) 915 { 916 /* couldn't find the cookie ID or something */ 917 if (send_error (auth, "Don't have the requested cookie ID")) 918 retval = TRUE; 919 goto out_6; 920 } 921 922 _dbus_string_set_length (&tmp, 0); 923 924 if (!_dbus_string_copy (&client_challenge, 0, &tmp, 925 _dbus_string_get_length (&tmp))) 926 goto out_6; 927 928 if (!_dbus_string_append (&tmp, " ")) 929 goto out_6; 930 931 if (!_dbus_string_copy (&correct_hash, 0, &tmp, 932 _dbus_string_get_length (&tmp))) 933 goto out_6; 934 935 if (!send_data (auth, &tmp)) 936 goto out_6; 937 938 retval = TRUE; 939 940 out_6: 941 _dbus_string_zero (&correct_hash); 942 _dbus_string_free (&correct_hash); 943 out_5: 944 _dbus_string_free (&client_challenge); 945 out_4: 946 _dbus_string_zero (&tmp); 947 _dbus_string_free (&tmp); 948 out_3: 949 _dbus_string_free (&server_challenge); 950 out_2: 951 _dbus_string_free (&cookie_id_str); 952 out_1: 953 _dbus_string_free (&context); 954 out_0: 955 return retval; 956} 957 958static void 959handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth) 960{ 961 auth->cookie_id = -1; 962 _dbus_string_set_length (&auth->challenge, 0); 963} 964 965static dbus_bool_t 966handle_server_data_external_mech (DBusAuth *auth, 967 const DBusString *data) 968{ 969 if (auth->credentials.uid == DBUS_UID_UNSET) 970 { 971 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n", 972 DBUS_AUTH_NAME (auth)); 973 return send_rejected (auth); 974 } 975 976 if (_dbus_string_get_length (data) > 0) 977 { 978 if (_dbus_string_get_length (&auth->identity) > 0) 979 { 980 /* Tried to send two auth identities, wtf */ 981 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 982 DBUS_AUTH_NAME (auth)); 983 return send_rejected (auth); 984 } 985 else 986 { 987 /* this is our auth identity */ 988 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 989 return FALSE; 990 } 991 } 992 993 /* Poke client for an auth identity, if none given */ 994 if (_dbus_string_get_length (&auth->identity) == 0 && 995 !auth->already_asked_for_initial_response) 996 { 997 if (send_data (auth, NULL)) 998 { 999 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n", 1000 DBUS_AUTH_NAME (auth)); 1001 auth->already_asked_for_initial_response = TRUE; 1002 return TRUE; 1003 } 1004 else 1005 return FALSE; 1006 } 1007 1008 _dbus_credentials_clear (&auth->desired_identity); 1009 1010 /* If auth->identity is still empty here, then client 1011 * responded with an empty string after we poked it for 1012 * an initial response. This means to try to auth the 1013 * identity provided in the credentials. 1014 */ 1015 if (_dbus_string_get_length (&auth->identity) == 0) 1016 { 1017 auth->desired_identity.uid = auth->credentials.uid; 1018 } 1019 else 1020 { 1021 if (!_dbus_uid_from_string (&auth->identity, 1022 &auth->desired_identity.uid)) 1023 { 1024 _dbus_verbose ("%s: could not get credentials from uid string\n", 1025 DBUS_AUTH_NAME (auth)); 1026 return send_rejected (auth); 1027 } 1028 } 1029 1030 if (auth->desired_identity.uid == DBUS_UID_UNSET) 1031 { 1032 _dbus_verbose ("%s: desired user %s is no good\n", 1033 DBUS_AUTH_NAME (auth), 1034 _dbus_string_get_const_data (&auth->identity)); 1035 return send_rejected (auth); 1036 } 1037 1038 if (_dbus_credentials_match (&auth->desired_identity, 1039 &auth->credentials)) 1040 { 1041 /* client has authenticated */ 1042 if (!send_ok (auth)) 1043 return FALSE; 1044 1045 _dbus_verbose ("%s: authenticated client with UID "DBUS_UID_FORMAT 1046 " matching socket credentials UID "DBUS_UID_FORMAT"\n", 1047 DBUS_AUTH_NAME (auth), 1048 auth->desired_identity.uid, 1049 auth->credentials.uid); 1050 1051 auth->authorized_identity.uid = auth->desired_identity.uid; 1052 1053 return TRUE; 1054 } 1055 else 1056 { 1057 _dbus_verbose ("%s: credentials uid="DBUS_UID_FORMAT 1058 " gid="DBUS_GID_FORMAT 1059 " do not allow uid="DBUS_UID_FORMAT 1060 " gid="DBUS_GID_FORMAT"\n", 1061 DBUS_AUTH_NAME (auth), 1062 auth->credentials.uid, auth->credentials.gid, 1063 auth->desired_identity.uid, auth->desired_identity.gid); 1064 return send_rejected (auth); 1065 } 1066} 1067 1068static void 1069handle_server_shutdown_external_mech (DBusAuth *auth) 1070{ 1071 1072} 1073 1074static dbus_bool_t 1075handle_client_initial_response_external_mech (DBusAuth *auth, 1076 DBusString *response) 1077{ 1078 /* We always append our UID as an initial response, so the server 1079 * doesn't have to send back an empty challenge to check whether we 1080 * want to specify an identity. i.e. this avoids a round trip that 1081 * the spec for the EXTERNAL mechanism otherwise requires. 1082 */ 1083 DBusString plaintext; 1084 1085 if (!_dbus_string_init (&plaintext)) 1086 return FALSE; 1087 1088 if (!_dbus_string_append_uint (&plaintext, 1089 _dbus_getuid ())) 1090 goto failed; 1091 1092 if (!_dbus_string_hex_encode (&plaintext, 0, 1093 response, 1094 _dbus_string_get_length (response))) 1095 goto failed; 1096 1097 _dbus_string_free (&plaintext); 1098 1099 return TRUE; 1100 1101 failed: 1102 _dbus_string_free (&plaintext); 1103 return FALSE; 1104} 1105 1106static dbus_bool_t 1107handle_client_data_external_mech (DBusAuth *auth, 1108 const DBusString *data) 1109{ 1110 1111 return TRUE; 1112} 1113 1114static void 1115handle_client_shutdown_external_mech (DBusAuth *auth) 1116{ 1117 1118} 1119 1120/* Put mechanisms here in order of preference. 1121 * What I eventually want to have is: 1122 * 1123 * - a mechanism that checks UNIX domain socket credentials 1124 * - a simple magic cookie mechanism like X11 or ICE 1125 * - mechanisms that chain to Cyrus SASL, so we can use anything it 1126 * offers such as Kerberos, X509, whatever. 1127 * 1128 */ 1129static const DBusAuthMechanismHandler 1130all_mechanisms[] = { 1131 { "EXTERNAL", 1132 handle_server_data_external_mech, 1133 NULL, NULL, 1134 handle_server_shutdown_external_mech, 1135 handle_client_initial_response_external_mech, 1136 handle_client_data_external_mech, 1137 NULL, NULL, 1138 handle_client_shutdown_external_mech }, 1139 { "DBUS_COOKIE_SHA1", 1140 handle_server_data_cookie_sha1_mech, 1141 NULL, NULL, 1142 handle_server_shutdown_cookie_sha1_mech, 1143 handle_client_initial_response_cookie_sha1_mech, 1144 handle_client_data_cookie_sha1_mech, 1145 NULL, NULL, 1146 handle_client_shutdown_cookie_sha1_mech }, 1147 { NULL, NULL } 1148}; 1149 1150static const DBusAuthMechanismHandler* 1151find_mech (const DBusString *name, 1152 char **allowed_mechs) 1153{ 1154 int i; 1155 1156 if (allowed_mechs != NULL && 1157 !_dbus_string_array_contains ((const char**) allowed_mechs, 1158 _dbus_string_get_const_data (name))) 1159 return NULL; 1160 1161 i = 0; 1162 while (all_mechanisms[i].mechanism != NULL) 1163 { 1164 if (_dbus_string_equal_c_str (name, 1165 all_mechanisms[i].mechanism)) 1166 1167 return &all_mechanisms[i]; 1168 1169 ++i; 1170 } 1171 1172 return NULL; 1173} 1174 1175static dbus_bool_t 1176send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) 1177{ 1178 DBusString auth_command; 1179 1180 if (!_dbus_string_init (&auth_command)) 1181 return FALSE; 1182 1183 if (!_dbus_string_append (&auth_command, 1184 "AUTH ")) 1185 { 1186 _dbus_string_free (&auth_command); 1187 return FALSE; 1188 } 1189 1190 if (!_dbus_string_append (&auth_command, 1191 mech->mechanism)) 1192 { 1193 _dbus_string_free (&auth_command); 1194 return FALSE; 1195 } 1196 1197 if (mech->client_initial_response_func != NULL) 1198 { 1199 if (!_dbus_string_append (&auth_command, " ")) 1200 { 1201 _dbus_string_free (&auth_command); 1202 return FALSE; 1203 } 1204 1205 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 1206 { 1207 _dbus_string_free (&auth_command); 1208 return FALSE; 1209 } 1210 } 1211 1212 if (!_dbus_string_append (&auth_command, 1213 "\r\n")) 1214 { 1215 _dbus_string_free (&auth_command); 1216 return FALSE; 1217 } 1218 1219 if (!_dbus_string_copy (&auth_command, 0, 1220 &auth->outgoing, 1221 _dbus_string_get_length (&auth->outgoing))) 1222 { 1223 _dbus_string_free (&auth_command); 1224 return FALSE; 1225 } 1226 1227 _dbus_string_free (&auth_command); 1228 shutdown_mech (auth); 1229 auth->mech = mech; 1230 goto_state (auth, &client_state_waiting_for_data); 1231 1232 return TRUE; 1233} 1234 1235static dbus_bool_t 1236send_data (DBusAuth *auth, DBusString *data) 1237{ 1238 int old_len; 1239 1240 if (data == NULL || _dbus_string_get_length (data) == 0) 1241 return _dbus_string_append (&auth->outgoing, "DATA\r\n"); 1242 else 1243 { 1244 old_len = _dbus_string_get_length (&auth->outgoing); 1245 if (!_dbus_string_append (&auth->outgoing, "DATA ")) 1246 goto out; 1247 1248 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, 1249 _dbus_string_get_length (&auth->outgoing))) 1250 goto out; 1251 1252 if (!_dbus_string_append (&auth->outgoing, "\r\n")) 1253 goto out; 1254 1255 return TRUE; 1256 1257 out: 1258 _dbus_string_set_length (&auth->outgoing, old_len); 1259 1260 return FALSE; 1261 } 1262} 1263 1264static dbus_bool_t 1265send_rejected (DBusAuth *auth) 1266{ 1267 DBusString command; 1268 DBusAuthServer *server_auth; 1269 int i; 1270 1271 if (!_dbus_string_init (&command)) 1272 return FALSE; 1273 1274 if (!_dbus_string_append (&command, 1275 "REJECTED")) 1276 goto nomem; 1277 1278 i = 0; 1279 while (all_mechanisms[i].mechanism != NULL) 1280 { 1281 if (!_dbus_string_append (&command, 1282 " ")) 1283 goto nomem; 1284 1285 if (!_dbus_string_append (&command, 1286 all_mechanisms[i].mechanism)) 1287 goto nomem; 1288 1289 ++i; 1290 } 1291 1292 if (!_dbus_string_append (&command, "\r\n")) 1293 goto nomem; 1294 1295 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 1296 _dbus_string_get_length (&auth->outgoing))) 1297 goto nomem; 1298 1299 shutdown_mech (auth); 1300 1301 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 1302 server_auth = DBUS_AUTH_SERVER (auth); 1303 server_auth->failures += 1; 1304 1305 if (server_auth->failures >= server_auth->max_failures) 1306 goto_state (auth, &common_state_need_disconnect); 1307 else 1308 goto_state (auth, &server_state_waiting_for_auth); 1309 1310 _dbus_string_free (&command); 1311 1312 return TRUE; 1313 1314 nomem: 1315 _dbus_string_free (&command); 1316 return FALSE; 1317} 1318 1319static dbus_bool_t 1320send_error (DBusAuth *auth, const char *message) 1321{ 1322 return _dbus_string_append_printf (&auth->outgoing, 1323 "ERROR \"%s\"\r\n", message); 1324} 1325 1326static dbus_bool_t 1327send_ok (DBusAuth *auth) 1328{ 1329 if (_dbus_string_append (&auth->outgoing, "OK\r\n")) 1330 { 1331 goto_state (auth, &server_state_waiting_for_begin); 1332 return TRUE; 1333 } 1334 else 1335 return FALSE; 1336} 1337 1338static dbus_bool_t 1339send_begin (DBusAuth *auth) 1340{ 1341 if (_dbus_string_append (&auth->outgoing, "BEGIN\r\n")) 1342 { 1343 goto_state (auth, &common_state_authenticated); 1344 return TRUE; 1345 } 1346 else 1347 return FALSE; 1348} 1349 1350static dbus_bool_t 1351send_cancel (DBusAuth *auth) 1352{ 1353 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) 1354 { 1355 goto_state (auth, &client_state_waiting_for_reject); 1356 return TRUE; 1357 } 1358 else 1359 return FALSE; 1360} 1361 1362static dbus_bool_t 1363process_data (DBusAuth *auth, 1364 const DBusString *args, 1365 DBusAuthDataFunction data_func) 1366{ 1367 int end; 1368 DBusString decoded; 1369 1370 if (!_dbus_string_init (&decoded)) 1371 return FALSE; 1372 1373 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) 1374 { 1375 _dbus_string_free (&decoded); 1376 return FALSE; 1377 } 1378 1379 if (_dbus_string_get_length (args) != end) 1380 { 1381 _dbus_string_free (&decoded); 1382 if (!send_error (auth, "Invalid hex encoding")) 1383 return FALSE; 1384 1385 return TRUE; 1386 } 1387 1388#ifdef DBUS_ENABLE_VERBOSE_MODE 1389 if (_dbus_string_validate_ascii (&decoded, 0, 1390 _dbus_string_get_length (&decoded))) 1391 _dbus_verbose ("%s: data: '%s'\n", 1392 DBUS_AUTH_NAME (auth), 1393 _dbus_string_get_const_data (&decoded)); 1394#endif 1395 1396 if (!(* data_func) (auth, &decoded)) 1397 { 1398 _dbus_string_free (&decoded); 1399 return FALSE; 1400 } 1401 1402 _dbus_string_free (&decoded); 1403 return TRUE; 1404} 1405 1406static dbus_bool_t 1407handle_auth (DBusAuth *auth, const DBusString *args) 1408{ 1409 if (_dbus_string_get_length (args) == 0) 1410 { 1411 /* No args to the auth, send mechanisms */ 1412 if (!send_rejected (auth)) 1413 return FALSE; 1414 1415 return TRUE; 1416 } 1417 else 1418 { 1419 int i; 1420 DBusString mech; 1421 DBusString hex_response; 1422 1423 _dbus_string_find_blank (args, 0, &i); 1424 1425 if (!_dbus_string_init (&mech)) 1426 return FALSE; 1427 1428 if (!_dbus_string_init (&hex_response)) 1429 { 1430 _dbus_string_free (&mech); 1431 return FALSE; 1432 } 1433 1434 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 1435 goto failed; 1436 1437 _dbus_string_skip_blank (args, i, &i); 1438 if (!_dbus_string_copy (args, i, &hex_response, 0)) 1439 goto failed; 1440 1441 auth->mech = find_mech (&mech, auth->allowed_mechs); 1442 if (auth->mech != NULL) 1443 { 1444 _dbus_verbose ("%s: Trying mechanism %s\n", 1445 DBUS_AUTH_NAME (auth), 1446 auth->mech->mechanism); 1447 1448 if (!process_data (auth, &hex_response, 1449 auth->mech->server_data_func)) 1450 goto failed; 1451 } 1452 else 1453 { 1454 /* Unsupported mechanism */ 1455 _dbus_verbose ("%s: Unsupported mechanism %s\n", 1456 DBUS_AUTH_NAME (auth), 1457 _dbus_string_get_const_data (&mech)); 1458 1459 if (!send_rejected (auth)) 1460 goto failed; 1461 } 1462 1463 _dbus_string_free (&mech); 1464 _dbus_string_free (&hex_response); 1465 1466 return TRUE; 1467 1468 failed: 1469 auth->mech = NULL; 1470 _dbus_string_free (&mech); 1471 _dbus_string_free (&hex_response); 1472 return FALSE; 1473 } 1474} 1475 1476static dbus_bool_t 1477handle_server_state_waiting_for_auth (DBusAuth *auth, 1478 DBusAuthCommand command, 1479 const DBusString *args) 1480{ 1481 switch (command) 1482 { 1483 case DBUS_AUTH_COMMAND_AUTH: 1484 return handle_auth (auth, args); 1485 1486 case DBUS_AUTH_COMMAND_CANCEL: 1487 case DBUS_AUTH_COMMAND_DATA: 1488 return send_error (auth, "Not currently in an auth conversation"); 1489 1490 case DBUS_AUTH_COMMAND_BEGIN: 1491 goto_state (auth, &common_state_need_disconnect); 1492 return TRUE; 1493 1494 case DBUS_AUTH_COMMAND_ERROR: 1495 return send_rejected (auth); 1496 1497 case DBUS_AUTH_COMMAND_REJECTED: 1498 case DBUS_AUTH_COMMAND_OK: 1499 case DBUS_AUTH_COMMAND_UNKNOWN: 1500 default: 1501 return send_error (auth, "Unknown command"); 1502 } 1503} 1504 1505static dbus_bool_t 1506handle_server_state_waiting_for_data (DBusAuth *auth, 1507 DBusAuthCommand command, 1508 const DBusString *args) 1509{ 1510 switch (command) 1511 { 1512 case DBUS_AUTH_COMMAND_AUTH: 1513 return send_error (auth, "Sent AUTH while another AUTH in progress"); 1514 1515 case DBUS_AUTH_COMMAND_CANCEL: 1516 case DBUS_AUTH_COMMAND_ERROR: 1517 return send_rejected (auth); 1518 1519 case DBUS_AUTH_COMMAND_DATA: 1520 return process_data (auth, args, auth->mech->server_data_func); 1521 1522 case DBUS_AUTH_COMMAND_BEGIN: 1523 goto_state (auth, &common_state_need_disconnect); 1524 return TRUE; 1525 1526 case DBUS_AUTH_COMMAND_REJECTED: 1527 case DBUS_AUTH_COMMAND_OK: 1528 case DBUS_AUTH_COMMAND_UNKNOWN: 1529 default: 1530 return send_error (auth, "Unknown command"); 1531 } 1532} 1533 1534static dbus_bool_t 1535handle_server_state_waiting_for_begin (DBusAuth *auth, 1536 DBusAuthCommand command, 1537 const DBusString *args) 1538{ 1539 switch (command) 1540 { 1541 case DBUS_AUTH_COMMAND_AUTH: 1542 return send_error (auth, "Sent AUTH while expecting BEGIN"); 1543 1544 case DBUS_AUTH_COMMAND_DATA: 1545 return send_error (auth, "Sent DATA while expecting BEGIN"); 1546 1547 case DBUS_AUTH_COMMAND_BEGIN: 1548 goto_state (auth, &common_state_authenticated); 1549 return TRUE; 1550 1551 case DBUS_AUTH_COMMAND_REJECTED: 1552 case DBUS_AUTH_COMMAND_OK: 1553 case DBUS_AUTH_COMMAND_UNKNOWN: 1554 default: 1555 return send_error (auth, "Unknown command"); 1556 1557 case DBUS_AUTH_COMMAND_CANCEL: 1558 case DBUS_AUTH_COMMAND_ERROR: 1559 return send_rejected (auth); 1560 } 1561} 1562 1563/* return FALSE if no memory, TRUE if all OK */ 1564static dbus_bool_t 1565get_word (const DBusString *str, 1566 int *start, 1567 DBusString *word) 1568{ 1569 int i; 1570 1571 _dbus_string_skip_blank (str, *start, start); 1572 _dbus_string_find_blank (str, *start, &i); 1573 1574 if (i > *start) 1575 { 1576 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) 1577 return FALSE; 1578 1579 *start = i; 1580 } 1581 1582 return TRUE; 1583} 1584 1585static dbus_bool_t 1586record_mechanisms (DBusAuth *auth, 1587 const DBusString *args) 1588{ 1589 int next; 1590 int len; 1591 1592 if (auth->already_got_mechanisms) 1593 return TRUE; 1594 1595 len = _dbus_string_get_length (args); 1596 1597 next = 0; 1598 while (next < len) 1599 { 1600 DBusString m; 1601 const DBusAuthMechanismHandler *mech; 1602 1603 if (!_dbus_string_init (&m)) 1604 goto nomem; 1605 1606 if (!get_word (args, &next, &m)) 1607 { 1608 _dbus_string_free (&m); 1609 goto nomem; 1610 } 1611 1612 mech = find_mech (&m, auth->allowed_mechs); 1613 1614 if (mech != NULL) 1615 { 1616 /* FIXME right now we try mechanisms in the order 1617 * the server lists them; should we do them in 1618 * some more deterministic order? 1619 * 1620 * Probably in all_mechanisms order, our order of 1621 * preference. Of course when the server is us, 1622 * it lists things in that order anyhow. 1623 */ 1624 1625 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", 1626 DBUS_AUTH_NAME (auth), mech->mechanism); 1627 1628 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 1629 (void*) mech)) 1630 { 1631 _dbus_string_free (&m); 1632 goto nomem; 1633 } 1634 } 1635 else 1636 { 1637 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", 1638 DBUS_AUTH_NAME (auth), 1639 _dbus_string_get_const_data (&m)); 1640 } 1641 1642 _dbus_string_free (&m); 1643 } 1644 1645 auth->already_got_mechanisms = TRUE; 1646 1647 return TRUE; 1648 1649 nomem: 1650 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 1651 1652 return FALSE; 1653} 1654 1655static dbus_bool_t 1656process_rejected (DBusAuth *auth, const DBusString *args) 1657{ 1658 const DBusAuthMechanismHandler *mech; 1659 DBusAuthClient *client; 1660 1661 client = DBUS_AUTH_CLIENT (auth); 1662 1663 if (!auth->already_got_mechanisms) 1664 { 1665 if (!record_mechanisms (auth, args)) 1666 return FALSE; 1667 } 1668 1669 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 1670 { 1671 mech = client->mechs_to_try->data; 1672 1673 if (!send_auth (auth, mech)) 1674 return FALSE; 1675 1676 _dbus_list_pop_first (&client->mechs_to_try); 1677 1678 _dbus_verbose ("%s: Trying mechanism %s\n", 1679 DBUS_AUTH_NAME (auth), 1680 mech->mechanism); 1681 } 1682 else 1683 { 1684 /* Give up */ 1685 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", 1686 DBUS_AUTH_NAME (auth)); 1687 goto_state (auth, &common_state_need_disconnect); 1688 } 1689 1690 return TRUE; 1691} 1692 1693 1694static dbus_bool_t 1695handle_client_state_waiting_for_data (DBusAuth *auth, 1696 DBusAuthCommand command, 1697 const DBusString *args) 1698{ 1699 _dbus_assert (auth->mech != NULL); 1700 1701 switch (command) 1702 { 1703 case DBUS_AUTH_COMMAND_DATA: 1704 return process_data (auth, args, auth->mech->client_data_func); 1705 1706 case DBUS_AUTH_COMMAND_REJECTED: 1707 return process_rejected (auth, args); 1708 1709 case DBUS_AUTH_COMMAND_OK: 1710 return send_begin (auth); 1711 1712 case DBUS_AUTH_COMMAND_ERROR: 1713 return send_cancel (auth); 1714 1715 case DBUS_AUTH_COMMAND_AUTH: 1716 case DBUS_AUTH_COMMAND_CANCEL: 1717 case DBUS_AUTH_COMMAND_BEGIN: 1718 case DBUS_AUTH_COMMAND_UNKNOWN: 1719 default: 1720 return send_error (auth, "Unknown command"); 1721 } 1722} 1723 1724static dbus_bool_t 1725handle_client_state_waiting_for_ok (DBusAuth *auth, 1726 DBusAuthCommand command, 1727 const DBusString *args) 1728{ 1729 switch (command) 1730 { 1731 case DBUS_AUTH_COMMAND_REJECTED: 1732 return process_rejected (auth, args); 1733 1734 case DBUS_AUTH_COMMAND_OK: 1735 return send_begin (auth); 1736 1737 case DBUS_AUTH_COMMAND_DATA: 1738 case DBUS_AUTH_COMMAND_ERROR: 1739 return send_cancel (auth); 1740 1741 case DBUS_AUTH_COMMAND_AUTH: 1742 case DBUS_AUTH_COMMAND_CANCEL: 1743 case DBUS_AUTH_COMMAND_BEGIN: 1744 case DBUS_AUTH_COMMAND_UNKNOWN: 1745 default: 1746 return send_error (auth, "Unknown command"); 1747 } 1748} 1749 1750static dbus_bool_t 1751handle_client_state_waiting_for_reject (DBusAuth *auth, 1752 DBusAuthCommand command, 1753 const DBusString *args) 1754{ 1755 switch (command) 1756 { 1757 case DBUS_AUTH_COMMAND_REJECTED: 1758 return process_rejected (auth, args); 1759 1760 case DBUS_AUTH_COMMAND_AUTH: 1761 case DBUS_AUTH_COMMAND_CANCEL: 1762 case DBUS_AUTH_COMMAND_DATA: 1763 case DBUS_AUTH_COMMAND_BEGIN: 1764 case DBUS_AUTH_COMMAND_OK: 1765 case DBUS_AUTH_COMMAND_ERROR: 1766 case DBUS_AUTH_COMMAND_UNKNOWN: 1767 default: 1768 goto_state (auth, &common_state_need_disconnect); 1769 return TRUE; 1770 } 1771} 1772 1773/** 1774 * Mapping from command name to enum 1775 */ 1776typedef struct { 1777 const char *name; /**< Name of the command */ 1778 DBusAuthCommand command; /**< Corresponding enum */ 1779} DBusAuthCommandName; 1780 1781static DBusAuthCommandName auth_command_names[] = { 1782 { "AUTH", DBUS_AUTH_COMMAND_AUTH }, 1783 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, 1784 { "DATA", DBUS_AUTH_COMMAND_DATA }, 1785 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, 1786 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, 1787 { "OK", DBUS_AUTH_COMMAND_OK }, 1788 { "ERROR", DBUS_AUTH_COMMAND_ERROR } 1789}; 1790 1791static DBusAuthCommand 1792lookup_command_from_name (DBusString *command) 1793{ 1794 int i; 1795 1796 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) 1797 { 1798 if (_dbus_string_equal_c_str (command, 1799 auth_command_names[i].name)) 1800 return auth_command_names[i].command; 1801 } 1802 1803 return DBUS_AUTH_COMMAND_UNKNOWN; 1804} 1805 1806static void 1807goto_state (DBusAuth *auth, const DBusAuthStateData *state) 1808{ 1809 _dbus_verbose ("%s: going from state %s to state %s\n", 1810 DBUS_AUTH_NAME (auth), 1811 auth->state->name, 1812 state->name); 1813 1814 auth->state = state; 1815} 1816 1817/* returns whether to call it again right away */ 1818static dbus_bool_t 1819process_command (DBusAuth *auth) 1820{ 1821 DBusAuthCommand command; 1822 DBusString line; 1823 DBusString args; 1824 int eol; 1825 int i, j; 1826 dbus_bool_t retval; 1827 1828 /* _dbus_verbose ("%s: trying process_command()\n"); */ 1829 1830 retval = FALSE; 1831 1832 eol = 0; 1833 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 1834 return FALSE; 1835 1836 if (!_dbus_string_init (&line)) 1837 { 1838 auth->needed_memory = TRUE; 1839 return FALSE; 1840 } 1841 1842 if (!_dbus_string_init (&args)) 1843 { 1844 _dbus_string_free (&line); 1845 auth->needed_memory = TRUE; 1846 return FALSE; 1847 } 1848 1849 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) 1850 goto out; 1851 1852 if (!_dbus_string_validate_ascii (&line, 0, 1853 _dbus_string_get_length (&line))) 1854 { 1855 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", 1856 DBUS_AUTH_NAME (auth)); 1857 if (!send_error (auth, "Command contained non-ASCII")) 1858 goto out; 1859 else 1860 goto next_command; 1861 } 1862 1863 _dbus_verbose ("%s: got command \"%s\"\n", 1864 DBUS_AUTH_NAME (auth), 1865 _dbus_string_get_const_data (&line)); 1866 1867 _dbus_string_find_blank (&line, 0, &i); 1868 _dbus_string_skip_blank (&line, i, &j); 1869 1870 if (j > i) 1871 _dbus_string_delete (&line, i, j - i); 1872 1873 if (!_dbus_string_move (&line, i, &args, 0)) 1874 goto out; 1875 1876 command = lookup_command_from_name (&line); 1877 if (!(* auth->state->handler) (auth, command, &args)) 1878 goto out; 1879 1880 next_command: 1881 1882 /* We've succeeded in processing the whole command so drop it out 1883 * of the incoming buffer and return TRUE to try another command. 1884 */ 1885 1886 _dbus_string_delete (&auth->incoming, 0, eol); 1887 1888 /* kill the \r\n */ 1889 _dbus_string_delete (&auth->incoming, 0, 2); 1890 1891 retval = TRUE; 1892 1893 out: 1894 _dbus_string_free (&args); 1895 _dbus_string_free (&line); 1896 1897 if (!retval) 1898 auth->needed_memory = TRUE; 1899 else 1900 auth->needed_memory = FALSE; 1901 1902 return retval; 1903} 1904 1905 1906/** @} */ 1907 1908/** 1909 * @addtogroup DBusAuth 1910 * @{ 1911 */ 1912 1913/** 1914 * Creates a new auth conversation object for the server side. 1915 * See doc/dbus-sasl-profile.txt for full details on what 1916 * this object does. 1917 * 1918 * @returns the new object or #NULL if no memory 1919 */ 1920DBusAuth* 1921_dbus_auth_server_new (void) 1922{ 1923 DBusAuth *auth; 1924 DBusAuthServer *server_auth; 1925 1926 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 1927 if (auth == NULL) 1928 return NULL; 1929 1930 auth->side = auth_side_server; 1931 auth->state = &server_state_waiting_for_auth; 1932 1933 server_auth = DBUS_AUTH_SERVER (auth); 1934 1935 /* perhaps this should be per-mechanism with a lower 1936 * max 1937 */ 1938 server_auth->failures = 0; 1939 server_auth->max_failures = 6; 1940 1941 return auth; 1942} 1943 1944/** 1945 * Creates a new auth conversation object for the client side. 1946 * See doc/dbus-sasl-profile.txt for full details on what 1947 * this object does. 1948 * 1949 * @returns the new object or #NULL if no memory 1950 */ 1951DBusAuth* 1952_dbus_auth_client_new (void) 1953{ 1954 DBusAuth *auth; 1955 1956 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 1957 if (auth == NULL) 1958 return NULL; 1959 1960 auth->side = auth_side_client; 1961 auth->state = &client_state_need_send_auth; 1962 1963 /* Start the auth conversation by sending AUTH for our default 1964 * mechanism */ 1965 if (!send_auth (auth, &all_mechanisms[0])) 1966 { 1967 _dbus_auth_unref (auth); 1968 return NULL; 1969 } 1970 1971 return auth; 1972} 1973 1974/** 1975 * Increments the refcount of an auth object. 1976 * 1977 * @param auth the auth conversation 1978 * @returns the auth conversation 1979 */ 1980DBusAuth * 1981_dbus_auth_ref (DBusAuth *auth) 1982{ 1983 _dbus_assert (auth != NULL); 1984 1985 auth->refcount += 1; 1986 1987 return auth; 1988} 1989 1990/** 1991 * Decrements the refcount of an auth object. 1992 * 1993 * @param auth the auth conversation 1994 */ 1995void 1996_dbus_auth_unref (DBusAuth *auth) 1997{ 1998 _dbus_assert (auth != NULL); 1999 _dbus_assert (auth->refcount > 0); 2000 2001 auth->refcount -= 1; 2002 if (auth->refcount == 0) 2003 { 2004 shutdown_mech (auth); 2005 2006 if (DBUS_AUTH_IS_CLIENT (auth)) 2007 { 2008 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 2009 } 2010 2011 if (auth->keyring) 2012 _dbus_keyring_unref (auth->keyring); 2013 2014 _dbus_string_free (&auth->context); 2015 _dbus_string_free (&auth->challenge); 2016 _dbus_string_free (&auth->identity); 2017 _dbus_string_free (&auth->incoming); 2018 _dbus_string_free (&auth->outgoing); 2019 2020 dbus_free_string_array (auth->allowed_mechs); 2021 2022 dbus_free (auth); 2023 } 2024} 2025 2026/** 2027 * Sets an array of authentication mechanism names 2028 * that we are willing to use. 2029 * 2030 * @param auth the auth conversation 2031 * @param mechanisms #NULL-terminated array of mechanism names 2032 * @returns #FALSE if no memory 2033 */ 2034dbus_bool_t 2035_dbus_auth_set_mechanisms (DBusAuth *auth, 2036 const char **mechanisms) 2037{ 2038 char **copy; 2039 2040 if (mechanisms != NULL) 2041 { 2042 copy = _dbus_dup_string_array (mechanisms); 2043 if (copy == NULL) 2044 return FALSE; 2045 } 2046 else 2047 copy = NULL; 2048 2049 dbus_free_string_array (auth->allowed_mechs); 2050 2051 auth->allowed_mechs = copy; 2052 2053 return TRUE; 2054} 2055 2056/** 2057 * @param auth the auth conversation object 2058 * @returns #TRUE if we're in a final state 2059 */ 2060#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) 2061 2062/** 2063 * Analyzes buffered input and moves the auth conversation forward, 2064 * returning the new state of the auth conversation. 2065 * 2066 * @param auth the auth conversation 2067 * @returns the new state 2068 */ 2069DBusAuthState 2070_dbus_auth_do_work (DBusAuth *auth) 2071{ 2072 auth->needed_memory = FALSE; 2073 2074 /* Max amount we'll buffer up before deciding someone's on crack */ 2075#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 2076 2077 do 2078 { 2079 if (DBUS_AUTH_IN_END_STATE (auth)) 2080 break; 2081 2082 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 2083 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 2084 { 2085 goto_state (auth, &common_state_need_disconnect); 2086 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", 2087 DBUS_AUTH_NAME (auth)); 2088 break; 2089 } 2090 } 2091 while (process_command (auth)); 2092 2093 if (auth->needed_memory) 2094 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 2095 else if (_dbus_string_get_length (&auth->outgoing) > 0) 2096 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 2097 else if (auth->state == &common_state_need_disconnect) 2098 return DBUS_AUTH_STATE_NEED_DISCONNECT; 2099 else if (auth->state == &common_state_authenticated) 2100 return DBUS_AUTH_STATE_AUTHENTICATED; 2101 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 2102} 2103 2104/** 2105 * Gets bytes that need to be sent to the peer we're conversing with. 2106 * After writing some bytes, _dbus_auth_bytes_sent() must be called 2107 * to notify the auth object that they were written. 2108 * 2109 * @param auth the auth conversation 2110 * @param str return location for a ref to the buffer to send 2111 * @returns #FALSE if nothing to send 2112 */ 2113dbus_bool_t 2114_dbus_auth_get_bytes_to_send (DBusAuth *auth, 2115 const DBusString **str) 2116{ 2117 _dbus_assert (auth != NULL); 2118 _dbus_assert (str != NULL); 2119 2120 *str = NULL; 2121 2122 if (_dbus_string_get_length (&auth->outgoing) == 0) 2123 return FALSE; 2124 2125 *str = &auth->outgoing; 2126 2127 return TRUE; 2128} 2129 2130/** 2131 * Notifies the auth conversation object that 2132 * the given number of bytes of the outgoing buffer 2133 * have been written out. 2134 * 2135 * @param auth the auth conversation 2136 * @param bytes_sent number of bytes written out 2137 */ 2138void 2139_dbus_auth_bytes_sent (DBusAuth *auth, 2140 int bytes_sent) 2141{ 2142 _dbus_verbose ("%s: Sent %d bytes of: %s\n", 2143 DBUS_AUTH_NAME (auth), 2144 bytes_sent, 2145 _dbus_string_get_const_data (&auth->outgoing)); 2146 2147 _dbus_string_delete (&auth->outgoing, 2148 0, bytes_sent); 2149} 2150 2151/** 2152 * Get a buffer to be used for reading bytes from the peer we're conversing 2153 * with. Bytes should be appended to this buffer. 2154 * 2155 * @param auth the auth conversation 2156 * @param buffer return location for buffer to append bytes to 2157 */ 2158void 2159_dbus_auth_get_buffer (DBusAuth *auth, 2160 DBusString **buffer) 2161{ 2162 _dbus_assert (auth != NULL); 2163 _dbus_assert (!auth->buffer_outstanding); 2164 2165 *buffer = &auth->incoming; 2166 2167 auth->buffer_outstanding = TRUE; 2168} 2169 2170/** 2171 * Returns a buffer with new data read into it. 2172 * 2173 * @param auth the auth conversation 2174 * @param buffer the buffer being returned 2175 * @param bytes_read number of new bytes added 2176 */ 2177void 2178_dbus_auth_return_buffer (DBusAuth *auth, 2179 DBusString *buffer, 2180 int bytes_read) 2181{ 2182 _dbus_assert (buffer == &auth->incoming); 2183 _dbus_assert (auth->buffer_outstanding); 2184 2185 auth->buffer_outstanding = FALSE; 2186} 2187 2188/** 2189 * Returns leftover bytes that were not used as part of the auth 2190 * conversation. These bytes will be part of the message stream 2191 * instead. This function may not be called until authentication has 2192 * succeeded. 2193 * 2194 * @param auth the auth conversation 2195 * @param str return location for pointer to string of unused bytes 2196 */ 2197void 2198_dbus_auth_get_unused_bytes (DBusAuth *auth, 2199 const DBusString **str) 2200{ 2201 if (!DBUS_AUTH_IN_END_STATE (auth)) 2202 return; 2203 2204 *str = &auth->incoming; 2205} 2206 2207 2208/** 2209 * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes() 2210 * after we've gotten them and successfully moved them elsewhere. 2211 * 2212 * @param auth the auth conversation 2213 */ 2214void 2215_dbus_auth_delete_unused_bytes (DBusAuth *auth) 2216{ 2217 if (!DBUS_AUTH_IN_END_STATE (auth)) 2218 return; 2219 2220 _dbus_string_set_length (&auth->incoming, 0); 2221} 2222 2223/** 2224 * Called post-authentication, indicates whether we need to encode 2225 * the message stream with _dbus_auth_encode_data() prior to 2226 * sending it to the peer. 2227 * 2228 * @param auth the auth conversation 2229 * @returns #TRUE if we need to encode the stream 2230 */ 2231dbus_bool_t 2232_dbus_auth_needs_encoding (DBusAuth *auth) 2233{ 2234 if (auth->state != &common_state_authenticated) 2235 return FALSE; 2236 2237 if (auth->mech != NULL) 2238 { 2239 if (DBUS_AUTH_IS_CLIENT (auth)) 2240 return auth->mech->client_encode_func != NULL; 2241 else 2242 return auth->mech->server_encode_func != NULL; 2243 } 2244 else 2245 return FALSE; 2246} 2247 2248/** 2249 * Called post-authentication, encodes a block of bytes for sending to 2250 * the peer. If no encoding was negotiated, just copies the bytes 2251 * (you can avoid this by checking _dbus_auth_needs_encoding()). 2252 * 2253 * @param auth the auth conversation 2254 * @param plaintext the plain text data 2255 * @param encoded initialized string to where encoded data is appended 2256 * @returns #TRUE if we had enough memory and successfully encoded 2257 */ 2258dbus_bool_t 2259_dbus_auth_encode_data (DBusAuth *auth, 2260 const DBusString *plaintext, 2261 DBusString *encoded) 2262{ 2263 _dbus_assert (plaintext != encoded); 2264 2265 if (auth->state != &common_state_authenticated) 2266 return FALSE; 2267 2268 if (_dbus_auth_needs_encoding (auth)) 2269 { 2270 if (DBUS_AUTH_IS_CLIENT (auth)) 2271 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 2272 else 2273 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 2274 } 2275 else 2276 { 2277 return _dbus_string_copy (plaintext, 0, encoded, 2278 _dbus_string_get_length (encoded)); 2279 } 2280} 2281 2282/** 2283 * Called post-authentication, indicates whether we need to decode 2284 * the message stream with _dbus_auth_decode_data() after 2285 * receiving it from the peer. 2286 * 2287 * @param auth the auth conversation 2288 * @returns #TRUE if we need to encode the stream 2289 */ 2290dbus_bool_t 2291_dbus_auth_needs_decoding (DBusAuth *auth) 2292{ 2293 if (auth->state != &common_state_authenticated) 2294 return FALSE; 2295 2296 if (auth->mech != NULL) 2297 { 2298 if (DBUS_AUTH_IS_CLIENT (auth)) 2299 return auth->mech->client_decode_func != NULL; 2300 else 2301 return auth->mech->server_decode_func != NULL; 2302 } 2303 else 2304 return FALSE; 2305} 2306 2307 2308/** 2309 * Called post-authentication, decodes a block of bytes received from 2310 * the peer. If no encoding was negotiated, just copies the bytes (you 2311 * can avoid this by checking _dbus_auth_needs_decoding()). 2312 * 2313 * @todo We need to be able to distinguish "out of memory" error 2314 * from "the data is hosed" error. 2315 * 2316 * @param auth the auth conversation 2317 * @param encoded the encoded data 2318 * @param plaintext initialized string where decoded data is appended 2319 * @returns #TRUE if we had enough memory and successfully decoded 2320 */ 2321dbus_bool_t 2322_dbus_auth_decode_data (DBusAuth *auth, 2323 const DBusString *encoded, 2324 DBusString *plaintext) 2325{ 2326 _dbus_assert (plaintext != encoded); 2327 2328 if (auth->state != &common_state_authenticated) 2329 return FALSE; 2330 2331 if (_dbus_auth_needs_decoding (auth)) 2332 { 2333 if (DBUS_AUTH_IS_CLIENT (auth)) 2334 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 2335 else 2336 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 2337 } 2338 else 2339 { 2340 return _dbus_string_copy (encoded, 0, plaintext, 2341 _dbus_string_get_length (plaintext)); 2342 } 2343} 2344 2345/** 2346 * Sets credentials received via reliable means from the operating 2347 * system. 2348 * 2349 * @param auth the auth conversation 2350 * @param credentials the credentials received 2351 */ 2352void 2353_dbus_auth_set_credentials (DBusAuth *auth, 2354 const DBusCredentials *credentials) 2355{ 2356 auth->credentials = *credentials; 2357} 2358 2359/** 2360 * Gets the identity we authorized the client as. Apps may have 2361 * different policies as to what identities they allow. 2362 * 2363 * @param auth the auth conversation 2364 * @param credentials the credentials we've authorized 2365 */ 2366void 2367_dbus_auth_get_identity (DBusAuth *auth, 2368 DBusCredentials *credentials) 2369{ 2370 if (auth->state == &common_state_authenticated) 2371 *credentials = auth->authorized_identity; 2372 else 2373 _dbus_credentials_clear (credentials); 2374} 2375 2376/** 2377 * Sets the "authentication context" which scopes cookies 2378 * with the DBUS_COOKIE_SHA1 auth mechanism for example. 2379 * 2380 * @param auth the auth conversation 2381 * @param context the context 2382 * @returns #FALSE if no memory 2383 */ 2384dbus_bool_t 2385_dbus_auth_set_context (DBusAuth *auth, 2386 const DBusString *context) 2387{ 2388 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), 2389 &auth->context, 0, _dbus_string_get_length (context)); 2390} 2391 2392/** @} */ 2393 2394#ifdef DBUS_BUILD_TESTS 2395#include "dbus-test.h" 2396#include "dbus-auth-script.h" 2397#include <stdio.h> 2398 2399static dbus_bool_t 2400process_test_subdir (const DBusString *test_base_dir, 2401 const char *subdir) 2402{ 2403 DBusString test_directory; 2404 DBusString filename; 2405 DBusDirIter *dir; 2406 dbus_bool_t retval; 2407 DBusError error; 2408 2409 retval = FALSE; 2410 dir = NULL; 2411 2412 if (!_dbus_string_init (&test_directory)) 2413 _dbus_assert_not_reached ("didn't allocate test_directory\n"); 2414 2415 _dbus_string_init_const (&filename, subdir); 2416 2417 if (!_dbus_string_copy (test_base_dir, 0, 2418 &test_directory, 0)) 2419 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); 2420 2421 if (!_dbus_concat_dir_and_file (&test_directory, &filename)) 2422 _dbus_assert_not_reached ("couldn't allocate full path"); 2423 2424 _dbus_string_free (&filename); 2425 if (!_dbus_string_init (&filename)) 2426 _dbus_assert_not_reached ("didn't allocate filename string\n"); 2427 2428 dbus_error_init (&error); 2429 dir = _dbus_directory_open (&test_directory, &error); 2430 if (dir == NULL) 2431 { 2432 _dbus_warn ("Could not open %s: %s\n", 2433 _dbus_string_get_const_data (&test_directory), 2434 error.message); 2435 dbus_error_free (&error); 2436 goto failed; 2437 } 2438 2439 printf ("Testing %s:\n", subdir); 2440 2441 next: 2442 while (_dbus_directory_get_next_file (dir, &filename, &error)) 2443 { 2444 DBusString full_path; 2445 2446 if (!_dbus_string_init (&full_path)) 2447 _dbus_assert_not_reached ("couldn't init string"); 2448 2449 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) 2450 _dbus_assert_not_reached ("couldn't copy dir to full_path"); 2451 2452 if (!_dbus_concat_dir_and_file (&full_path, &filename)) 2453 _dbus_assert_not_reached ("couldn't concat file to dir"); 2454 2455 if (!_dbus_string_ends_with_c_str (&filename, ".auth-script")) 2456 { 2457 _dbus_verbose ("Skipping non-.auth-script file %s\n", 2458 _dbus_string_get_const_data (&filename)); 2459 _dbus_string_free (&full_path); 2460 goto next; 2461 } 2462 2463 printf (" %s\n", _dbus_string_get_const_data (&filename)); 2464 2465 if (!_dbus_auth_script_run (&full_path)) 2466 { 2467 _dbus_string_free (&full_path); 2468 goto failed; 2469 } 2470 else 2471 _dbus_string_free (&full_path); 2472 } 2473 2474 if (dbus_error_is_set (&error)) 2475 { 2476 _dbus_warn ("Could not get next file in %s: %s\n", 2477 _dbus_string_get_const_data (&test_directory), error.message); 2478 dbus_error_free (&error); 2479 goto failed; 2480 } 2481 2482 retval = TRUE; 2483 2484 failed: 2485 2486 if (dir) 2487 _dbus_directory_close (dir); 2488 _dbus_string_free (&test_directory); 2489 _dbus_string_free (&filename); 2490 2491 return retval; 2492} 2493 2494static dbus_bool_t 2495process_test_dirs (const char *test_data_dir) 2496{ 2497 DBusString test_directory; 2498 dbus_bool_t retval; 2499 2500 retval = FALSE; 2501 2502 _dbus_string_init_const (&test_directory, test_data_dir); 2503 2504 if (!process_test_subdir (&test_directory, "auth")) 2505 goto failed; 2506 2507 retval = TRUE; 2508 2509 failed: 2510 2511 _dbus_string_free (&test_directory); 2512 2513 return retval; 2514} 2515 2516dbus_bool_t 2517_dbus_auth_test (const char *test_data_dir) 2518{ 2519 2520 if (test_data_dir == NULL) 2521 return TRUE; 2522 2523 if (!process_test_dirs (test_data_dir)) 2524 return FALSE; 2525 2526 return TRUE; 2527} 2528 2529#endif /* DBUS_BUILD_TESTS */ 2530