dbus-auth.c revision 5baf2f856a9c6625993234855b07680da1c8916f
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 goto_state (auth, &server_state_waiting_for_data); 1043 return TRUE; 1044 } 1045 else 1046 return FALSE; 1047 } 1048 1049 _dbus_credentials_clear (auth->desired_identity); 1050 1051 /* If auth->identity is still empty here, then client 1052 * responded with an empty string after we poked it for 1053 * an initial response. This means to try to auth the 1054 * identity provided in the credentials. 1055 */ 1056 if (_dbus_string_get_length (&auth->identity) == 0) 1057 { 1058 if (!_dbus_credentials_add_credentials (auth->desired_identity, 1059 auth->credentials)) 1060 { 1061 return FALSE; /* OOM */ 1062 } 1063 } 1064 else 1065 { 1066 if (!_dbus_credentials_add_from_user (auth->desired_identity, 1067 &auth->identity)) 1068 { 1069 _dbus_verbose ("%s: could not get credentials from uid string\n", 1070 DBUS_AUTH_NAME (auth)); 1071 return send_rejected (auth); 1072 } 1073 } 1074 1075 if (_dbus_credentials_are_anonymous (auth->desired_identity)) 1076 { 1077 _dbus_verbose ("%s: desired user %s is no good\n", 1078 DBUS_AUTH_NAME (auth), 1079 _dbus_string_get_const_data (&auth->identity)); 1080 return send_rejected (auth); 1081 } 1082 1083 if (_dbus_credentials_are_superset (auth->credentials, 1084 auth->desired_identity)) 1085 { 1086 /* client has authenticated */ 1087 if (!_dbus_credentials_add_credentials (auth->authorized_identity, 1088 auth->desired_identity)) 1089 return FALSE; 1090 1091 /* also copy process ID from the socket credentials 1092 */ 1093 if (!_dbus_credentials_add_credential (auth->authorized_identity, 1094 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 1095 auth->credentials)) 1096 return FALSE; 1097 1098 /* also copy audit data from the socket credentials 1099 */ 1100 if (!_dbus_credentials_add_credential (auth->authorized_identity, 1101 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, 1102 auth->credentials)) 1103 return FALSE; 1104 1105 if (!send_ok (auth)) 1106 return FALSE; 1107 1108 _dbus_verbose ("%s: authenticated client based on socket credentials\n", 1109 DBUS_AUTH_NAME (auth)); 1110 1111 return TRUE; 1112 } 1113 else 1114 { 1115 _dbus_verbose ("%s: desired identity not found in socket credentials\n", 1116 DBUS_AUTH_NAME (auth)); 1117 return send_rejected (auth); 1118 } 1119} 1120 1121static void 1122handle_server_shutdown_external_mech (DBusAuth *auth) 1123{ 1124 1125} 1126 1127static dbus_bool_t 1128handle_client_initial_response_external_mech (DBusAuth *auth, 1129 DBusString *response) 1130{ 1131 /* We always append our UID as an initial response, so the server 1132 * doesn't have to send back an empty challenge to check whether we 1133 * want to specify an identity. i.e. this avoids a round trip that 1134 * the spec for the EXTERNAL mechanism otherwise requires. 1135 */ 1136 DBusString plaintext; 1137 1138 if (!_dbus_string_init (&plaintext)) 1139 return FALSE; 1140 1141 if (!_dbus_append_user_from_current_process (&plaintext)) 1142 goto failed; 1143 1144 if (!_dbus_string_hex_encode (&plaintext, 0, 1145 response, 1146 _dbus_string_get_length (response))) 1147 goto failed; 1148 1149 _dbus_string_free (&plaintext); 1150 1151 return TRUE; 1152 1153 failed: 1154 _dbus_string_free (&plaintext); 1155 return FALSE; 1156} 1157 1158static dbus_bool_t 1159handle_client_data_external_mech (DBusAuth *auth, 1160 const DBusString *data) 1161{ 1162 1163 return TRUE; 1164} 1165 1166static void 1167handle_client_shutdown_external_mech (DBusAuth *auth) 1168{ 1169 1170} 1171 1172/* 1173 * ANONYMOUS mechanism 1174 */ 1175 1176static dbus_bool_t 1177handle_server_data_anonymous_mech (DBusAuth *auth, 1178 const DBusString *data) 1179{ 1180 if (_dbus_string_get_length (data) > 0) 1181 { 1182 /* Client is allowed to send "trace" data, the only defined 1183 * meaning is that if it contains '@' it is an email address, 1184 * and otherwise it is anything else, and it's supposed to be 1185 * UTF-8 1186 */ 1187 if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data))) 1188 { 1189 _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n", 1190 DBUS_AUTH_NAME (auth)); 1191 1192 { 1193 DBusString plaintext; 1194 DBusString encoded; 1195 _dbus_string_init_const (&plaintext, "D-Bus " VERSION); 1196 _dbus_string_init (&encoded); 1197 _dbus_string_hex_encode (&plaintext, 0, 1198 &encoded, 1199 0); 1200 _dbus_verbose ("%s: try '%s'\n", 1201 DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded)); 1202 } 1203 return send_rejected (auth); 1204 } 1205 1206 _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", 1207 DBUS_AUTH_NAME (auth), 1208 _dbus_string_get_const_data (data)); 1209 } 1210 1211 /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ 1212 _dbus_credentials_clear (auth->desired_identity); 1213 1214 /* Copy process ID from the socket credentials 1215 */ 1216 if (!_dbus_credentials_add_credential (auth->authorized_identity, 1217 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 1218 auth->credentials)) 1219 return FALSE; 1220 1221 /* Anonymous is always allowed */ 1222 if (!send_ok (auth)) 1223 return FALSE; 1224 1225 _dbus_verbose ("%s: authenticated client as anonymous\n", 1226 DBUS_AUTH_NAME (auth)); 1227 1228 return TRUE; 1229} 1230 1231static void 1232handle_server_shutdown_anonymous_mech (DBusAuth *auth) 1233{ 1234 1235} 1236 1237static dbus_bool_t 1238handle_client_initial_response_anonymous_mech (DBusAuth *auth, 1239 DBusString *response) 1240{ 1241 /* Our initial response is a "trace" string which must be valid UTF-8 1242 * and must be an email address if it contains '@'. 1243 * We just send the dbus implementation info, like a user-agent or 1244 * something, because... why not. There's nothing guaranteed here 1245 * though, we could change it later. 1246 */ 1247 DBusString plaintext; 1248 1249 if (!_dbus_string_init (&plaintext)) 1250 return FALSE; 1251 1252 if (!_dbus_string_append (&plaintext, 1253 "libdbus " VERSION)) 1254 goto failed; 1255 1256 if (!_dbus_string_hex_encode (&plaintext, 0, 1257 response, 1258 _dbus_string_get_length (response))) 1259 goto failed; 1260 1261 _dbus_string_free (&plaintext); 1262 1263 return TRUE; 1264 1265 failed: 1266 _dbus_string_free (&plaintext); 1267 return FALSE; 1268} 1269 1270static dbus_bool_t 1271handle_client_data_anonymous_mech (DBusAuth *auth, 1272 const DBusString *data) 1273{ 1274 1275 return TRUE; 1276} 1277 1278static void 1279handle_client_shutdown_anonymous_mech (DBusAuth *auth) 1280{ 1281 1282} 1283 1284/* Put mechanisms here in order of preference. 1285 * Right now we have: 1286 * 1287 * - EXTERNAL checks socket credentials (or in the future, other info from the OS) 1288 * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE 1289 * - ANONYMOUS checks nothing but doesn't auth the person as a user 1290 * 1291 * We might ideally add a mechanism to chain to Cyrus SASL so we can 1292 * use its mechanisms as well. 1293 * 1294 */ 1295static const DBusAuthMechanismHandler 1296all_mechanisms[] = { 1297 { "EXTERNAL", 1298 handle_server_data_external_mech, 1299 NULL, NULL, 1300 handle_server_shutdown_external_mech, 1301 handle_client_initial_response_external_mech, 1302 handle_client_data_external_mech, 1303 NULL, NULL, 1304 handle_client_shutdown_external_mech }, 1305 { "DBUS_COOKIE_SHA1", 1306 handle_server_data_cookie_sha1_mech, 1307 NULL, NULL, 1308 handle_server_shutdown_cookie_sha1_mech, 1309 handle_client_initial_response_cookie_sha1_mech, 1310 handle_client_data_cookie_sha1_mech, 1311 NULL, NULL, 1312 handle_client_shutdown_cookie_sha1_mech }, 1313 { "ANONYMOUS", 1314 handle_server_data_anonymous_mech, 1315 NULL, NULL, 1316 handle_server_shutdown_anonymous_mech, 1317 handle_client_initial_response_anonymous_mech, 1318 handle_client_data_anonymous_mech, 1319 NULL, NULL, 1320 handle_client_shutdown_anonymous_mech }, 1321 { NULL, NULL } 1322}; 1323 1324static const DBusAuthMechanismHandler* 1325find_mech (const DBusString *name, 1326 char **allowed_mechs) 1327{ 1328 int i; 1329 1330 if (allowed_mechs != NULL && 1331 !_dbus_string_array_contains ((const char**) allowed_mechs, 1332 _dbus_string_get_const_data (name))) 1333 return NULL; 1334 1335 i = 0; 1336 while (all_mechanisms[i].mechanism != NULL) 1337 { 1338 if (_dbus_string_equal_c_str (name, 1339 all_mechanisms[i].mechanism)) 1340 1341 return &all_mechanisms[i]; 1342 1343 ++i; 1344 } 1345 1346 return NULL; 1347} 1348 1349static dbus_bool_t 1350send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) 1351{ 1352 DBusString auth_command; 1353 1354 if (!_dbus_string_init (&auth_command)) 1355 return FALSE; 1356 1357 if (!_dbus_string_append (&auth_command, 1358 "AUTH ")) 1359 { 1360 _dbus_string_free (&auth_command); 1361 return FALSE; 1362 } 1363 1364 if (!_dbus_string_append (&auth_command, 1365 mech->mechanism)) 1366 { 1367 _dbus_string_free (&auth_command); 1368 return FALSE; 1369 } 1370 1371 if (mech->client_initial_response_func != NULL) 1372 { 1373 if (!_dbus_string_append (&auth_command, " ")) 1374 { 1375 _dbus_string_free (&auth_command); 1376 return FALSE; 1377 } 1378 1379 if (!(* mech->client_initial_response_func) (auth, &auth_command)) 1380 { 1381 _dbus_string_free (&auth_command); 1382 return FALSE; 1383 } 1384 } 1385 1386 if (!_dbus_string_append (&auth_command, 1387 "\r\n")) 1388 { 1389 _dbus_string_free (&auth_command); 1390 return FALSE; 1391 } 1392 1393 if (!_dbus_string_copy (&auth_command, 0, 1394 &auth->outgoing, 1395 _dbus_string_get_length (&auth->outgoing))) 1396 { 1397 _dbus_string_free (&auth_command); 1398 return FALSE; 1399 } 1400 1401 _dbus_string_free (&auth_command); 1402 shutdown_mech (auth); 1403 auth->mech = mech; 1404 goto_state (auth, &client_state_waiting_for_data); 1405 1406 return TRUE; 1407} 1408 1409static dbus_bool_t 1410send_data (DBusAuth *auth, DBusString *data) 1411{ 1412 int old_len; 1413 1414 if (data == NULL || _dbus_string_get_length (data) == 0) 1415 return _dbus_string_append (&auth->outgoing, "DATA\r\n"); 1416 else 1417 { 1418 old_len = _dbus_string_get_length (&auth->outgoing); 1419 if (!_dbus_string_append (&auth->outgoing, "DATA ")) 1420 goto out; 1421 1422 if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, 1423 _dbus_string_get_length (&auth->outgoing))) 1424 goto out; 1425 1426 if (!_dbus_string_append (&auth->outgoing, "\r\n")) 1427 goto out; 1428 1429 return TRUE; 1430 1431 out: 1432 _dbus_string_set_length (&auth->outgoing, old_len); 1433 1434 return FALSE; 1435 } 1436} 1437 1438static dbus_bool_t 1439send_rejected (DBusAuth *auth) 1440{ 1441 DBusString command; 1442 DBusAuthServer *server_auth; 1443 int i; 1444 1445 if (!_dbus_string_init (&command)) 1446 return FALSE; 1447 1448 if (!_dbus_string_append (&command, 1449 "REJECTED")) 1450 goto nomem; 1451 1452 i = 0; 1453 while (all_mechanisms[i].mechanism != NULL) 1454 { 1455 if (!_dbus_string_append (&command, 1456 " ")) 1457 goto nomem; 1458 1459 if (!_dbus_string_append (&command, 1460 all_mechanisms[i].mechanism)) 1461 goto nomem; 1462 1463 ++i; 1464 } 1465 1466 if (!_dbus_string_append (&command, "\r\n")) 1467 goto nomem; 1468 1469 if (!_dbus_string_copy (&command, 0, &auth->outgoing, 1470 _dbus_string_get_length (&auth->outgoing))) 1471 goto nomem; 1472 1473 shutdown_mech (auth); 1474 1475 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 1476 server_auth = DBUS_AUTH_SERVER (auth); 1477 server_auth->failures += 1; 1478 1479 if (server_auth->failures >= server_auth->max_failures) 1480 goto_state (auth, &common_state_need_disconnect); 1481 else 1482 goto_state (auth, &server_state_waiting_for_auth); 1483 1484 _dbus_string_free (&command); 1485 1486 return TRUE; 1487 1488 nomem: 1489 _dbus_string_free (&command); 1490 return FALSE; 1491} 1492 1493static dbus_bool_t 1494send_error (DBusAuth *auth, const char *message) 1495{ 1496 return _dbus_string_append_printf (&auth->outgoing, 1497 "ERROR \"%s\"\r\n", message); 1498} 1499 1500static dbus_bool_t 1501send_ok (DBusAuth *auth) 1502{ 1503 int orig_len; 1504 1505 orig_len = _dbus_string_get_length (&auth->outgoing); 1506 1507 if (_dbus_string_append (&auth->outgoing, "OK ") && 1508 _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, 1509 0, 1510 &auth->outgoing, 1511 _dbus_string_get_length (&auth->outgoing)) && 1512 _dbus_string_append (&auth->outgoing, "\r\n")) 1513 { 1514 goto_state (auth, &server_state_waiting_for_begin); 1515 return TRUE; 1516 } 1517 else 1518 { 1519 _dbus_string_set_length (&auth->outgoing, orig_len); 1520 return FALSE; 1521 } 1522} 1523 1524static dbus_bool_t 1525send_begin (DBusAuth *auth, 1526 const DBusString *args_from_ok) 1527{ 1528 int end_of_hex; 1529 1530 /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ 1531 _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); 1532 1533 /* We decode the hex string to binary, using guid_from_server as scratch... */ 1534 1535 end_of_hex = 0; 1536 if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, 1537 & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) 1538 return FALSE; 1539 1540 /* now clear out the scratch */ 1541 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 1542 1543 if (end_of_hex != _dbus_string_get_length (args_from_ok) || 1544 end_of_hex == 0) 1545 { 1546 _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", 1547 end_of_hex, _dbus_string_get_length (args_from_ok)); 1548 goto_state (auth, &common_state_need_disconnect); 1549 return TRUE; 1550 } 1551 1552 if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) && 1553 _dbus_string_append (&auth->outgoing, "BEGIN\r\n")) 1554 { 1555 _dbus_verbose ("Got GUID '%s' from the server\n", 1556 _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); 1557 1558 goto_state (auth, &common_state_authenticated); 1559 return TRUE; 1560 } 1561 else 1562 { 1563 _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); 1564 return FALSE; 1565 } 1566} 1567 1568static dbus_bool_t 1569send_cancel (DBusAuth *auth) 1570{ 1571 if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) 1572 { 1573 goto_state (auth, &client_state_waiting_for_reject); 1574 return TRUE; 1575 } 1576 else 1577 return FALSE; 1578} 1579 1580static dbus_bool_t 1581process_data (DBusAuth *auth, 1582 const DBusString *args, 1583 DBusAuthDataFunction data_func) 1584{ 1585 int end; 1586 DBusString decoded; 1587 1588 if (!_dbus_string_init (&decoded)) 1589 return FALSE; 1590 1591 if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) 1592 { 1593 _dbus_string_free (&decoded); 1594 return FALSE; 1595 } 1596 1597 if (_dbus_string_get_length (args) != end) 1598 { 1599 _dbus_string_free (&decoded); 1600 if (!send_error (auth, "Invalid hex encoding")) 1601 return FALSE; 1602 1603 return TRUE; 1604 } 1605 1606#ifdef DBUS_ENABLE_VERBOSE_MODE 1607 if (_dbus_string_validate_ascii (&decoded, 0, 1608 _dbus_string_get_length (&decoded))) 1609 _dbus_verbose ("%s: data: '%s'\n", 1610 DBUS_AUTH_NAME (auth), 1611 _dbus_string_get_const_data (&decoded)); 1612#endif 1613 1614 if (!(* data_func) (auth, &decoded)) 1615 { 1616 _dbus_string_free (&decoded); 1617 return FALSE; 1618 } 1619 1620 _dbus_string_free (&decoded); 1621 return TRUE; 1622} 1623 1624static dbus_bool_t 1625handle_auth (DBusAuth *auth, const DBusString *args) 1626{ 1627 if (_dbus_string_get_length (args) == 0) 1628 { 1629 /* No args to the auth, send mechanisms */ 1630 if (!send_rejected (auth)) 1631 return FALSE; 1632 1633 return TRUE; 1634 } 1635 else 1636 { 1637 int i; 1638 DBusString mech; 1639 DBusString hex_response; 1640 1641 _dbus_string_find_blank (args, 0, &i); 1642 1643 if (!_dbus_string_init (&mech)) 1644 return FALSE; 1645 1646 if (!_dbus_string_init (&hex_response)) 1647 { 1648 _dbus_string_free (&mech); 1649 return FALSE; 1650 } 1651 1652 if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) 1653 goto failed; 1654 1655 _dbus_string_skip_blank (args, i, &i); 1656 if (!_dbus_string_copy (args, i, &hex_response, 0)) 1657 goto failed; 1658 1659 auth->mech = find_mech (&mech, auth->allowed_mechs); 1660 if (auth->mech != NULL) 1661 { 1662 _dbus_verbose ("%s: Trying mechanism %s\n", 1663 DBUS_AUTH_NAME (auth), 1664 auth->mech->mechanism); 1665 1666 if (!process_data (auth, &hex_response, 1667 auth->mech->server_data_func)) 1668 goto failed; 1669 } 1670 else 1671 { 1672 /* Unsupported mechanism */ 1673 _dbus_verbose ("%s: Unsupported mechanism %s\n", 1674 DBUS_AUTH_NAME (auth), 1675 _dbus_string_get_const_data (&mech)); 1676 1677 if (!send_rejected (auth)) 1678 goto failed; 1679 } 1680 1681 _dbus_string_free (&mech); 1682 _dbus_string_free (&hex_response); 1683 1684 return TRUE; 1685 1686 failed: 1687 auth->mech = NULL; 1688 _dbus_string_free (&mech); 1689 _dbus_string_free (&hex_response); 1690 return FALSE; 1691 } 1692} 1693 1694static dbus_bool_t 1695handle_server_state_waiting_for_auth (DBusAuth *auth, 1696 DBusAuthCommand command, 1697 const DBusString *args) 1698{ 1699 switch (command) 1700 { 1701 case DBUS_AUTH_COMMAND_AUTH: 1702 return handle_auth (auth, args); 1703 1704 case DBUS_AUTH_COMMAND_CANCEL: 1705 case DBUS_AUTH_COMMAND_DATA: 1706 return send_error (auth, "Not currently in an auth conversation"); 1707 1708 case DBUS_AUTH_COMMAND_BEGIN: 1709 goto_state (auth, &common_state_need_disconnect); 1710 return TRUE; 1711 1712 case DBUS_AUTH_COMMAND_ERROR: 1713 return send_rejected (auth); 1714 1715 case DBUS_AUTH_COMMAND_REJECTED: 1716 case DBUS_AUTH_COMMAND_OK: 1717 case DBUS_AUTH_COMMAND_UNKNOWN: 1718 default: 1719 return send_error (auth, "Unknown command"); 1720 } 1721} 1722 1723static dbus_bool_t 1724handle_server_state_waiting_for_data (DBusAuth *auth, 1725 DBusAuthCommand command, 1726 const DBusString *args) 1727{ 1728 switch (command) 1729 { 1730 case DBUS_AUTH_COMMAND_AUTH: 1731 return send_error (auth, "Sent AUTH while another AUTH in progress"); 1732 1733 case DBUS_AUTH_COMMAND_CANCEL: 1734 case DBUS_AUTH_COMMAND_ERROR: 1735 return send_rejected (auth); 1736 1737 case DBUS_AUTH_COMMAND_DATA: 1738 return process_data (auth, args, auth->mech->server_data_func); 1739 1740 case DBUS_AUTH_COMMAND_BEGIN: 1741 goto_state (auth, &common_state_need_disconnect); 1742 return TRUE; 1743 1744 case DBUS_AUTH_COMMAND_REJECTED: 1745 case DBUS_AUTH_COMMAND_OK: 1746 case DBUS_AUTH_COMMAND_UNKNOWN: 1747 default: 1748 return send_error (auth, "Unknown command"); 1749 } 1750} 1751 1752static dbus_bool_t 1753handle_server_state_waiting_for_begin (DBusAuth *auth, 1754 DBusAuthCommand command, 1755 const DBusString *args) 1756{ 1757 switch (command) 1758 { 1759 case DBUS_AUTH_COMMAND_AUTH: 1760 return send_error (auth, "Sent AUTH while expecting BEGIN"); 1761 1762 case DBUS_AUTH_COMMAND_DATA: 1763 return send_error (auth, "Sent DATA while expecting BEGIN"); 1764 1765 case DBUS_AUTH_COMMAND_BEGIN: 1766 goto_state (auth, &common_state_authenticated); 1767 return TRUE; 1768 1769 case DBUS_AUTH_COMMAND_REJECTED: 1770 case DBUS_AUTH_COMMAND_OK: 1771 case DBUS_AUTH_COMMAND_UNKNOWN: 1772 default: 1773 return send_error (auth, "Unknown command"); 1774 1775 case DBUS_AUTH_COMMAND_CANCEL: 1776 case DBUS_AUTH_COMMAND_ERROR: 1777 return send_rejected (auth); 1778 } 1779} 1780 1781/* return FALSE if no memory, TRUE if all OK */ 1782static dbus_bool_t 1783get_word (const DBusString *str, 1784 int *start, 1785 DBusString *word) 1786{ 1787 int i; 1788 1789 _dbus_string_skip_blank (str, *start, start); 1790 _dbus_string_find_blank (str, *start, &i); 1791 1792 if (i > *start) 1793 { 1794 if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) 1795 return FALSE; 1796 1797 *start = i; 1798 } 1799 1800 return TRUE; 1801} 1802 1803static dbus_bool_t 1804record_mechanisms (DBusAuth *auth, 1805 const DBusString *args) 1806{ 1807 int next; 1808 int len; 1809 1810 if (auth->already_got_mechanisms) 1811 return TRUE; 1812 1813 len = _dbus_string_get_length (args); 1814 1815 next = 0; 1816 while (next < len) 1817 { 1818 DBusString m; 1819 const DBusAuthMechanismHandler *mech; 1820 1821 if (!_dbus_string_init (&m)) 1822 goto nomem; 1823 1824 if (!get_word (args, &next, &m)) 1825 { 1826 _dbus_string_free (&m); 1827 goto nomem; 1828 } 1829 1830 mech = find_mech (&m, auth->allowed_mechs); 1831 1832 if (mech != NULL) 1833 { 1834 /* FIXME right now we try mechanisms in the order 1835 * the server lists them; should we do them in 1836 * some more deterministic order? 1837 * 1838 * Probably in all_mechanisms order, our order of 1839 * preference. Of course when the server is us, 1840 * it lists things in that order anyhow. 1841 */ 1842 1843 if (mech != &all_mechanisms[0]) 1844 { 1845 _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", 1846 DBUS_AUTH_NAME (auth), mech->mechanism); 1847 1848 if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, 1849 (void*) mech)) 1850 { 1851 _dbus_string_free (&m); 1852 goto nomem; 1853 } 1854 } 1855 else 1856 { 1857 _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", 1858 DBUS_AUTH_NAME (auth), mech->mechanism); 1859 } 1860 } 1861 else 1862 { 1863 _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", 1864 DBUS_AUTH_NAME (auth), 1865 _dbus_string_get_const_data (&m)); 1866 } 1867 1868 _dbus_string_free (&m); 1869 } 1870 1871 auth->already_got_mechanisms = TRUE; 1872 1873 return TRUE; 1874 1875 nomem: 1876 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 1877 1878 return FALSE; 1879} 1880 1881static dbus_bool_t 1882process_rejected (DBusAuth *auth, const DBusString *args) 1883{ 1884 const DBusAuthMechanismHandler *mech; 1885 DBusAuthClient *client; 1886 1887 client = DBUS_AUTH_CLIENT (auth); 1888 1889 if (!auth->already_got_mechanisms) 1890 { 1891 if (!record_mechanisms (auth, args)) 1892 return FALSE; 1893 } 1894 1895 if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) 1896 { 1897 mech = client->mechs_to_try->data; 1898 1899 if (!send_auth (auth, mech)) 1900 return FALSE; 1901 1902 _dbus_list_pop_first (&client->mechs_to_try); 1903 1904 _dbus_verbose ("%s: Trying mechanism %s\n", 1905 DBUS_AUTH_NAME (auth), 1906 mech->mechanism); 1907 } 1908 else 1909 { 1910 /* Give up */ 1911 _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", 1912 DBUS_AUTH_NAME (auth)); 1913 goto_state (auth, &common_state_need_disconnect); 1914 } 1915 1916 return TRUE; 1917} 1918 1919 1920static dbus_bool_t 1921handle_client_state_waiting_for_data (DBusAuth *auth, 1922 DBusAuthCommand command, 1923 const DBusString *args) 1924{ 1925 _dbus_assert (auth->mech != NULL); 1926 1927 switch (command) 1928 { 1929 case DBUS_AUTH_COMMAND_DATA: 1930 return process_data (auth, args, auth->mech->client_data_func); 1931 1932 case DBUS_AUTH_COMMAND_REJECTED: 1933 return process_rejected (auth, args); 1934 1935 case DBUS_AUTH_COMMAND_OK: 1936 return send_begin (auth, args); 1937 1938 case DBUS_AUTH_COMMAND_ERROR: 1939 return send_cancel (auth); 1940 1941 case DBUS_AUTH_COMMAND_AUTH: 1942 case DBUS_AUTH_COMMAND_CANCEL: 1943 case DBUS_AUTH_COMMAND_BEGIN: 1944 case DBUS_AUTH_COMMAND_UNKNOWN: 1945 default: 1946 return send_error (auth, "Unknown command"); 1947 } 1948} 1949 1950static dbus_bool_t 1951handle_client_state_waiting_for_ok (DBusAuth *auth, 1952 DBusAuthCommand command, 1953 const DBusString *args) 1954{ 1955 switch (command) 1956 { 1957 case DBUS_AUTH_COMMAND_REJECTED: 1958 return process_rejected (auth, args); 1959 1960 case DBUS_AUTH_COMMAND_OK: 1961 return send_begin (auth, args); 1962 1963 case DBUS_AUTH_COMMAND_DATA: 1964 case DBUS_AUTH_COMMAND_ERROR: 1965 return send_cancel (auth); 1966 1967 case DBUS_AUTH_COMMAND_AUTH: 1968 case DBUS_AUTH_COMMAND_CANCEL: 1969 case DBUS_AUTH_COMMAND_BEGIN: 1970 case DBUS_AUTH_COMMAND_UNKNOWN: 1971 default: 1972 return send_error (auth, "Unknown command"); 1973 } 1974} 1975 1976static dbus_bool_t 1977handle_client_state_waiting_for_reject (DBusAuth *auth, 1978 DBusAuthCommand command, 1979 const DBusString *args) 1980{ 1981 switch (command) 1982 { 1983 case DBUS_AUTH_COMMAND_REJECTED: 1984 return process_rejected (auth, args); 1985 1986 case DBUS_AUTH_COMMAND_AUTH: 1987 case DBUS_AUTH_COMMAND_CANCEL: 1988 case DBUS_AUTH_COMMAND_DATA: 1989 case DBUS_AUTH_COMMAND_BEGIN: 1990 case DBUS_AUTH_COMMAND_OK: 1991 case DBUS_AUTH_COMMAND_ERROR: 1992 case DBUS_AUTH_COMMAND_UNKNOWN: 1993 default: 1994 goto_state (auth, &common_state_need_disconnect); 1995 return TRUE; 1996 } 1997} 1998 1999/** 2000 * Mapping from command name to enum 2001 */ 2002typedef struct { 2003 const char *name; /**< Name of the command */ 2004 DBusAuthCommand command; /**< Corresponding enum */ 2005} DBusAuthCommandName; 2006 2007static const DBusAuthCommandName auth_command_names[] = { 2008 { "AUTH", DBUS_AUTH_COMMAND_AUTH }, 2009 { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, 2010 { "DATA", DBUS_AUTH_COMMAND_DATA }, 2011 { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, 2012 { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, 2013 { "OK", DBUS_AUTH_COMMAND_OK }, 2014 { "ERROR", DBUS_AUTH_COMMAND_ERROR } 2015}; 2016 2017static DBusAuthCommand 2018lookup_command_from_name (DBusString *command) 2019{ 2020 int i; 2021 2022 for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) 2023 { 2024 if (_dbus_string_equal_c_str (command, 2025 auth_command_names[i].name)) 2026 return auth_command_names[i].command; 2027 } 2028 2029 return DBUS_AUTH_COMMAND_UNKNOWN; 2030} 2031 2032static void 2033goto_state (DBusAuth *auth, 2034 const DBusAuthStateData *state) 2035{ 2036 _dbus_verbose ("%s: going from state %s to state %s\n", 2037 DBUS_AUTH_NAME (auth), 2038 auth->state->name, 2039 state->name); 2040 2041 auth->state = state; 2042} 2043 2044/* returns whether to call it again right away */ 2045static dbus_bool_t 2046process_command (DBusAuth *auth) 2047{ 2048 DBusAuthCommand command; 2049 DBusString line; 2050 DBusString args; 2051 int eol; 2052 int i, j; 2053 dbus_bool_t retval; 2054 2055 /* _dbus_verbose ("%s: trying process_command()\n"); */ 2056 2057 retval = FALSE; 2058 2059 eol = 0; 2060 if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) 2061 return FALSE; 2062 2063 if (!_dbus_string_init (&line)) 2064 { 2065 auth->needed_memory = TRUE; 2066 return FALSE; 2067 } 2068 2069 if (!_dbus_string_init (&args)) 2070 { 2071 _dbus_string_free (&line); 2072 auth->needed_memory = TRUE; 2073 return FALSE; 2074 } 2075 2076 if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) 2077 goto out; 2078 2079 if (!_dbus_string_validate_ascii (&line, 0, 2080 _dbus_string_get_length (&line))) 2081 { 2082 _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", 2083 DBUS_AUTH_NAME (auth)); 2084 if (!send_error (auth, "Command contained non-ASCII")) 2085 goto out; 2086 else 2087 goto next_command; 2088 } 2089 2090 _dbus_verbose ("%s: got command \"%s\"\n", 2091 DBUS_AUTH_NAME (auth), 2092 _dbus_string_get_const_data (&line)); 2093 2094 _dbus_string_find_blank (&line, 0, &i); 2095 _dbus_string_skip_blank (&line, i, &j); 2096 2097 if (j > i) 2098 _dbus_string_delete (&line, i, j - i); 2099 2100 if (!_dbus_string_move (&line, i, &args, 0)) 2101 goto out; 2102 2103 /* FIXME 1.0 we should probably validate that only the allowed 2104 * chars are in the command name 2105 */ 2106 2107 command = lookup_command_from_name (&line); 2108 if (!(* auth->state->handler) (auth, command, &args)) 2109 goto out; 2110 2111 next_command: 2112 2113 /* We've succeeded in processing the whole command so drop it out 2114 * of the incoming buffer and return TRUE to try another command. 2115 */ 2116 2117 _dbus_string_delete (&auth->incoming, 0, eol); 2118 2119 /* kill the \r\n */ 2120 _dbus_string_delete (&auth->incoming, 0, 2); 2121 2122 retval = TRUE; 2123 2124 out: 2125 _dbus_string_free (&args); 2126 _dbus_string_free (&line); 2127 2128 if (!retval) 2129 auth->needed_memory = TRUE; 2130 else 2131 auth->needed_memory = FALSE; 2132 2133 return retval; 2134} 2135 2136 2137/** @} */ 2138 2139/** 2140 * @addtogroup DBusAuth 2141 * @{ 2142 */ 2143 2144/** 2145 * Creates a new auth conversation object for the server side. 2146 * See doc/dbus-sasl-profile.txt for full details on what 2147 * this object does. 2148 * 2149 * @returns the new object or #NULL if no memory 2150 */ 2151DBusAuth* 2152_dbus_auth_server_new (const DBusString *guid) 2153{ 2154 DBusAuth *auth; 2155 DBusAuthServer *server_auth; 2156 DBusString guid_copy; 2157 2158 if (!_dbus_string_init (&guid_copy)) 2159 return NULL; 2160 2161 if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) 2162 { 2163 _dbus_string_free (&guid_copy); 2164 return NULL; 2165 } 2166 2167 auth = _dbus_auth_new (sizeof (DBusAuthServer)); 2168 if (auth == NULL) 2169 { 2170 _dbus_string_free (&guid_copy); 2171 return NULL; 2172 } 2173 2174 auth->side = auth_side_server; 2175 auth->state = &server_state_waiting_for_auth; 2176 2177 server_auth = DBUS_AUTH_SERVER (auth); 2178 2179 server_auth->guid = guid_copy; 2180 2181 /* perhaps this should be per-mechanism with a lower 2182 * max 2183 */ 2184 server_auth->failures = 0; 2185 server_auth->max_failures = 6; 2186 2187 return auth; 2188} 2189 2190/** 2191 * Creates a new auth conversation object for the client side. 2192 * See doc/dbus-sasl-profile.txt for full details on what 2193 * this object does. 2194 * 2195 * @returns the new object or #NULL if no memory 2196 */ 2197DBusAuth* 2198_dbus_auth_client_new (void) 2199{ 2200 DBusAuth *auth; 2201 DBusString guid_str; 2202 2203 if (!_dbus_string_init (&guid_str)) 2204 return NULL; 2205 2206 auth = _dbus_auth_new (sizeof (DBusAuthClient)); 2207 if (auth == NULL) 2208 { 2209 _dbus_string_free (&guid_str); 2210 return NULL; 2211 } 2212 2213 DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; 2214 2215 auth->side = auth_side_client; 2216 auth->state = &client_state_need_send_auth; 2217 2218 /* Start the auth conversation by sending AUTH for our default 2219 * mechanism */ 2220 if (!send_auth (auth, &all_mechanisms[0])) 2221 { 2222 _dbus_auth_unref (auth); 2223 return NULL; 2224 } 2225 2226 return auth; 2227} 2228 2229/** 2230 * Increments the refcount of an auth object. 2231 * 2232 * @param auth the auth conversation 2233 * @returns the auth conversation 2234 */ 2235DBusAuth * 2236_dbus_auth_ref (DBusAuth *auth) 2237{ 2238 _dbus_assert (auth != NULL); 2239 2240 auth->refcount += 1; 2241 2242 return auth; 2243} 2244 2245/** 2246 * Decrements the refcount of an auth object. 2247 * 2248 * @param auth the auth conversation 2249 */ 2250void 2251_dbus_auth_unref (DBusAuth *auth) 2252{ 2253 _dbus_assert (auth != NULL); 2254 _dbus_assert (auth->refcount > 0); 2255 2256 auth->refcount -= 1; 2257 if (auth->refcount == 0) 2258 { 2259 shutdown_mech (auth); 2260 2261 if (DBUS_AUTH_IS_CLIENT (auth)) 2262 { 2263 _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 2264 _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); 2265 } 2266 else 2267 { 2268 _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); 2269 2270 _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); 2271 } 2272 2273 if (auth->keyring) 2274 _dbus_keyring_unref (auth->keyring); 2275 2276 _dbus_string_free (&auth->context); 2277 _dbus_string_free (&auth->challenge); 2278 _dbus_string_free (&auth->identity); 2279 _dbus_string_free (&auth->incoming); 2280 _dbus_string_free (&auth->outgoing); 2281 2282 dbus_free_string_array (auth->allowed_mechs); 2283 2284 _dbus_credentials_unref (auth->credentials); 2285 _dbus_credentials_unref (auth->authorized_identity); 2286 _dbus_credentials_unref (auth->desired_identity); 2287 2288 dbus_free (auth); 2289 } 2290} 2291 2292/** 2293 * Sets an array of authentication mechanism names 2294 * that we are willing to use. 2295 * 2296 * @param auth the auth conversation 2297 * @param mechanisms #NULL-terminated array of mechanism names 2298 * @returns #FALSE if no memory 2299 */ 2300dbus_bool_t 2301_dbus_auth_set_mechanisms (DBusAuth *auth, 2302 const char **mechanisms) 2303{ 2304 char **copy; 2305 2306 if (mechanisms != NULL) 2307 { 2308 copy = _dbus_dup_string_array (mechanisms); 2309 if (copy == NULL) 2310 return FALSE; 2311 } 2312 else 2313 copy = NULL; 2314 2315 dbus_free_string_array (auth->allowed_mechs); 2316 2317 auth->allowed_mechs = copy; 2318 2319 return TRUE; 2320} 2321 2322/** 2323 * @param auth the auth conversation object 2324 * @returns #TRUE if we're in a final state 2325 */ 2326#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) 2327 2328/** 2329 * Analyzes buffered input and moves the auth conversation forward, 2330 * returning the new state of the auth conversation. 2331 * 2332 * @param auth the auth conversation 2333 * @returns the new state 2334 */ 2335DBusAuthState 2336_dbus_auth_do_work (DBusAuth *auth) 2337{ 2338 auth->needed_memory = FALSE; 2339 2340 /* Max amount we'll buffer up before deciding someone's on crack */ 2341#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) 2342 2343 do 2344 { 2345 if (DBUS_AUTH_IN_END_STATE (auth)) 2346 break; 2347 2348 if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || 2349 _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) 2350 { 2351 goto_state (auth, &common_state_need_disconnect); 2352 _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", 2353 DBUS_AUTH_NAME (auth)); 2354 break; 2355 } 2356 } 2357 while (process_command (auth)); 2358 2359 if (auth->needed_memory) 2360 return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; 2361 else if (_dbus_string_get_length (&auth->outgoing) > 0) 2362 return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; 2363 else if (auth->state == &common_state_need_disconnect) 2364 return DBUS_AUTH_STATE_NEED_DISCONNECT; 2365 else if (auth->state == &common_state_authenticated) 2366 return DBUS_AUTH_STATE_AUTHENTICATED; 2367 else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; 2368} 2369 2370/** 2371 * Gets bytes that need to be sent to the peer we're conversing with. 2372 * After writing some bytes, _dbus_auth_bytes_sent() must be called 2373 * to notify the auth object that they were written. 2374 * 2375 * @param auth the auth conversation 2376 * @param str return location for a ref to the buffer to send 2377 * @returns #FALSE if nothing to send 2378 */ 2379dbus_bool_t 2380_dbus_auth_get_bytes_to_send (DBusAuth *auth, 2381 const DBusString **str) 2382{ 2383 _dbus_assert (auth != NULL); 2384 _dbus_assert (str != NULL); 2385 2386 *str = NULL; 2387 2388 if (_dbus_string_get_length (&auth->outgoing) == 0) 2389 return FALSE; 2390 2391 *str = &auth->outgoing; 2392 2393 return TRUE; 2394} 2395 2396/** 2397 * Notifies the auth conversation object that 2398 * the given number of bytes of the outgoing buffer 2399 * have been written out. 2400 * 2401 * @param auth the auth conversation 2402 * @param bytes_sent number of bytes written out 2403 */ 2404void 2405_dbus_auth_bytes_sent (DBusAuth *auth, 2406 int bytes_sent) 2407{ 2408 _dbus_verbose ("%s: Sent %d bytes of: %s\n", 2409 DBUS_AUTH_NAME (auth), 2410 bytes_sent, 2411 _dbus_string_get_const_data (&auth->outgoing)); 2412 2413 _dbus_string_delete (&auth->outgoing, 2414 0, bytes_sent); 2415} 2416 2417/** 2418 * Get a buffer to be used for reading bytes from the peer we're conversing 2419 * with. Bytes should be appended to this buffer. 2420 * 2421 * @param auth the auth conversation 2422 * @param buffer return location for buffer to append bytes to 2423 */ 2424void 2425_dbus_auth_get_buffer (DBusAuth *auth, 2426 DBusString **buffer) 2427{ 2428 _dbus_assert (auth != NULL); 2429 _dbus_assert (!auth->buffer_outstanding); 2430 2431 *buffer = &auth->incoming; 2432 2433 auth->buffer_outstanding = TRUE; 2434} 2435 2436/** 2437 * Returns a buffer with new data read into it. 2438 * 2439 * @param auth the auth conversation 2440 * @param buffer the buffer being returned 2441 * @param bytes_read number of new bytes added 2442 */ 2443void 2444_dbus_auth_return_buffer (DBusAuth *auth, 2445 DBusString *buffer, 2446 int bytes_read) 2447{ 2448 _dbus_assert (buffer == &auth->incoming); 2449 _dbus_assert (auth->buffer_outstanding); 2450 2451 auth->buffer_outstanding = FALSE; 2452} 2453 2454/** 2455 * Returns leftover bytes that were not used as part of the auth 2456 * conversation. These bytes will be part of the message stream 2457 * instead. This function may not be called until authentication has 2458 * succeeded. 2459 * 2460 * @param auth the auth conversation 2461 * @param str return location for pointer to string of unused bytes 2462 */ 2463void 2464_dbus_auth_get_unused_bytes (DBusAuth *auth, 2465 const DBusString **str) 2466{ 2467 if (!DBUS_AUTH_IN_END_STATE (auth)) 2468 return; 2469 2470 *str = &auth->incoming; 2471} 2472 2473 2474/** 2475 * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes() 2476 * after we've gotten them and successfully moved them elsewhere. 2477 * 2478 * @param auth the auth conversation 2479 */ 2480void 2481_dbus_auth_delete_unused_bytes (DBusAuth *auth) 2482{ 2483 if (!DBUS_AUTH_IN_END_STATE (auth)) 2484 return; 2485 2486 _dbus_string_set_length (&auth->incoming, 0); 2487} 2488 2489/** 2490 * Called post-authentication, indicates whether we need to encode 2491 * the message stream with _dbus_auth_encode_data() prior to 2492 * sending it to the peer. 2493 * 2494 * @param auth the auth conversation 2495 * @returns #TRUE if we need to encode the stream 2496 */ 2497dbus_bool_t 2498_dbus_auth_needs_encoding (DBusAuth *auth) 2499{ 2500 if (auth->state != &common_state_authenticated) 2501 return FALSE; 2502 2503 if (auth->mech != NULL) 2504 { 2505 if (DBUS_AUTH_IS_CLIENT (auth)) 2506 return auth->mech->client_encode_func != NULL; 2507 else 2508 return auth->mech->server_encode_func != NULL; 2509 } 2510 else 2511 return FALSE; 2512} 2513 2514/** 2515 * Called post-authentication, encodes a block of bytes for sending to 2516 * the peer. If no encoding was negotiated, just copies the bytes 2517 * (you can avoid this by checking _dbus_auth_needs_encoding()). 2518 * 2519 * @param auth the auth conversation 2520 * @param plaintext the plain text data 2521 * @param encoded initialized string to where encoded data is appended 2522 * @returns #TRUE if we had enough memory and successfully encoded 2523 */ 2524dbus_bool_t 2525_dbus_auth_encode_data (DBusAuth *auth, 2526 const DBusString *plaintext, 2527 DBusString *encoded) 2528{ 2529 _dbus_assert (plaintext != encoded); 2530 2531 if (auth->state != &common_state_authenticated) 2532 return FALSE; 2533 2534 if (_dbus_auth_needs_encoding (auth)) 2535 { 2536 if (DBUS_AUTH_IS_CLIENT (auth)) 2537 return (* auth->mech->client_encode_func) (auth, plaintext, encoded); 2538 else 2539 return (* auth->mech->server_encode_func) (auth, plaintext, encoded); 2540 } 2541 else 2542 { 2543 return _dbus_string_copy (plaintext, 0, encoded, 2544 _dbus_string_get_length (encoded)); 2545 } 2546} 2547 2548/** 2549 * Called post-authentication, indicates whether we need to decode 2550 * the message stream with _dbus_auth_decode_data() after 2551 * receiving it from the peer. 2552 * 2553 * @param auth the auth conversation 2554 * @returns #TRUE if we need to encode the stream 2555 */ 2556dbus_bool_t 2557_dbus_auth_needs_decoding (DBusAuth *auth) 2558{ 2559 if (auth->state != &common_state_authenticated) 2560 return FALSE; 2561 2562 if (auth->mech != NULL) 2563 { 2564 if (DBUS_AUTH_IS_CLIENT (auth)) 2565 return auth->mech->client_decode_func != NULL; 2566 else 2567 return auth->mech->server_decode_func != NULL; 2568 } 2569 else 2570 return FALSE; 2571} 2572 2573 2574/** 2575 * Called post-authentication, decodes a block of bytes received from 2576 * the peer. If no encoding was negotiated, just copies the bytes (you 2577 * can avoid this by checking _dbus_auth_needs_decoding()). 2578 * 2579 * @todo 1.0? We need to be able to distinguish "out of memory" error 2580 * from "the data is hosed" error. 2581 * 2582 * @param auth the auth conversation 2583 * @param encoded the encoded data 2584 * @param plaintext initialized string where decoded data is appended 2585 * @returns #TRUE if we had enough memory and successfully decoded 2586 */ 2587dbus_bool_t 2588_dbus_auth_decode_data (DBusAuth *auth, 2589 const DBusString *encoded, 2590 DBusString *plaintext) 2591{ 2592 _dbus_assert (plaintext != encoded); 2593 2594 if (auth->state != &common_state_authenticated) 2595 return FALSE; 2596 2597 if (_dbus_auth_needs_decoding (auth)) 2598 { 2599 if (DBUS_AUTH_IS_CLIENT (auth)) 2600 return (* auth->mech->client_decode_func) (auth, encoded, plaintext); 2601 else 2602 return (* auth->mech->server_decode_func) (auth, encoded, plaintext); 2603 } 2604 else 2605 { 2606 return _dbus_string_copy (encoded, 0, plaintext, 2607 _dbus_string_get_length (plaintext)); 2608 } 2609} 2610 2611/** 2612 * Sets credentials received via reliable means from the operating 2613 * system. 2614 * 2615 * @param auth the auth conversation 2616 * @param credentials the credentials received 2617 * @returns #FALSE on OOM 2618 */ 2619dbus_bool_t 2620_dbus_auth_set_credentials (DBusAuth *auth, 2621 DBusCredentials *credentials) 2622{ 2623 _dbus_credentials_clear (auth->credentials); 2624 return _dbus_credentials_add_credentials (auth->credentials, 2625 credentials); 2626} 2627 2628/** 2629 * Gets the identity we authorized the client as. Apps may have 2630 * different policies as to what identities they allow. 2631 * 2632 * Returned credentials are not a copy and should not be modified 2633 * 2634 * @param auth the auth conversation 2635 * @returns the credentials we've authorized BY REFERENCE do not modify 2636 */ 2637DBusCredentials* 2638_dbus_auth_get_identity (DBusAuth *auth) 2639{ 2640 if (auth->state == &common_state_authenticated) 2641 { 2642 return auth->authorized_identity; 2643 } 2644 else 2645 { 2646 /* FIXME instead of this, keep an empty credential around that 2647 * doesn't require allocation or something 2648 */ 2649 /* return empty credentials */ 2650 _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); 2651 return auth->authorized_identity; 2652 } 2653} 2654 2655/** 2656 * Gets the GUID from the server if we've authenticated; gets 2657 * #NULL otherwise. 2658 * @param auth the auth object 2659 * @returns the GUID in ASCII hex format 2660 */ 2661const char* 2662_dbus_auth_get_guid_from_server (DBusAuth *auth) 2663{ 2664 _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); 2665 2666 if (auth->state == &common_state_authenticated) 2667 return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); 2668 else 2669 return NULL; 2670} 2671 2672/** 2673 * Sets the "authentication context" which scopes cookies 2674 * with the DBUS_COOKIE_SHA1 auth mechanism for example. 2675 * 2676 * @param auth the auth conversation 2677 * @param context the context 2678 * @returns #FALSE if no memory 2679 */ 2680dbus_bool_t 2681_dbus_auth_set_context (DBusAuth *auth, 2682 const DBusString *context) 2683{ 2684 return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), 2685 &auth->context, 0, _dbus_string_get_length (context)); 2686} 2687 2688/** @} */ 2689 2690/* tests in dbus-auth-util.c */ 2691