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