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