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