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