dbus-auth.c revision e7c0d217795f4e8eb618f82b9b3e52807436c8f1
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/* 428 * DBUS_COOKIE_SHA1 mechanism 429 */ 430 431/* Returns TRUE but with an empty string hash if the 432 * cookie_id isn't known. As with all this code 433 * TRUE just means we had enough memory. 434 */ 435static dbus_bool_t 436sha1_compute_hash (DBusAuth *auth, 437 int cookie_id, 438 const DBusString *server_challenge, 439 const DBusString *client_challenge, 440 DBusString *hash) 441{ 442 DBusString cookie; 443 DBusString to_hash; 444 dbus_bool_t retval; 445 446 _dbus_assert (auth->keyring != NULL); 447 448 retval = FALSE; 449 450 if (!_dbus_string_init (&cookie)) 451 return FALSE; 452 453 if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id, 454 &cookie)) 455 goto out_0; 456 457 if (_dbus_string_get_length (&cookie) == 0) 458 { 459 retval = TRUE; 460 goto out_0; 461 } 462 463 if (!_dbus_string_init (&to_hash)) 464 goto out_0; 465 466 if (!_dbus_string_copy (server_challenge, 0, 467 &to_hash, _dbus_string_get_length (&to_hash))) 468 goto out_1; 469 470 if (!_dbus_string_append (&to_hash, ":")) 471 goto out_1; 472 473 if (!_dbus_string_copy (client_challenge, 0, 474 &to_hash, _dbus_string_get_length (&to_hash))) 475 goto out_1; 476 477 if (!_dbus_string_append (&to_hash, ":")) 478 goto out_1; 479 480 if (!_dbus_string_copy (&cookie, 0, 481 &to_hash, _dbus_string_get_length (&to_hash))) 482 goto out_1; 483 484 if (!_dbus_sha_compute (&to_hash, hash)) 485 goto out_1; 486 487 retval = TRUE; 488 489 out_1: 490 _dbus_string_zero (&to_hash); 491 _dbus_string_free (&to_hash); 492 out_0: 493 _dbus_string_zero (&cookie); 494 _dbus_string_free (&cookie); 495 return retval; 496} 497 498/** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of 499 * entropy, we use 128. This is the number of bytes in the random 500 * challenge. 501 */ 502#define N_CHALLENGE_BYTES (128/8) 503 504static dbus_bool_t 505sha1_handle_first_client_response (DBusAuth *auth, 506 const DBusString *data) 507{ 508 /* We haven't sent a challenge yet, we're expecting a desired 509 * username from the client. 510 */ 511 DBusString tmp; 512 DBusString tmp2; 513 dbus_bool_t retval; 514 DBusError error; 515 516 retval = FALSE; 517 518 _dbus_string_set_length (&auth->challenge, 0); 519 520 if (_dbus_string_get_length (data) > 0) 521 { 522 if (_dbus_string_get_length (&auth->identity) > 0) 523 { 524 /* Tried to send two auth identities, wtf */ 525 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 526 DBUS_AUTH_NAME (auth)); 527 return send_rejected (auth); 528 } 529 else 530 { 531 /* this is our auth identity */ 532 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 533 return FALSE; 534 } 535 } 536 537 if (!_dbus_credentials_add_from_user (auth->desired_identity, data)) 538 { 539 _dbus_verbose ("%s: Did not get a valid username from client\n", 540 DBUS_AUTH_NAME (auth)); 541 return send_rejected (auth); 542 } 543 544 if (!_dbus_string_init (&tmp)) 545 return FALSE; 546 547 if (!_dbus_string_init (&tmp2)) 548 { 549 _dbus_string_free (&tmp); 550 return FALSE; 551 } 552 553 /* we cache the keyring for speed, so here we drop it if it's the 554 * wrong one. FIXME caching the keyring here is useless since we use 555 * a different DBusAuth for every connection. 556 */ 557 if (auth->keyring && 558 !_dbus_keyring_is_for_credentials (auth->keyring, 559 auth->desired_identity)) 560 { 561 _dbus_keyring_unref (auth->keyring); 562 auth->keyring = NULL; 563 } 564 565 if (auth->keyring == NULL) 566 { 567 dbus_error_init (&error); 568 auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity, 569 &auth->context, 570 &error); 571 572 if (auth->keyring == NULL) 573 { 574 if (dbus_error_has_name (&error, 575 DBUS_ERROR_NO_MEMORY)) 576 { 577 dbus_error_free (&error); 578 goto out; 579 } 580 else 581 { 582 _DBUS_ASSERT_ERROR_IS_SET (&error); 583 _dbus_verbose ("%s: Error loading keyring: %s\n", 584 DBUS_AUTH_NAME (auth), error.message); 585 if (send_rejected (auth)) 586 retval = TRUE; /* retval is only about mem */ 587 dbus_error_free (&error); 588 goto out; 589 } 590 } 591 else 592 { 593 _dbus_assert (!dbus_error_is_set (&error)); 594 } 595 } 596 597 _dbus_assert (auth->keyring != NULL); 598 599 dbus_error_init (&error); 600 auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); 601 if (auth->cookie_id < 0) 602 { 603 _DBUS_ASSERT_ERROR_IS_SET (&error); 604 _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n", 605 DBUS_AUTH_NAME (auth), error.message); 606 if (send_rejected (auth)) 607 retval = TRUE; 608 dbus_error_free (&error); 609 goto out; 610 } 611 else 612 { 613 _dbus_assert (!dbus_error_is_set (&error)); 614 } 615 616 if (!_dbus_string_copy (&auth->context, 0, 617 &tmp2, _dbus_string_get_length (&tmp2))) 618 goto out; 619 620 if (!_dbus_string_append (&tmp2, " ")) 621 goto out; 622 623 if (!_dbus_string_append_int (&tmp2, auth->cookie_id)) 624 goto out; 625 626 if (!_dbus_string_append (&tmp2, " ")) 627 goto out; 628 629 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) 630 goto out; 631 632 _dbus_string_set_length (&auth->challenge, 0); 633 if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0)) 634 goto out; 635 636 if (!_dbus_string_hex_encode (&tmp, 0, &tmp2, 637 _dbus_string_get_length (&tmp2))) 638 goto out; 639 640 if (!send_data (auth, &tmp2)) 641 goto out; 642 643 goto_state (auth, &server_state_waiting_for_data); 644 retval = TRUE; 645 646 out: 647 _dbus_string_zero (&tmp); 648 _dbus_string_free (&tmp); 649 _dbus_string_zero (&tmp2); 650 _dbus_string_free (&tmp2); 651 652 return retval; 653} 654 655static dbus_bool_t 656sha1_handle_second_client_response (DBusAuth *auth, 657 const DBusString *data) 658{ 659 /* We are expecting a response which is the hex-encoded client 660 * challenge, space, then SHA-1 hash of the concatenation of our 661 * challenge, ":", client challenge, ":", secret key, all 662 * hex-encoded. 663 */ 664 int i; 665 DBusString client_challenge; 666 DBusString client_hash; 667 dbus_bool_t retval; 668 DBusString correct_hash; 669 670 retval = FALSE; 671 672 if (!_dbus_string_find_blank (data, 0, &i)) 673 { 674 _dbus_verbose ("%s: no space separator in client response\n", 675 DBUS_AUTH_NAME (auth)); 676 return send_rejected (auth); 677 } 678 679 if (!_dbus_string_init (&client_challenge)) 680 goto out_0; 681 682 if (!_dbus_string_init (&client_hash)) 683 goto out_1; 684 685 if (!_dbus_string_copy_len (data, 0, i, &client_challenge, 686 0)) 687 goto out_2; 688 689 _dbus_string_skip_blank (data, i, &i); 690 691 if (!_dbus_string_copy_len (data, i, 692 _dbus_string_get_length (data) - i, 693 &client_hash, 694 0)) 695 goto out_2; 696 697 if (_dbus_string_get_length (&client_challenge) == 0 || 698 _dbus_string_get_length (&client_hash) == 0) 699 { 700 _dbus_verbose ("%s: zero-length client challenge or hash\n", 701 DBUS_AUTH_NAME (auth)); 702 if (send_rejected (auth)) 703 retval = TRUE; 704 goto out_2; 705 } 706 707 if (!_dbus_string_init (&correct_hash)) 708 goto out_2; 709 710 if (!sha1_compute_hash (auth, auth->cookie_id, 711 &auth->challenge, 712 &client_challenge, 713 &correct_hash)) 714 goto out_3; 715 716 /* if cookie_id was invalid, then we get an empty hash */ 717 if (_dbus_string_get_length (&correct_hash) == 0) 718 { 719 if (send_rejected (auth)) 720 retval = TRUE; 721 goto out_3; 722 } 723 724 if (!_dbus_string_equal (&client_hash, &correct_hash)) 725 { 726 if (send_rejected (auth)) 727 retval = TRUE; 728 goto out_3; 729 } 730 731 if (!_dbus_credentials_add_credentials (auth->authorized_identity, 732 auth->desired_identity)) 733 goto out_3; 734 735 /* Copy process ID from the socket credentials if it's there 736 */ 737 if (!_dbus_credentials_add_credential (auth->authorized_identity, 738 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 739 auth->credentials)) 740 goto out_3; 741 742 if (!send_ok (auth)) 743 goto out_3; 744 745 _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n", 746 DBUS_AUTH_NAME (auth)); 747 748 retval = TRUE; 749 750 out_3: 751 _dbus_string_zero (&correct_hash); 752 _dbus_string_free (&correct_hash); 753 out_2: 754 _dbus_string_zero (&client_hash); 755 _dbus_string_free (&client_hash); 756 out_1: 757 _dbus_string_free (&client_challenge); 758 out_0: 759 return retval; 760} 761 762static dbus_bool_t 763handle_server_data_cookie_sha1_mech (DBusAuth *auth, 764 const DBusString *data) 765{ 766 if (auth->cookie_id < 0) 767 return sha1_handle_first_client_response (auth, data); 768 else 769 return sha1_handle_second_client_response (auth, data); 770} 771 772static void 773handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth) 774{ 775 auth->cookie_id = -1; 776 _dbus_string_set_length (&auth->challenge, 0); 777} 778 779static dbus_bool_t 780handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth, 781 DBusString *response) 782{ 783 DBusString username; 784 dbus_bool_t retval; 785 786 retval = FALSE; 787 788 if (!_dbus_string_init (&username)) 789 return FALSE; 790 791 if (!_dbus_append_user_from_current_process (&username)) 792 goto out_0; 793 794 if (!_dbus_string_hex_encode (&username, 0, 795 response, 796 _dbus_string_get_length (response))) 797 goto out_0; 798 799 retval = TRUE; 800 801 out_0: 802 _dbus_string_free (&username); 803 804 return retval; 805} 806 807static dbus_bool_t 808handle_client_data_cookie_sha1_mech (DBusAuth *auth, 809 const DBusString *data) 810{ 811 /* The data we get from the server should be the cookie context 812 * name, the cookie ID, and the server challenge, separated by 813 * spaces. We send back our challenge string and the correct hash. 814 */ 815 dbus_bool_t retval; 816 DBusString context; 817 DBusString cookie_id_str; 818 DBusString server_challenge; 819 DBusString client_challenge; 820 DBusString correct_hash; 821 DBusString tmp; 822 int i, j; 823 long val; 824 825 retval = FALSE; 826 827 if (!_dbus_string_find_blank (data, 0, &i)) 828 { 829 if (send_error (auth, 830 "Server did not send context/ID/challenge properly")) 831 retval = TRUE; 832 goto out_0; 833 } 834 835 if (!_dbus_string_init (&context)) 836 goto out_0; 837 838 if (!_dbus_string_copy_len (data, 0, i, 839 &context, 0)) 840 goto out_1; 841 842 _dbus_string_skip_blank (data, i, &i); 843 if (!_dbus_string_find_blank (data, i, &j)) 844 { 845 if (send_error (auth, 846 "Server did not send context/ID/challenge properly")) 847 retval = TRUE; 848 goto out_1; 849 } 850 851 if (!_dbus_string_init (&cookie_id_str)) 852 goto out_1; 853 854 if (!_dbus_string_copy_len (data, i, j - i, 855 &cookie_id_str, 0)) 856 goto out_2; 857 858 if (!_dbus_string_init (&server_challenge)) 859 goto out_2; 860 861 i = j; 862 _dbus_string_skip_blank (data, i, &i); 863 j = _dbus_string_get_length (data); 864 865 if (!_dbus_string_copy_len (data, i, j - i, 866 &server_challenge, 0)) 867 goto out_3; 868 869 if (!_dbus_keyring_validate_context (&context)) 870 { 871 if (send_error (auth, "Server sent invalid cookie context")) 872 retval = TRUE; 873 goto out_3; 874 } 875 876 if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL)) 877 { 878 if (send_error (auth, "Could not parse cookie ID as an integer")) 879 retval = TRUE; 880 goto out_3; 881 } 882 883 if (_dbus_string_get_length (&server_challenge) == 0) 884 { 885 if (send_error (auth, "Empty server challenge string")) 886 retval = TRUE; 887 goto out_3; 888 } 889 890 if (auth->keyring == NULL) 891 { 892 DBusError error; 893 894 dbus_error_init (&error); 895 auth->keyring = _dbus_keyring_new_for_credentials (NULL, 896 &context, 897 &error); 898 899 if (auth->keyring == NULL) 900 { 901 if (dbus_error_has_name (&error, 902 DBUS_ERROR_NO_MEMORY)) 903 { 904 dbus_error_free (&error); 905 goto out_3; 906 } 907 else 908 { 909 _DBUS_ASSERT_ERROR_IS_SET (&error); 910 911 _dbus_verbose ("%s: Error loading keyring: %s\n", 912 DBUS_AUTH_NAME (auth), error.message); 913 914 if (send_error (auth, "Could not load cookie file")) 915 retval = TRUE; /* retval is only about mem */ 916 917 dbus_error_free (&error); 918 goto out_3; 919 } 920 } 921 else 922 { 923 _dbus_assert (!dbus_error_is_set (&error)); 924 } 925 } 926 927 _dbus_assert (auth->keyring != NULL); 928 929 if (!_dbus_string_init (&tmp)) 930 goto out_3; 931 932 if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) 933 goto out_4; 934 935 if (!_dbus_string_init (&client_challenge)) 936 goto out_4; 937 938 if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0)) 939 goto out_5; 940 941 if (!_dbus_string_init (&correct_hash)) 942 goto out_5; 943 944 if (!sha1_compute_hash (auth, val, 945 &server_challenge, 946 &client_challenge, 947 &correct_hash)) 948 goto out_6; 949 950 if (_dbus_string_get_length (&correct_hash) == 0) 951 { 952 /* couldn't find the cookie ID or something */ 953 if (send_error (auth, "Don't have the requested cookie ID")) 954 retval = TRUE; 955 goto out_6; 956 } 957 958 _dbus_string_set_length (&tmp, 0); 959 960 if (!_dbus_string_copy (&client_challenge, 0, &tmp, 961 _dbus_string_get_length (&tmp))) 962 goto out_6; 963 964 if (!_dbus_string_append (&tmp, " ")) 965 goto out_6; 966 967 if (!_dbus_string_copy (&correct_hash, 0, &tmp, 968 _dbus_string_get_length (&tmp))) 969 goto out_6; 970 971 if (!send_data (auth, &tmp)) 972 goto out_6; 973 974 retval = TRUE; 975 976 out_6: 977 _dbus_string_zero (&correct_hash); 978 _dbus_string_free (&correct_hash); 979 out_5: 980 _dbus_string_free (&client_challenge); 981 out_4: 982 _dbus_string_zero (&tmp); 983 _dbus_string_free (&tmp); 984 out_3: 985 _dbus_string_free (&server_challenge); 986 out_2: 987 _dbus_string_free (&cookie_id_str); 988 out_1: 989 _dbus_string_free (&context); 990 out_0: 991 return retval; 992} 993 994static void 995handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth) 996{ 997 auth->cookie_id = -1; 998 _dbus_string_set_length (&auth->challenge, 0); 999} 1000 1001/* 1002 * EXTERNAL mechanism 1003 */ 1004 1005static dbus_bool_t 1006handle_server_data_external_mech (DBusAuth *auth, 1007 const DBusString *data) 1008{ 1009 if (_dbus_credentials_are_anonymous (auth->credentials)) 1010 { 1011 _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n", 1012 DBUS_AUTH_NAME (auth)); 1013 return send_rejected (auth); 1014 } 1015 1016 if (_dbus_string_get_length (data) > 0) 1017 { 1018 if (_dbus_string_get_length (&auth->identity) > 0) 1019 { 1020 /* Tried to send two auth identities, wtf */ 1021 _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", 1022 DBUS_AUTH_NAME (auth)); 1023 return send_rejected (auth); 1024 } 1025 else 1026 { 1027 /* this is our auth identity */ 1028 if (!_dbus_string_copy (data, 0, &auth->identity, 0)) 1029 return FALSE; 1030 } 1031 } 1032 1033 /* Poke client for an auth identity, if none given */ 1034 if (_dbus_string_get_length (&auth->identity) == 0 && 1035 !auth->already_asked_for_initial_response) 1036 { 1037 if (send_data (auth, NULL)) 1038 { 1039 _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n", 1040 DBUS_AUTH_NAME (auth)); 1041 auth->already_asked_for_initial_response = TRUE; 1042 return TRUE; 1043 } 1044 else 1045 return FALSE; 1046 } 1047 1048 _dbus_credentials_clear (auth->desired_identity); 1049 1050 /* If auth->identity is still empty here, then client 1051 * responded with an empty string after we poked it for 1052 * an initial response. This means to try to auth the 1053 * identity provided in the credentials. 1054 */ 1055 if (_dbus_string_get_length (&auth->identity) == 0) 1056 { 1057 if (!_dbus_credentials_add_credentials (auth->desired_identity, 1058 auth->credentials)) 1059 { 1060 return FALSE; /* OOM */ 1061 } 1062 } 1063 else 1064 { 1065 if (!_dbus_credentials_add_from_user (auth->desired_identity, 1066 &auth->identity)) 1067 { 1068 _dbus_verbose ("%s: could not get credentials from uid string\n", 1069 DBUS_AUTH_NAME (auth)); 1070 return send_rejected (auth); 1071 } 1072 } 1073 1074 if (_dbus_credentials_are_anonymous (auth->desired_identity)) 1075 { 1076 _dbus_verbose ("%s: desired user %s is no good\n", 1077 DBUS_AUTH_NAME (auth), 1078 _dbus_string_get_const_data (&auth->identity)); 1079 return send_rejected (auth); 1080 } 1081 1082 if (_dbus_credentials_are_superset (auth->credentials, 1083 auth->desired_identity)) 1084 { 1085 /* client has authenticated */ 1086 if (!_dbus_credentials_add_credentials (auth->authorized_identity, 1087 auth->desired_identity)) 1088 return FALSE; 1089 1090 /* also copy process ID from the socket credentials 1091 */ 1092 if (!_dbus_credentials_add_credential (auth->authorized_identity, 1093 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 1094 auth->credentials)) 1095 return FALSE; 1096 1097 if (!send_ok (auth)) 1098 return FALSE; 1099 1100 _dbus_verbose ("%s: authenticated client based on socket credentials\n", 1101 DBUS_AUTH_NAME (auth)); 1102 1103 return TRUE; 1104 } 1105 else 1106 { 1107 _dbus_verbose ("%s: desired identity not found in socket credentials\n", 1108 DBUS_AUTH_NAME (auth)); 1109 return send_rejected (auth); 1110 } 1111} 1112 1113static void 1114handle_server_shutdown_external_mech (DBusAuth *auth) 1115{ 1116 1117} 1118 1119static dbus_bool_t 1120handle_client_initial_response_external_mech (DBusAuth *auth, 1121 DBusString *response) 1122{ 1123 /* We always append our UID as an initial response, so the server 1124 * doesn't have to send back an empty challenge to check whether we 1125 * want to specify an identity. i.e. this avoids a round trip that 1126 * the spec for the EXTERNAL mechanism otherwise requires. 1127 */ 1128 DBusString plaintext; 1129 1130 if (!_dbus_string_init (&plaintext)) 1131 return FALSE; 1132 1133 if (!_dbus_append_user_from_current_process (&plaintext)) 1134 goto failed; 1135 1136 if (!_dbus_string_hex_encode (&plaintext, 0, 1137 response, 1138 _dbus_string_get_length (response))) 1139 goto failed; 1140 1141 _dbus_string_free (&plaintext); 1142 1143 return TRUE; 1144 1145 failed: 1146 _dbus_string_free (&plaintext); 1147 return FALSE; 1148} 1149 1150static dbus_bool_t 1151handle_client_data_external_mech (DBusAuth *auth, 1152 const DBusString *data) 1153{ 1154 1155 return TRUE; 1156} 1157 1158static void 1159handle_client_shutdown_external_mech (DBusAuth *auth) 1160{ 1161 1162} 1163 1164/* 1165 * ANONYMOUS mechanism 1166 */ 1167 1168static dbus_bool_t 1169handle_server_data_anonymous_mech (DBusAuth *auth, 1170 const DBusString *data) 1171{ 1172 if (_dbus_string_get_length (data) > 0) 1173 { 1174 /* Client is allowed to send "trace" data, the only defined 1175 * meaning is that if it contains '@' it is an email address, 1176 * and otherwise it is anything else, and it's supposed to be 1177 * UTF-8 1178 */ 1179 if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data))) 1180 { 1181 _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n", 1182 DBUS_AUTH_NAME (auth)); 1183 1184 { 1185 DBusString plaintext; 1186 DBusString encoded; 1187 _dbus_string_init_const (&plaintext, "D-Bus " VERSION); 1188 _dbus_string_init (&encoded); 1189 _dbus_string_hex_encode (&plaintext, 0, 1190 &encoded, 1191 0); 1192 _dbus_verbose ("%s: try '%s'\n", 1193 DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded)); 1194 } 1195 return send_rejected (auth); 1196 } 1197 1198 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", 1199 DBUS_AUTH_NAME (auth), 1200 _dbus_string_get_const_data (data)); 1201 } 1202 1203 /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ 1204 _dbus_credentials_clear (auth->desired_identity); 1205 1206 /* Copy process ID from the socket credentials 1207 */ 1208 if (!_dbus_credentials_add_credential (auth->authorized_identity, 1209 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 1210 auth->credentials)) 1211 return FALSE; 1212 1213 /* Anonymous is always allowed */ 1214 if (!send_ok (auth)) 1215 return FALSE; 1216 1217 _dbus_verbose ("%s: authenticated client as anonymous\n", 1218 DBUS_AUTH_NAME (auth)); 1219 1220 return TRUE; 1221} 1222 1223static void 1224handle_server_shutdown_anonymous_mech (DBusAuth *auth) 1225{ 1226 1227} 1228 1229static dbus_bool_t 1230handle_client_initial_response_anonymous_mech (DBusAuth *auth, 1231 DBusString *response) 1232{ 1233 /* Our initial response is a "trace" string which must be valid UTF-8 1234 * and must be an email address if it contains '@'. 1235 * We just send the dbus implementation info, like a user-agent or 1236 * something, because... why not. There's nothing guaranteed here 1237 * though, we could change it later. 1238 */ 1239 DBusString plaintext; 1240 1241 if (!_dbus_string_init (&plaintext)) 1242 return FALSE; 1243 1244 if (!_dbus_string_append (&plaintext, 1245 "libdbus " VERSION)) 1246 goto failed; 1247 1248 if (!_dbus_string_hex_encode (&plaintext, 0, 1249 response, 1250 _dbus_string_get_length (response))) 1251 goto failed; 1252 1253 _dbus_string_free (&plaintext); 1254 1255 return TRUE; 1256 1257 failed: 1258 _dbus_string_free (&plaintext); 1259 return FALSE; 1260} 1261 1262static dbus_bool_t 1263handle_client_data_anonymous_mech (DBusAuth *auth, 1264 const DBusString *data) 1265{ 1266 1267 return TRUE; 1268} 1269 1270static void 1271handle_client_shutdown_anonymous_mech (DBusAuth *auth) 1272{ 1273 1274} 1275 1276/* Put mechanisms here in order of preference. 1277 * Right now we have: 1278 * 1279 * - EXTERNAL checks socket credentials (or in the future, other info from the OS) 1280 * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE 1281 * - ANONYMOUS checks nothing but doesn't auth the person as a user 1282 * 1283 * We might ideally add a mechanism to chain to Cyrus SASL so we can 1284 * use its mechanisms as well. 1285 * 1286 */ 1287static const DBusAuthMechanismHandler 1288all_mechanisms[] = { 1289 { "EXTERNAL", 1290 handle_server_data_external_mech, 1291 NULL, NULL, 1292 handle_server_shutdown_external_mech, 1293 handle_client_initial_response_external_mech, 1294 handle_client_data_external_mech, 1295 NULL, NULL, 1296 handle_client_shutdown_external_mech }, 1297 { "DBUS_COOKIE_SHA1", 1298 handle_server_data_cookie_sha1_mech, 1299 NULL, NULL, 1300 handle_server_shutdown_cookie_sha1_mech, 1301 handle_client_initial_response_cookie_sha1_mech, 1302 handle_client_data_cookie_sha1_mech, 1303 NULL, NULL, 1304 handle_client_shutdown_cookie_sha1_mech }, 1305 { "ANONYMOUS", 1306 handle_server_data_anonymous_mech, 1307 NULL, NULL, 1308 handle_server_shutdown_anonymous_mech, 1309 handle_client_initial_response_anonymous_mech, 1310 handle_client_data_anonymous_mech, 1311 NULL, NULL, 1312 handle_client_shutdown_anonymous_mech }, 1313 { NULL, NULL } 1314}; 1315 1316static const DBusAuthMechanismHandler* 1317find_mech (const DBusString *name, 1318 char **allowed_mechs) 1319{ 1320 int i; 1321 1322 if (allowed_mechs != NULL && 1323 !_dbus_string_array_contains ((const char**) allowed_mechs, 1324 _dbus_string_get_const_data (name))) 1325 return NULL; 1326 1327 i = 0; 1328 while (all_mechanisms[i].mechanism != NULL) 1329 { 1330 if (_dbus_string_equal_c_str (name, 1331 all_mechanisms[i].mechanism)) 1332 1333 return &all_mechanisms[i]; 1334 1335 ++i; 1336 } 1337 1338 return NULL; 1339} 1340 1341static dbus_bool_t 1342send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) 1343{ 1344 DBusString auth_command; 1345 1346 if (!_dbus_string_init (&auth_command)) 1347 return FALSE; 1348 1349 if (!_dbus_string_append (&auth_command, 1350 "AUTH ")) 1351 { 1352 _dbus_string_free (&auth_command); 1353 return FALSE; 1354 } 1355 1356 if (!_dbus_string_append (&auth_command, 1357 mech->mechanism)) 1358 { 1359 _dbus_string_free (&auth_command); 1360 return FALSE; 1361 } 1362 1363 if (mech->client_initial_response_func != NULL) 1364 { 1365 if (!_dbus_string_append (&auth_command, " ")) 1366 { 1367 _dbus_string_free (&auth_command); 1368 return FALSE; 1369 } 1370 1371 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 1372 { 1373 _dbus_string_free (&auth_command); 1374 return FALSE; 1375 } 1376 } 1377 1378 if (!_dbus_string_append (&auth_command, 1379 "\r\n")) 1380 { 1381 _dbus_string_free (&auth_command); 1382 return FALSE; 1383 } 1384 1385 if (!_dbus_string_copy (&auth_command, 0, 1386 &auth->outgoing, 1387 _dbus_string_get_length (&auth->outgoing))) 1388 { 1389 _dbus_string_free (&auth_command); 1390 return FALSE; 1391 } 1392 1393 _dbus_string_free (&auth_command); 1394 shutdown_mech (auth); 1395 auth->mech = mech; 1396 goto_state (auth, &client_state_waiting_for_data); 1397 1398 return TRUE; 1399} 1400 1401static dbus_bool_t 1402send_data (DBusAuth *auth, DBusString *data) 1403{ 1404 int old_len; 1405 1406 if (data == NULL || _dbus_string_get_length (data) == 0) 1407 return _dbus_string_append (&auth->outgoing, "DATA\r\n"); 1408 else 1409 { 1410 old_len = _dbus_string_get_length (&auth->outgoing); 1411 if (!_dbus_string_append (&auth->outgoing, "DATA ")) 1412 goto out; 1413 1414 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, 1415 _dbus_string_get_length (&auth->outgoing))) 1416 goto out; 1417 1418 if (!_dbus_string_append (&auth->outgoing, "\r\n")) 1419 goto out; 1420 1421 return TRUE; 1422 1423 out: 1424 _dbus_string_set_length (&auth->outgoing, old_len); 1425 1426 return FALSE; 1427 } 1428} 1429 1430static dbus_bool_t 1431send_rejected (DBusAuth *auth) 1432{ 1433 DBusString command; 1434 DBusAuthServer *server_auth; 1435 int i; 1436 1437 if (!_dbus_string_init (&command)) 1438 return FALSE; 1439 1440 if (!_dbus_string_append (&command, 1441 "REJECTED")) 1442 goto nomem; 1443 1444 i = 0; 1445 while (all_mechanisms[i].mechanism != NULL) 1446 { 1447 if (!_dbus_string_append (&command, 1448 " ")) 1449 goto nomem; 1450 1451 if (!_dbus_string_append (&command, 1452 all_mechanisms[i].mechanism)) 1453 goto nomem; 1454 1455 ++i; 1456 } 1457 1458 if (!_dbus_string_append (&command, "\r\n")) 1459 goto nomem; 1460 1461 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 1462 _dbus_string_get_length (&auth->outgoing))) 1463 goto nomem; 1464 1465 shutdown_mech (auth); 1466 1467 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 1468 server_auth = DBUS_AUTH_SERVER (auth); 1469 server_auth->failures += 1; 1470 1471 if (server_auth->failures >= server_auth->max_failures) 1472 goto_state (auth, &common_state_need_disconnect); 1473 else 1474 goto_state (auth, &server_state_waiting_for_auth); 1475 1476 _dbus_string_free (&command); 1477 1478 return TRUE; 1479 1480 nomem: 1481 _dbus_string_free (&command); 1482 return FALSE; 1483} 1484 1485static dbus_bool_t 1486send_error (DBusAuth *auth, const char *message) 1487{ 1488 return _dbus_string_append_printf (&auth->outgoing, 1489 "ERROR \"%s\"\r\n", message); 1490} 1491 1492static dbus_bool_t 1493send_ok (DBusAuth *auth) 1494{ 1495 int orig_len; 1496 1497 orig_len = _dbus_string_get_length (&auth->outgoing); 1498 1499 if (_dbus_string_append (&auth->outgoing, "OK ") && 1500 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, 1501 0, 1502 &auth->outgoing, 1503 _dbus_string_get_length (&auth->outgoing)) && 1504 _dbus_string_append (&auth->outgoing, "\r\n")) 1505 { 1506 goto_state (auth, &server_state_waiting_for_begin); 1507 return TRUE; 1508 } 1509 else 1510 { 1511 _dbus_string_set_length (&auth->outgoing, orig_len); 1512 return FALSE; 1513 } 1514} 1515 1516static dbus_bool_t 1517send_begin (DBusAuth *auth, 1518 const DBusString *args_from_ok) 1519{ 1520 int end_of_hex; 1521 1522 /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ 1523 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); 1524 1525 /* We decode the hex string to binary, using guid_from_server as scratch... */ 1526 1527 end_of_hex = 0; 1528 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, 1529 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) 1530 return FALSE; 1531 1532 /* now clear out the scratch */ 1533 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 1534 1535 if (end_of_hex != _dbus_string_get_length (args_from_ok) || 1536 end_of_hex == 0) 1537 { 1538 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", 1539 end_of_hex, _dbus_string_get_length (args_from_ok)); 1540 goto_state (auth, &common_state_need_disconnect); 1541 return TRUE; 1542 } 1543 1544 if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) && 1545 _dbus_string_append (&auth->outgoing, "BEGIN\r\n")) 1546 { 1547 _dbus_verbose ("Got GUID '%s' from the server\n", 1548 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); 1549 1550 goto_state (auth, &common_state_authenticated); 1551 return TRUE; 1552 } 1553 else 1554 { 1555 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 1556 return FALSE; 1557 } 1558} 1559 1560static dbus_bool_t 1561send_cancel (DBusAuth *auth) 1562{ 1563 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) 1564 { 1565 goto_state (auth, &client_state_waiting_for_reject); 1566 return TRUE; 1567 } 1568 else 1569 return FALSE; 1570} 1571 1572static dbus_bool_t 1573process_data (DBusAuth *auth, 1574 const DBusString *args, 1575 DBusAuthDataFunction data_func) 1576{ 1577 int end; 1578 DBusString decoded; 1579 1580 if (!_dbus_string_init (&decoded)) 1581 return FALSE; 1582 1583 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) 1584 { 1585 _dbus_string_free (&decoded); 1586 return FALSE; 1587 } 1588 1589 if (_dbus_string_get_length (args) != end) 1590 { 1591 _dbus_string_free (&decoded); 1592 if (!send_error (auth, "Invalid hex encoding")) 1593 return FALSE; 1594 1595 return TRUE; 1596 } 1597 1598#ifdef DBUS_ENABLE_VERBOSE_MODE 1599 if (_dbus_string_validate_ascii (&decoded, 0, 1600 _dbus_string_get_length (&decoded))) 1601 _dbus_verbose ("%s: data: '%s'\n", 1602 DBUS_AUTH_NAME (auth), 1603 _dbus_string_get_const_data (&decoded)); 1604#endif 1605 1606 if (!(* data_func) (auth, &decoded)) 1607 { 1608 _dbus_string_free (&decoded); 1609 return FALSE; 1610 } 1611 1612 _dbus_string_free (&decoded); 1613 return TRUE; 1614} 1615 1616static dbus_bool_t 1617handle_auth (DBusAuth *auth, const DBusString *args) 1618{ 1619 if (_dbus_string_get_length (args) == 0) 1620 { 1621 /* No args to the auth, send mechanisms */ 1622 if (!send_rejected (auth)) 1623 return FALSE; 1624 1625 return TRUE; 1626 } 1627 else 1628 { 1629 int i; 1630 DBusString mech; 1631 DBusString hex_response; 1632 1633 _dbus_string_find_blank (args, 0, &i); 1634 1635 if (!_dbus_string_init (&mech)) 1636 return FALSE; 1637 1638 if (!_dbus_string_init (&hex_response)) 1639 { 1640 _dbus_string_free (&mech); 1641 return FALSE; 1642 } 1643 1644 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 1645 goto failed; 1646 1647 _dbus_string_skip_blank (args, i, &i); 1648 if (!_dbus_string_copy (args, i, &hex_response, 0)) 1649 goto failed; 1650 1651 auth->mech = find_mech (&mech, auth->allowed_mechs); 1652 if (auth->mech != NULL) 1653 { 1654 _dbus_verbose ("%s: Trying mechanism %s\n", 1655 DBUS_AUTH_NAME (auth), 1656 auth->mech->mechanism); 1657 1658 if (!process_data (auth, &hex_response, 1659 auth->mech->server_data_func)) 1660 goto failed; 1661 } 1662 else 1663 { 1664 /* Unsupported mechanism */ 1665 _dbus_verbose ("%s: Unsupported mechanism %s\n", 1666 DBUS_AUTH_NAME (auth), 1667 _dbus_string_get_const_data (&mech)); 1668 1669 if (!send_rejected (auth)) 1670 goto failed; 1671 } 1672 1673 _dbus_string_free (&mech); 1674 _dbus_string_free (&hex_response); 1675 1676 return TRUE; 1677 1678 failed: 1679 auth->mech = NULL; 1680 _dbus_string_free (&mech); 1681 _dbus_string_free (&hex_response); 1682 return FALSE; 1683 } 1684} 1685 1686static dbus_bool_t 1687handle_server_state_waiting_for_auth (DBusAuth *auth, 1688 DBusAuthCommand command, 1689 const DBusString *args) 1690{ 1691 switch (command) 1692 { 1693 case DBUS_AUTH_COMMAND_AUTH: 1694 return handle_auth (auth, args); 1695 1696 case DBUS_AUTH_COMMAND_CANCEL: 1697 case DBUS_AUTH_COMMAND_DATA: 1698 return send_error (auth, "Not currently in an auth conversation"); 1699 1700 case DBUS_AUTH_COMMAND_BEGIN: 1701 goto_state (auth, &common_state_need_disconnect); 1702 return TRUE; 1703 1704 case DBUS_AUTH_COMMAND_ERROR: 1705 return send_rejected (auth); 1706 1707 case DBUS_AUTH_COMMAND_REJECTED: 1708 case DBUS_AUTH_COMMAND_OK: 1709 case DBUS_AUTH_COMMAND_UNKNOWN: 1710 default: 1711 return send_error (auth, "Unknown command"); 1712 } 1713} 1714 1715static dbus_bool_t 1716handle_server_state_waiting_for_data (DBusAuth *auth, 1717 DBusAuthCommand command, 1718 const DBusString *args) 1719{ 1720 switch (command) 1721 { 1722 case DBUS_AUTH_COMMAND_AUTH: 1723 return send_error (auth, "Sent AUTH while another AUTH in progress"); 1724 1725 case DBUS_AUTH_COMMAND_CANCEL: 1726 case DBUS_AUTH_COMMAND_ERROR: 1727 return send_rejected (auth); 1728 1729 case DBUS_AUTH_COMMAND_DATA: 1730 return process_data (auth, args, auth->mech->server_data_func); 1731 1732 case DBUS_AUTH_COMMAND_BEGIN: 1733 goto_state (auth, &common_state_need_disconnect); 1734 return TRUE; 1735 1736 case DBUS_AUTH_COMMAND_REJECTED: 1737 case DBUS_AUTH_COMMAND_OK: 1738 case DBUS_AUTH_COMMAND_UNKNOWN: 1739 default: 1740 return send_error (auth, "Unknown command"); 1741 } 1742} 1743 1744static dbus_bool_t 1745handle_server_state_waiting_for_begin (DBusAuth *auth, 1746 DBusAuthCommand command, 1747 const DBusString *args) 1748{ 1749 switch (command) 1750 { 1751 case DBUS_AUTH_COMMAND_AUTH: 1752 return send_error (auth, "Sent AUTH while expecting BEGIN"); 1753 1754 case DBUS_AUTH_COMMAND_DATA: 1755 return send_error (auth, "Sent DATA while expecting BEGIN"); 1756 1757 case DBUS_AUTH_COMMAND_BEGIN: 1758 goto_state (auth, &common_state_authenticated); 1759 return TRUE; 1760 1761 case DBUS_AUTH_COMMAND_REJECTED: 1762 case DBUS_AUTH_COMMAND_OK: 1763 case DBUS_AUTH_COMMAND_UNKNOWN: 1764 default: 1765 return send_error (auth, "Unknown command"); 1766 1767 case DBUS_AUTH_COMMAND_CANCEL: 1768 case DBUS_AUTH_COMMAND_ERROR: 1769 return send_rejected (auth); 1770 } 1771} 1772 1773/* return FALSE if no memory, TRUE if all OK */ 1774static dbus_bool_t 1775get_word (const DBusString *str, 1776 int *start, 1777 DBusString *word) 1778{ 1779 int i; 1780 1781 _dbus_string_skip_blank (str, *start, start); 1782 _dbus_string_find_blank (str, *start, &i); 1783 1784 if (i > *start) 1785 { 1786 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) 1787 return FALSE; 1788 1789 *start = i; 1790 } 1791 1792 return TRUE; 1793} 1794 1795static dbus_bool_t 1796record_mechanisms (DBusAuth *auth, 1797 const DBusString *args) 1798{ 1799 int next; 1800 int len; 1801 1802 if (auth->already_got_mechanisms) 1803 return TRUE; 1804 1805 len = _dbus_string_get_length (args); 1806 1807 next = 0; 1808 while (next < len) 1809 { 1810 DBusString m; 1811 const DBusAuthMechanismHandler *mech; 1812 1813 if (!_dbus_string_init (&m)) 1814 goto nomem; 1815 1816 if (!get_word (args, &next, &m)) 1817 { 1818 _dbus_string_free (&m); 1819 goto nomem; 1820 } 1821 1822 mech = find_mech (&m, auth->allowed_mechs); 1823 1824 if (mech != NULL) 1825 { 1826 /* FIXME right now we try mechanisms in the order 1827 * the server lists them; should we do them in 1828 * some more deterministic order? 1829 * 1830 * Probably in all_mechanisms order, our order of 1831 * preference. Of course when the server is us, 1832 * it lists things in that order anyhow. 1833 */ 1834 1835 if (mech != &all_mechanisms[0]) 1836 { 1837 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", 1838 DBUS_AUTH_NAME (auth), mech->mechanism); 1839 1840 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 1841 (void*) mech)) 1842 { 1843 _dbus_string_free (&m); 1844 goto nomem; 1845 } 1846 } 1847 else 1848 { 1849 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", 1850 DBUS_AUTH_NAME (auth), mech->mechanism); 1851 } 1852 } 1853 else 1854 { 1855 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", 1856 DBUS_AUTH_NAME (auth), 1857 _dbus_string_get_const_data (&m)); 1858 } 1859 1860 _dbus_string_free (&m); 1861 } 1862 1863 auth->already_got_mechanisms = TRUE; 1864 1865 return TRUE; 1866 1867 nomem: 1868 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 1869 1870 return FALSE; 1871} 1872 1873static dbus_bool_t 1874process_rejected (DBusAuth *auth, const DBusString *args) 1875{ 1876 const DBusAuthMechanismHandler *mech; 1877 DBusAuthClient *client; 1878 1879 client = DBUS_AUTH_CLIENT (auth); 1880 1881 if (!auth->already_got_mechanisms) 1882 { 1883 if (!record_mechanisms (auth, args)) 1884 return FALSE; 1885 } 1886 1887 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 1888 { 1889 mech = client->mechs_to_try->data; 1890 1891 if (!send_auth (auth, mech)) 1892 return FALSE; 1893 1894 _dbus_list_pop_first (&client->mechs_to_try); 1895 1896 _dbus_verbose ("%s: Trying mechanism %s\n", 1897 DBUS_AUTH_NAME (auth), 1898 mech->mechanism); 1899 } 1900 else 1901 { 1902 /* Give up */ 1903 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", 1904 DBUS_AUTH_NAME (auth)); 1905 goto_state (auth, &common_state_need_disconnect); 1906 } 1907 1908 return TRUE; 1909} 1910 1911 1912static dbus_bool_t 1913handle_client_state_waiting_for_data (DBusAuth *auth, 1914 DBusAuthCommand command, 1915 const DBusString *args) 1916{ 1917 _dbus_assert (auth->mech != NULL); 1918 1919 switch (command) 1920 { 1921 case DBUS_AUTH_COMMAND_DATA: 1922 return process_data (auth, args, auth->mech->client_data_func); 1923 1924 case DBUS_AUTH_COMMAND_REJECTED: 1925 return process_rejected (auth, args); 1926 1927 case DBUS_AUTH_COMMAND_OK: 1928 return send_begin (auth, args); 1929 1930 case DBUS_AUTH_COMMAND_ERROR: 1931 return send_cancel (auth); 1932 1933 case DBUS_AUTH_COMMAND_AUTH: 1934 case DBUS_AUTH_COMMAND_CANCEL: 1935 case DBUS_AUTH_COMMAND_BEGIN: 1936 case DBUS_AUTH_COMMAND_UNKNOWN: 1937 default: 1938 return send_error (auth, "Unknown command"); 1939 } 1940} 1941 1942static dbus_bool_t 1943handle_client_state_waiting_for_ok (DBusAuth *auth, 1944 DBusAuthCommand command, 1945 const DBusString *args) 1946{ 1947 switch (command) 1948 { 1949 case DBUS_AUTH_COMMAND_REJECTED: 1950 return process_rejected (auth, args); 1951 1952 case DBUS_AUTH_COMMAND_OK: 1953 return send_begin (auth, args); 1954 1955 case DBUS_AUTH_COMMAND_DATA: 1956 case DBUS_AUTH_COMMAND_ERROR: 1957 return send_cancel (auth); 1958 1959 case DBUS_AUTH_COMMAND_AUTH: 1960 case DBUS_AUTH_COMMAND_CANCEL: 1961 case DBUS_AUTH_COMMAND_BEGIN: 1962 case DBUS_AUTH_COMMAND_UNKNOWN: 1963 default: 1964 return send_error (auth, "Unknown command"); 1965 } 1966} 1967 1968static dbus_bool_t 1969handle_client_state_waiting_for_reject (DBusAuth *auth, 1970 DBusAuthCommand command, 1971 const DBusString *args) 1972{ 1973 switch (command) 1974 { 1975 case DBUS_AUTH_COMMAND_REJECTED: 1976 return process_rejected (auth, args); 1977 1978 case DBUS_AUTH_COMMAND_AUTH: 1979 case DBUS_AUTH_COMMAND_CANCEL: 1980 case DBUS_AUTH_COMMAND_DATA: 1981 case DBUS_AUTH_COMMAND_BEGIN: 1982 case DBUS_AUTH_COMMAND_OK: 1983 case DBUS_AUTH_COMMAND_ERROR: 1984 case DBUS_AUTH_COMMAND_UNKNOWN: 1985 default: 1986 goto_state (auth, &common_state_need_disconnect); 1987 return TRUE; 1988 } 1989} 1990 1991/** 1992 * Mapping from command name to enum 1993 */ 1994typedef struct { 1995 const char *name; /**< Name of the command */ 1996 DBusAuthCommand command; /**< Corresponding enum */ 1997} DBusAuthCommandName; 1998 1999static const DBusAuthCommandName auth_command_names[] = { 2000 { "AUTH", DBUS_AUTH_COMMAND_AUTH }, 2001 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, 2002 { "DATA", DBUS_AUTH_COMMAND_DATA }, 2003 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, 2004 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, 2005 { "OK", DBUS_AUTH_COMMAND_OK }, 2006 { "ERROR", DBUS_AUTH_COMMAND_ERROR } 2007}; 2008 2009static DBusAuthCommand 2010lookup_command_from_name (DBusString *command) 2011{ 2012 int i; 2013 2014 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) 2015 { 2016 if (_dbus_string_equal_c_str (command, 2017 auth_command_names[i].name)) 2018 return auth_command_names[i].command; 2019 } 2020 2021 return DBUS_AUTH_COMMAND_UNKNOWN; 2022} 2023 2024static void 2025goto_state (DBusAuth *auth, 2026 const DBusAuthStateData *state) 2027{ 2028 _dbus_verbose ("%s: going from state %s to state %s\n", 2029 DBUS_AUTH_NAME (auth), 2030 auth->state->name, 2031 state->name); 2032 2033 auth->state = state; 2034} 2035 2036/* returns whether to call it again right away */ 2037static dbus_bool_t 2038process_command (DBusAuth *auth) 2039{ 2040 DBusAuthCommand command; 2041 DBusString line; 2042 DBusString args; 2043 int eol; 2044 int i, j; 2045 dbus_bool_t retval; 2046 2047 /* _dbus_verbose ("%s: trying process_command()\n"); */ 2048 2049 retval = FALSE; 2050 2051 eol = 0; 2052 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 2053 return FALSE; 2054 2055 if (!_dbus_string_init (&line)) 2056 { 2057 auth->needed_memory = TRUE; 2058 return FALSE; 2059 } 2060 2061 if (!_dbus_string_init (&args)) 2062 { 2063 _dbus_string_free (&line); 2064 auth->needed_memory = TRUE; 2065 return FALSE; 2066 } 2067 2068 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) 2069 goto out; 2070 2071 if (!_dbus_string_validate_ascii (&line, 0, 2072 _dbus_string_get_length (&line))) 2073 { 2074 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", 2075 DBUS_AUTH_NAME (auth)); 2076 if (!send_error (auth, "Command contained non-ASCII")) 2077 goto out; 2078 else 2079 goto next_command; 2080 } 2081 2082 _dbus_verbose ("%s: got command \"%s\"\n", 2083 DBUS_AUTH_NAME (auth), 2084 _dbus_string_get_const_data (&line)); 2085 2086 _dbus_string_find_blank (&line, 0, &i); 2087 _dbus_string_skip_blank (&line, i, &j); 2088 2089 if (j > i) 2090 _dbus_string_delete (&line, i, j - i); 2091 2092 if (!_dbus_string_move (&line, i, &args, 0)) 2093 goto out; 2094 2095 /* FIXME 1.0 we should probably validate that only the allowed 2096 * chars are in the command name 2097 */ 2098 2099 command = lookup_command_from_name (&line); 2100 if (!(* auth->state->handler) (auth, command, &args)) 2101 goto out; 2102 2103 next_command: 2104 2105 /* We've succeeded in processing the whole command so drop it out 2106 * of the incoming buffer and return TRUE to try another command. 2107 */ 2108 2109 _dbus_string_delete (&auth->incoming, 0, eol); 2110 2111 /* kill the \r\n */ 2112 _dbus_string_delete (&auth->incoming, 0, 2); 2113 2114 retval = TRUE; 2115 2116 out: 2117 _dbus_string_free (&args); 2118 _dbus_string_free (&line); 2119 2120 if (!retval) 2121 auth->needed_memory = TRUE; 2122 else 2123 auth->needed_memory = FALSE; 2124 2125 return retval; 2126} 2127 2128 2129/** @} */ 2130 2131/** 2132 * @addtogroup DBusAuth 2133 * @{ 2134 */ 2135 2136/** 2137 * Creates a new auth conversation object for the server side. 2138 * See doc/dbus-sasl-profile.txt for full details on what 2139 * this object does. 2140 * 2141 * @returns the new object or #NULL if no memory 2142 */ 2143DBusAuth* 2144_dbus_auth_server_new (const DBusString *guid) 2145{ 2146 DBusAuth *auth; 2147 DBusAuthServer *server_auth; 2148 DBusString guid_copy; 2149 2150 if (!_dbus_string_init (&guid_copy)) 2151 return NULL; 2152 2153 if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) 2154 { 2155 _dbus_string_free (&guid_copy); 2156 return NULL; 2157 } 2158 2159 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 2160 if (auth == NULL) 2161 { 2162 _dbus_string_free (&guid_copy); 2163 return NULL; 2164 } 2165 2166 auth->side = auth_side_server; 2167 auth->state = &server_state_waiting_for_auth; 2168 2169 server_auth = DBUS_AUTH_SERVER (auth); 2170 2171 server_auth->guid = guid_copy; 2172 2173 /* perhaps this should be per-mechanism with a lower 2174 * max 2175 */ 2176 server_auth->failures = 0; 2177 server_auth->max_failures = 6; 2178 2179 return auth; 2180} 2181 2182/** 2183 * Creates a new auth conversation object for the client side. 2184 * See doc/dbus-sasl-profile.txt for full details on what 2185 * this object does. 2186 * 2187 * @returns the new object or #NULL if no memory 2188 */ 2189DBusAuth* 2190_dbus_auth_client_new (void) 2191{ 2192 DBusAuth *auth; 2193 DBusString guid_str; 2194 2195 if (!_dbus_string_init (&guid_str)) 2196 return NULL; 2197 2198 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 2199 if (auth == NULL) 2200 { 2201 _dbus_string_free (&guid_str); 2202 return NULL; 2203 } 2204 2205 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; 2206 2207 auth->side = auth_side_client; 2208 auth->state = &client_state_need_send_auth; 2209 2210 /* Start the auth conversation by sending AUTH for our default 2211 * mechanism */ 2212 if (!send_auth (auth, &all_mechanisms[0])) 2213 { 2214 _dbus_auth_unref (auth); 2215 return NULL; 2216 } 2217 2218 return auth; 2219} 2220 2221/** 2222 * Increments the refcount of an auth object. 2223 * 2224 * @param auth the auth conversation 2225 * @returns the auth conversation 2226 */ 2227DBusAuth * 2228_dbus_auth_ref (DBusAuth *auth) 2229{ 2230 _dbus_assert (auth != NULL); 2231 2232 auth->refcount += 1; 2233 2234 return auth; 2235} 2236 2237/** 2238 * Decrements the refcount of an auth object. 2239 * 2240 * @param auth the auth conversation 2241 */ 2242void 2243_dbus_auth_unref (DBusAuth *auth) 2244{ 2245 _dbus_assert (auth != NULL); 2246 _dbus_assert (auth->refcount > 0); 2247 2248 auth->refcount -= 1; 2249 if (auth->refcount == 0) 2250 { 2251 shutdown_mech (auth); 2252 2253 if (DBUS_AUTH_IS_CLIENT (auth)) 2254 { 2255 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 2256 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 2257 } 2258 else 2259 { 2260 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 2261 2262 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); 2263 } 2264 2265 if (auth->keyring) 2266 _dbus_keyring_unref (auth->keyring); 2267 2268 _dbus_string_free (&auth->context); 2269 _dbus_string_free (&auth->challenge); 2270 _dbus_string_free (&auth->identity); 2271 _dbus_string_free (&auth->incoming); 2272 _dbus_string_free (&auth->outgoing); 2273 2274 dbus_free_string_array (auth->allowed_mechs); 2275 2276 _dbus_credentials_unref (auth->credentials); 2277 _dbus_credentials_unref (auth->authorized_identity); 2278 _dbus_credentials_unref (auth->desired_identity); 2279 2280 dbus_free (auth); 2281 } 2282} 2283 2284/** 2285 * Sets an array of authentication mechanism names 2286 * that we are willing to use. 2287 * 2288 * @param auth the auth conversation 2289 * @param mechanisms #NULL-terminated array of mechanism names 2290 * @returns #FALSE if no memory 2291 */ 2292dbus_bool_t 2293_dbus_auth_set_mechanisms (DBusAuth *auth, 2294 const char **mechanisms) 2295{ 2296 char **copy; 2297 2298 if (mechanisms != NULL) 2299 { 2300 copy = _dbus_dup_string_array (mechanisms); 2301 if (copy == NULL) 2302 return FALSE; 2303 } 2304 else 2305 copy = NULL; 2306 2307 dbus_free_string_array (auth->allowed_mechs); 2308 2309 auth->allowed_mechs = copy; 2310 2311 return TRUE; 2312} 2313 2314/** 2315 * @param auth the auth conversation object 2316 * @returns #TRUE if we're in a final state 2317 */ 2318#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) 2319 2320/** 2321 * Analyzes buffered input and moves the auth conversation forward, 2322 * returning the new state of the auth conversation. 2323 * 2324 * @param auth the auth conversation 2325 * @returns the new state 2326 */ 2327DBusAuthState 2328_dbus_auth_do_work (DBusAuth *auth) 2329{ 2330 auth->needed_memory = FALSE; 2331 2332 /* Max amount we'll buffer up before deciding someone's on crack */ 2333#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 2334 2335 do 2336 { 2337 if (DBUS_AUTH_IN_END_STATE (auth)) 2338 break; 2339 2340 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 2341 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 2342 { 2343 goto_state (auth, &common_state_need_disconnect); 2344 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", 2345 DBUS_AUTH_NAME (auth)); 2346 break; 2347 } 2348 } 2349 while (process_command (auth)); 2350 2351 if (auth->needed_memory) 2352 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 2353 else if (_dbus_string_get_length (&auth->outgoing) > 0) 2354 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 2355 else if (auth->state == &common_state_need_disconnect) 2356 return DBUS_AUTH_STATE_NEED_DISCONNECT; 2357 else if (auth->state == &common_state_authenticated) 2358 return DBUS_AUTH_STATE_AUTHENTICATED; 2359 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 2360} 2361 2362/** 2363 * Gets bytes that need to be sent to the peer we're conversing with. 2364 * After writing some bytes, _dbus_auth_bytes_sent() must be called 2365 * to notify the auth object that they were written. 2366 * 2367 * @param auth the auth conversation 2368 * @param str return location for a ref to the buffer to send 2369 * @returns #FALSE if nothing to send 2370 */ 2371dbus_bool_t 2372_dbus_auth_get_bytes_to_send (DBusAuth *auth, 2373 const DBusString **str) 2374{ 2375 _dbus_assert (auth != NULL); 2376 _dbus_assert (str != NULL); 2377 2378 *str = NULL; 2379 2380 if (_dbus_string_get_length (&auth->outgoing) == 0) 2381 return FALSE; 2382 2383 *str = &auth->outgoing; 2384 2385 return TRUE; 2386} 2387 2388/** 2389 * Notifies the auth conversation object that 2390 * the given number of bytes of the outgoing buffer 2391 * have been written out. 2392 * 2393 * @param auth the auth conversation 2394 * @param bytes_sent number of bytes written out 2395 */ 2396void 2397_dbus_auth_bytes_sent (DBusAuth *auth, 2398 int bytes_sent) 2399{ 2400 _dbus_verbose ("%s: Sent %d bytes of: %s\n", 2401 DBUS_AUTH_NAME (auth), 2402 bytes_sent, 2403 _dbus_string_get_const_data (&auth->outgoing)); 2404 2405 _dbus_string_delete (&auth->outgoing, 2406 0, bytes_sent); 2407} 2408 2409/** 2410 * Get a buffer to be used for reading bytes from the peer we're conversing 2411 * with. Bytes should be appended to this buffer. 2412 * 2413 * @param auth the auth conversation 2414 * @param buffer return location for buffer to append bytes to 2415 */ 2416void 2417_dbus_auth_get_buffer (DBusAuth *auth, 2418 DBusString **buffer) 2419{ 2420 _dbus_assert (auth != NULL); 2421 _dbus_assert (!auth->buffer_outstanding); 2422 2423 *buffer = &auth->incoming; 2424 2425 auth->buffer_outstanding = TRUE; 2426} 2427 2428/** 2429 * Returns a buffer with new data read into it. 2430 * 2431 * @param auth the auth conversation 2432 * @param buffer the buffer being returned 2433 * @param bytes_read number of new bytes added 2434 */ 2435void 2436_dbus_auth_return_buffer (DBusAuth *auth, 2437 DBusString *buffer, 2438 int bytes_read) 2439{ 2440 _dbus_assert (buffer == &auth->incoming); 2441 _dbus_assert (auth->buffer_outstanding); 2442 2443 auth->buffer_outstanding = FALSE; 2444} 2445 2446/** 2447 * Returns leftover bytes that were not used as part of the auth 2448 * conversation. These bytes will be part of the message stream 2449 * instead. This function may not be called until authentication has 2450 * succeeded. 2451 * 2452 * @param auth the auth conversation 2453 * @param str return location for pointer to string of unused bytes 2454 */ 2455void 2456_dbus_auth_get_unused_bytes (DBusAuth *auth, 2457 const DBusString **str) 2458{ 2459 if (!DBUS_AUTH_IN_END_STATE (auth)) 2460 return; 2461 2462 *str = &auth->incoming; 2463} 2464 2465 2466/** 2467 * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes() 2468 * after we've gotten them and successfully moved them elsewhere. 2469 * 2470 * @param auth the auth conversation 2471 */ 2472void 2473_dbus_auth_delete_unused_bytes (DBusAuth *auth) 2474{ 2475 if (!DBUS_AUTH_IN_END_STATE (auth)) 2476 return; 2477 2478 _dbus_string_set_length (&auth->incoming, 0); 2479} 2480 2481/** 2482 * Called post-authentication, indicates whether we need to encode 2483 * the message stream with _dbus_auth_encode_data() prior to 2484 * sending it to the peer. 2485 * 2486 * @param auth the auth conversation 2487 * @returns #TRUE if we need to encode the stream 2488 */ 2489dbus_bool_t 2490_dbus_auth_needs_encoding (DBusAuth *auth) 2491{ 2492 if (auth->state != &common_state_authenticated) 2493 return FALSE; 2494 2495 if (auth->mech != NULL) 2496 { 2497 if (DBUS_AUTH_IS_CLIENT (auth)) 2498 return auth->mech->client_encode_func != NULL; 2499 else 2500 return auth->mech->server_encode_func != NULL; 2501 } 2502 else 2503 return FALSE; 2504} 2505 2506/** 2507 * Called post-authentication, encodes a block of bytes for sending to 2508 * the peer. If no encoding was negotiated, just copies the bytes 2509 * (you can avoid this by checking _dbus_auth_needs_encoding()). 2510 * 2511 * @param auth the auth conversation 2512 * @param plaintext the plain text data 2513 * @param encoded initialized string to where encoded data is appended 2514 * @returns #TRUE if we had enough memory and successfully encoded 2515 */ 2516dbus_bool_t 2517_dbus_auth_encode_data (DBusAuth *auth, 2518 const DBusString *plaintext, 2519 DBusString *encoded) 2520{ 2521 _dbus_assert (plaintext != encoded); 2522 2523 if (auth->state != &common_state_authenticated) 2524 return FALSE; 2525 2526 if (_dbus_auth_needs_encoding (auth)) 2527 { 2528 if (DBUS_AUTH_IS_CLIENT (auth)) 2529 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 2530 else 2531 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 2532 } 2533 else 2534 { 2535 return _dbus_string_copy (plaintext, 0, encoded, 2536 _dbus_string_get_length (encoded)); 2537 } 2538} 2539 2540/** 2541 * Called post-authentication, indicates whether we need to decode 2542 * the message stream with _dbus_auth_decode_data() after 2543 * receiving it from the peer. 2544 * 2545 * @param auth the auth conversation 2546 * @returns #TRUE if we need to encode the stream 2547 */ 2548dbus_bool_t 2549_dbus_auth_needs_decoding (DBusAuth *auth) 2550{ 2551 if (auth->state != &common_state_authenticated) 2552 return FALSE; 2553 2554 if (auth->mech != NULL) 2555 { 2556 if (DBUS_AUTH_IS_CLIENT (auth)) 2557 return auth->mech->client_decode_func != NULL; 2558 else 2559 return auth->mech->server_decode_func != NULL; 2560 } 2561 else 2562 return FALSE; 2563} 2564 2565 2566/** 2567 * Called post-authentication, decodes a block of bytes received from 2568 * the peer. If no encoding was negotiated, just copies the bytes (you 2569 * can avoid this by checking _dbus_auth_needs_decoding()). 2570 * 2571 * @todo 1.0? We need to be able to distinguish "out of memory" error 2572 * from "the data is hosed" error. 2573 * 2574 * @param auth the auth conversation 2575 * @param encoded the encoded data 2576 * @param plaintext initialized string where decoded data is appended 2577 * @returns #TRUE if we had enough memory and successfully decoded 2578 */ 2579dbus_bool_t 2580_dbus_auth_decode_data (DBusAuth *auth, 2581 const DBusString *encoded, 2582 DBusString *plaintext) 2583{ 2584 _dbus_assert (plaintext != encoded); 2585 2586 if (auth->state != &common_state_authenticated) 2587 return FALSE; 2588 2589 if (_dbus_auth_needs_decoding (auth)) 2590 { 2591 if (DBUS_AUTH_IS_CLIENT (auth)) 2592 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 2593 else 2594 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 2595 } 2596 else 2597 { 2598 return _dbus_string_copy (encoded, 0, plaintext, 2599 _dbus_string_get_length (plaintext)); 2600 } 2601} 2602 2603/** 2604 * Sets credentials received via reliable means from the operating 2605 * system. 2606 * 2607 * @param auth the auth conversation 2608 * @param credentials the credentials received 2609 * @returns #FALSE on OOM 2610 */ 2611dbus_bool_t 2612_dbus_auth_set_credentials (DBusAuth *auth, 2613 DBusCredentials *credentials) 2614{ 2615 _dbus_credentials_clear (auth->credentials); 2616 return _dbus_credentials_add_credentials (auth->credentials, 2617 credentials); 2618} 2619 2620/** 2621 * Gets the identity we authorized the client as. Apps may have 2622 * different policies as to what identities they allow. 2623 * 2624 * Returned credentials are not a copy and should not be modified 2625 * 2626 * @param auth the auth conversation 2627 * @returns the credentials we've authorized BY REFERENCE do not modify 2628 */ 2629DBusCredentials* 2630_dbus_auth_get_identity (DBusAuth *auth) 2631{ 2632 if (auth->state == &common_state_authenticated) 2633 { 2634 return auth->authorized_identity; 2635 } 2636 else 2637 { 2638 /* FIXME instead of this, keep an empty credential around that 2639 * doesn't require allocation or something 2640 */ 2641 /* return empty credentials */ 2642 _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); 2643 return auth->authorized_identity; 2644 } 2645} 2646 2647/** 2648 * Gets the GUID from the server if we've authenticated; gets 2649 * #NULL otherwise. 2650 * @param auth the auth object 2651 * @returns the GUID in ASCII hex format 2652 */ 2653const char* 2654_dbus_auth_get_guid_from_server (DBusAuth *auth) 2655{ 2656 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); 2657 2658 if (auth->state == &common_state_authenticated) 2659 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 2660 else 2661 return NULL; 2662} 2663 2664/** 2665 * Sets the "authentication context" which scopes cookies 2666 * with the DBUS_COOKIE_SHA1 auth mechanism for example. 2667 * 2668 * @param auth the auth conversation 2669 * @param context the context 2670 * @returns #FALSE if no memory 2671 */ 2672dbus_bool_t 2673_dbus_auth_set_context (DBusAuth *auth, 2674 const DBusString *context) 2675{ 2676 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), 2677 &auth->context, 0, _dbus_string_get_length (context)); 2678} 2679 2680/** @} */ 2681 2682/* tests in dbus-auth-util.c */ 2683