1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-keyring.c Store secret cookies in your homedir 3 * 4 * Copyright (C) 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-keyring.h" 26#include "dbus-protocol.h" 27#include <dbus/dbus-string.h> 28#include <dbus/dbus-list.h> 29#include <dbus/dbus-sysdeps.h> 30 31/** 32 * @defgroup DBusKeyring keyring class 33 * @ingroup DBusInternals 34 * @brief DBusKeyring data structure 35 * 36 * Types and functions related to DBusKeyring. DBusKeyring is intended 37 * to manage cookies used to authenticate clients to servers. This is 38 * essentially the "verify that client can read the user's homedir" 39 * authentication mechanism. Both client and server must have access 40 * to the homedir. 41 * 42 * The secret keys are not kept in locked memory, and are written to a 43 * file in the user's homedir. However they are transient (only used 44 * by a single server instance for a fixed period of time, then 45 * discarded). Also, the keys are not sent over the wire. 46 * 47 * @todo there's a memory leak on some codepath in here, I saw it once 48 * when running make check - probably some specific initial cookies 49 * present in the cookie file, then depending on what we do with them. 50 */ 51 52/** 53 * @defgroup DBusKeyringInternals DBusKeyring implementation details 54 * @ingroup DBusInternals 55 * @brief DBusKeyring implementation details 56 * 57 * The guts of DBusKeyring. 58 * 59 * @{ 60 */ 61 62/** The maximum age of a key before we create a new key to use in 63 * challenges. This isn't super-reliably enforced, since system 64 * clocks can change or be wrong, but we make a best effort to only 65 * use keys for a short time. 66 */ 67#define NEW_KEY_TIMEOUT_SECONDS (60*5) 68/** 69 * The time after which we drop a key from the secrets file. 70 * The EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS is the minimum 71 * time window a client has to complete authentication. 72 */ 73#define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2)) 74/** 75 * The maximum amount of time a key can be in the future. 76 */ 77#define MAX_TIME_TRAVEL_SECONDS (60*5) 78 79/** 80 * Maximum number of keys in the keyring before 81 * we just ignore the rest 82 */ 83#ifdef DBUS_BUILD_TESTS 84#define MAX_KEYS_IN_FILE 10 85#else 86#define MAX_KEYS_IN_FILE 256 87#endif 88 89/** 90 * A single key from the cookie file 91 */ 92typedef struct 93{ 94 dbus_int32_t id; /**< identifier used to refer to the key */ 95 96 long creation_time; /**< when the key was generated, 97 * as unix timestamp. signed long 98 * matches struct timeval. 99 */ 100 101 DBusString secret; /**< the actual key */ 102 103} DBusKey; 104 105/** 106 * @brief Internals of DBusKeyring. 107 * 108 * DBusKeyring internals. DBusKeyring is an opaque object, it must be 109 * used via accessor functions. 110 */ 111struct DBusKeyring 112{ 113 int refcount; /**< Reference count */ 114 DBusString directory; /**< Directory the below two items are inside */ 115 DBusString filename; /**< Keyring filename */ 116 DBusString filename_lock; /**< Name of lockfile */ 117 DBusKey *keys; /**< Keys loaded from the file */ 118 int n_keys; /**< Number of keys */ 119 DBusCredentials *credentials; /**< Credentials containing user the keyring is for */ 120}; 121 122static DBusKeyring* 123_dbus_keyring_new (void) 124{ 125 DBusKeyring *keyring; 126 127 keyring = dbus_new0 (DBusKeyring, 1); 128 if (keyring == NULL) 129 goto out_0; 130 131 if (!_dbus_string_init (&keyring->directory)) 132 goto out_1; 133 134 if (!_dbus_string_init (&keyring->filename)) 135 goto out_2; 136 137 if (!_dbus_string_init (&keyring->filename_lock)) 138 goto out_3; 139 140 keyring->refcount = 1; 141 keyring->keys = NULL; 142 keyring->n_keys = 0; 143 144 return keyring; 145 146 /* out_4: */ 147 _dbus_string_free (&keyring->filename_lock); 148 out_3: 149 _dbus_string_free (&keyring->filename); 150 out_2: 151 _dbus_string_free (&keyring->directory); 152 out_1: 153 dbus_free (keyring); 154 out_0: 155 return NULL; 156} 157 158static void 159free_keys (DBusKey *keys, 160 int n_keys) 161{ 162 int i; 163 164 /* should be safe for args NULL, 0 */ 165 166 i = 0; 167 while (i < n_keys) 168 { 169 _dbus_string_free (&keys[i].secret); 170 ++i; 171 } 172 173 dbus_free (keys); 174} 175 176/* Our locking scheme is highly unreliable. However, there is 177 * unfortunately no reliable locking scheme in user home directories; 178 * between bugs in Linux NFS, people using Tru64 or other total crap 179 * NFS, AFS, random-file-system-of-the-week, and so forth, fcntl() in 180 * homedirs simply generates tons of bug reports. This has been 181 * learned through hard experience with GConf, unfortunately. 182 * 183 * This bad hack might work better for the kind of lock we have here, 184 * which we don't expect to hold for any length of time. Crashing 185 * while we hold it should be unlikely, and timing out such that we 186 * delete a stale lock should also be unlikely except when the 187 * filesystem is running really slowly. Stuff might break in corner 188 * cases but as long as it's not a security-level breakage it should 189 * be OK. 190 */ 191 192/** Maximum number of timeouts waiting for lock before we decide it's stale */ 193#define MAX_LOCK_TIMEOUTS 32 194/** Length of each timeout while waiting for a lock */ 195#define LOCK_TIMEOUT_MILLISECONDS 250 196 197static dbus_bool_t 198_dbus_keyring_lock (DBusKeyring *keyring) 199{ 200 int n_timeouts; 201 202 n_timeouts = 0; 203 while (n_timeouts < MAX_LOCK_TIMEOUTS) 204 { 205 DBusError error = DBUS_ERROR_INIT; 206 207 if (_dbus_create_file_exclusively (&keyring->filename_lock, 208 &error)) 209 break; 210 211 _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n", 212 LOCK_TIMEOUT_MILLISECONDS, error.message); 213 dbus_error_free (&error); 214 215 _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS); 216 217 ++n_timeouts; 218 } 219 220 if (n_timeouts == MAX_LOCK_TIMEOUTS) 221 { 222 DBusError error = DBUS_ERROR_INIT; 223 224 _dbus_verbose ("Lock file timed out %d times, assuming stale\n", 225 n_timeouts); 226 227 if (!_dbus_delete_file (&keyring->filename_lock, &error)) 228 { 229 _dbus_verbose ("Couldn't delete old lock file: %s\n", 230 error.message); 231 dbus_error_free (&error); 232 return FALSE; 233 } 234 235 if (!_dbus_create_file_exclusively (&keyring->filename_lock, 236 &error)) 237 { 238 _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n", 239 error.message); 240 dbus_error_free (&error); 241 return FALSE; 242 } 243 } 244 245 return TRUE; 246} 247 248static void 249_dbus_keyring_unlock (DBusKeyring *keyring) 250{ 251 DBusError error = DBUS_ERROR_INIT; 252 253 if (!_dbus_delete_file (&keyring->filename_lock, &error)) 254 { 255 _dbus_warn ("Failed to delete lock file: %s\n", 256 error.message); 257 dbus_error_free (&error); 258 } 259} 260 261static DBusKey* 262find_key_by_id (DBusKey *keys, 263 int n_keys, 264 int id) 265{ 266 int i; 267 268 i = 0; 269 while (i < n_keys) 270 { 271 if (keys[i].id == id) 272 return &keys[i]; 273 274 ++i; 275 } 276 277 return NULL; 278} 279 280static dbus_bool_t 281add_new_key (DBusKey **keys_p, 282 int *n_keys_p, 283 DBusError *error) 284{ 285 DBusKey *new; 286 DBusString bytes; 287 int id; 288 long timestamp; 289 const unsigned char *s; 290 dbus_bool_t retval; 291 DBusKey *keys; 292 int n_keys; 293 294 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 295 296 if (!_dbus_string_init (&bytes)) 297 { 298 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 299 return FALSE; 300 } 301 302 keys = *keys_p; 303 n_keys = *n_keys_p; 304 retval = FALSE; 305 306 /* Generate an integer ID and then the actual key. */ 307 retry: 308 309 if (!_dbus_generate_random_bytes (&bytes, 4)) 310 { 311 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 312 goto out; 313 } 314 315 s = (const unsigned char*) _dbus_string_get_const_data (&bytes); 316 317 id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); 318 if (id < 0) 319 id = - id; 320 _dbus_assert (id >= 0); 321 322 if (find_key_by_id (keys, n_keys, id) != NULL) 323 { 324 _dbus_string_set_length (&bytes, 0); 325 _dbus_verbose ("Key ID %d already existed, trying another one\n", 326 id); 327 goto retry; 328 } 329 330 _dbus_verbose ("Creating key with ID %d\n", id); 331 332#define KEY_LENGTH_BYTES 24 333 _dbus_string_set_length (&bytes, 0); 334 if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES)) 335 { 336 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 337 goto out; 338 } 339 340 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); 341 if (new == NULL) 342 { 343 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 344 goto out; 345 } 346 347 keys = new; 348 *keys_p = keys; /* otherwise *keys_p ends up invalid */ 349 n_keys += 1; 350 351 if (!_dbus_string_init (&keys[n_keys-1].secret)) 352 { 353 n_keys -= 1; /* we don't want to free the one we didn't init */ 354 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 355 goto out; 356 } 357 358 _dbus_get_current_time (×tamp, NULL); 359 360 keys[n_keys-1].id = id; 361 keys[n_keys-1].creation_time = timestamp; 362 if (!_dbus_string_move (&bytes, 0, 363 &keys[n_keys-1].secret, 364 0)) 365 { 366 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 367 _dbus_string_free (&keys[n_keys-1].secret); 368 n_keys -= 1; 369 goto out; 370 } 371 372 retval = TRUE; 373 374 out: 375 *n_keys_p = n_keys; 376 377 _dbus_string_free (&bytes); 378 return retval; 379} 380 381/** 382 * Reloads the keyring file, optionally adds one new key to the file, 383 * removes all expired keys from the file iff a key was added, then 384 * resaves the file. Stores the keys from the file in keyring->keys. 385 * Note that the file is only resaved (written to) if a key is added, 386 * this means that only servers ever write to the file and need to 387 * lock it, which avoids a lot of lock contention at login time and 388 * such. 389 * 390 * @param keyring the keyring 391 * @param add_new #TRUE to add a new key to the file, expire keys, and resave 392 * @param error return location for errors 393 * @returns #FALSE on failure 394 */ 395static dbus_bool_t 396_dbus_keyring_reload (DBusKeyring *keyring, 397 dbus_bool_t add_new, 398 DBusError *error) 399{ 400 DBusString contents; 401 DBusString line; 402 dbus_bool_t retval; 403 dbus_bool_t have_lock; 404 DBusKey *keys; 405 int n_keys; 406 int i; 407 long now; 408 DBusError tmp_error; 409 410 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 411 412 if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error)) 413 return FALSE; 414 415 if (!_dbus_string_init (&contents)) 416 { 417 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 418 return FALSE; 419 } 420 421 if (!_dbus_string_init (&line)) 422 { 423 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 424 _dbus_string_free (&contents); 425 return FALSE; 426 } 427 428 keys = NULL; 429 n_keys = 0; 430 retval = FALSE; 431 have_lock = FALSE; 432 433 _dbus_get_current_time (&now, NULL); 434 435 if (add_new) 436 { 437 if (!_dbus_keyring_lock (keyring)) 438 { 439 dbus_set_error (error, DBUS_ERROR_FAILED, 440 "Could not lock keyring file to add to it"); 441 goto out; 442 } 443 444 have_lock = TRUE; 445 } 446 447 dbus_error_init (&tmp_error); 448 if (!_dbus_file_get_contents (&contents, 449 &keyring->filename, 450 &tmp_error)) 451 { 452 _dbus_verbose ("Failed to load keyring file: %s\n", 453 tmp_error.message); 454 /* continue with empty keyring file, so we recreate it */ 455 dbus_error_free (&tmp_error); 456 } 457 458 if (!_dbus_string_validate_ascii (&contents, 0, 459 _dbus_string_get_length (&contents))) 460 { 461 _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n"); 462 _dbus_string_set_length (&contents, 0); 463 } 464 465 /* FIXME this is badly inefficient for large keyring files 466 * (not that large keyring files exist outside of test suites) 467 */ 468 while (_dbus_string_pop_line (&contents, &line)) 469 { 470 int next; 471 long val; 472 int id; 473 long timestamp; 474 int len; 475 int end; 476 DBusKey *new; 477 478 /* Don't load more than the max. */ 479 if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE)) 480 break; 481 482 next = 0; 483 if (!_dbus_string_parse_int (&line, 0, &val, &next)) 484 { 485 _dbus_verbose ("could not parse secret key ID at start of line\n"); 486 continue; 487 } 488 489 if (val > _DBUS_INT32_MAX || val < 0) 490 { 491 _dbus_verbose ("invalid secret key ID at start of line\n"); 492 continue; 493 } 494 495 id = val; 496 497 _dbus_string_skip_blank (&line, next, &next); 498 499 if (!_dbus_string_parse_int (&line, next, ×tamp, &next)) 500 { 501 _dbus_verbose ("could not parse secret key timestamp\n"); 502 continue; 503 } 504 505 if (timestamp < 0 || 506 (now + MAX_TIME_TRAVEL_SECONDS) < timestamp || 507 (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp) 508 { 509 _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n", 510 now - timestamp, timestamp, now); 511 continue; 512 } 513 514 _dbus_string_skip_blank (&line, next, &next); 515 516 len = _dbus_string_get_length (&line); 517 518 if ((len - next) == 0) 519 { 520 _dbus_verbose ("no secret key after ID and timestamp\n"); 521 continue; 522 } 523 524 /* We have all three parts */ 525 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); 526 if (new == NULL) 527 { 528 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 529 goto out; 530 } 531 532 keys = new; 533 n_keys += 1; 534 535 if (!_dbus_string_init (&keys[n_keys-1].secret)) 536 { 537 n_keys -= 1; /* we don't want to free the one we didn't init */ 538 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 539 goto out; 540 } 541 542 keys[n_keys-1].id = id; 543 keys[n_keys-1].creation_time = timestamp; 544 if (!_dbus_string_hex_decode (&line, next, &end, 545 &keys[n_keys-1].secret, 0)) 546 { 547 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 548 goto out; 549 } 550 551 if (_dbus_string_get_length (&line) != end) 552 { 553 _dbus_verbose ("invalid hex encoding in keyring file\n"); 554 _dbus_string_free (&keys[n_keys - 1].secret); 555 n_keys -= 1; 556 continue; 557 } 558 } 559 560 _dbus_verbose ("Successfully loaded %d existing keys\n", 561 n_keys); 562 563 if (add_new) 564 { 565 if (!add_new_key (&keys, &n_keys, error)) 566 { 567 _dbus_verbose ("Failed to generate new key: %s\n", 568 error ? error->message : "(unknown)"); 569 goto out; 570 } 571 572 _dbus_string_set_length (&contents, 0); 573 574 i = 0; 575 while (i < n_keys) 576 { 577 if (!_dbus_string_append_int (&contents, 578 keys[i].id)) 579 goto nomem; 580 581 if (!_dbus_string_append_byte (&contents, ' ')) 582 goto nomem; 583 584 if (!_dbus_string_append_int (&contents, 585 keys[i].creation_time)) 586 goto nomem; 587 588 if (!_dbus_string_append_byte (&contents, ' ')) 589 goto nomem; 590 591 if (!_dbus_string_hex_encode (&keys[i].secret, 0, 592 &contents, 593 _dbus_string_get_length (&contents))) 594 goto nomem; 595 596 if (!_dbus_string_append_byte (&contents, '\n')) 597 goto nomem; 598 599 ++i; 600 continue; 601 602 nomem: 603 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 604 goto out; 605 } 606 607 if (!_dbus_string_save_to_file (&contents, &keyring->filename, 608 FALSE, error)) 609 goto out; 610 } 611 612 if (keyring->keys) 613 free_keys (keyring->keys, keyring->n_keys); 614 keyring->keys = keys; 615 keyring->n_keys = n_keys; 616 keys = NULL; 617 n_keys = 0; 618 619 retval = TRUE; 620 621 out: 622 if (have_lock) 623 _dbus_keyring_unlock (keyring); 624 625 if (! ((retval == TRUE && (error == NULL || error->name == NULL)) || 626 (retval == FALSE && (error == NULL || error->name != NULL)))) 627 { 628 if (error && error->name) 629 _dbus_verbose ("error is %s: %s\n", error->name, error->message); 630 _dbus_warn ("returning %d but error pointer %p name %s\n", 631 retval, error, error->name ? error->name : "(none)"); 632 _dbus_assert_not_reached ("didn't handle errors properly"); 633 } 634 635 if (keys != NULL) 636 { 637 i = 0; 638 while (i < n_keys) 639 { 640 _dbus_string_zero (&keys[i].secret); 641 _dbus_string_free (&keys[i].secret); 642 ++i; 643 } 644 645 dbus_free (keys); 646 } 647 648 _dbus_string_free (&contents); 649 _dbus_string_free (&line); 650 651 return retval; 652} 653 654/** @} */ /* end of internals */ 655 656/** 657 * @addtogroup DBusKeyring 658 * 659 * @{ 660 */ 661 662/** 663 * Increments reference count of the keyring 664 * 665 * @param keyring the keyring 666 * @returns the keyring 667 */ 668DBusKeyring * 669_dbus_keyring_ref (DBusKeyring *keyring) 670{ 671 keyring->refcount += 1; 672 673 return keyring; 674} 675 676/** 677 * Decrements refcount and finalizes if it reaches 678 * zero. 679 * 680 * @param keyring the keyring 681 */ 682void 683_dbus_keyring_unref (DBusKeyring *keyring) 684{ 685 keyring->refcount -= 1; 686 687 if (keyring->refcount == 0) 688 { 689 if (keyring->credentials) 690 _dbus_credentials_unref (keyring->credentials); 691 692 _dbus_string_free (&keyring->filename); 693 _dbus_string_free (&keyring->filename_lock); 694 _dbus_string_free (&keyring->directory); 695 free_keys (keyring->keys, keyring->n_keys); 696 dbus_free (keyring); 697 } 698} 699 700/** 701 * Creates a new keyring that lives in the ~/.dbus-keyrings directory 702 * of the given user credentials. If the credentials are #NULL or 703 * empty, uses those of the current process. 704 * 705 * @param username username to get keyring for, or #NULL 706 * @param context which keyring to get 707 * @param error return location for errors 708 * @returns the keyring or #NULL on error 709 */ 710DBusKeyring* 711_dbus_keyring_new_for_credentials (DBusCredentials *credentials, 712 const DBusString *context, 713 DBusError *error) 714{ 715 DBusString ringdir; 716 DBusKeyring *keyring; 717 dbus_bool_t error_set; 718 DBusError tmp_error; 719 DBusCredentials *our_credentials; 720 721 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 722 723 keyring = NULL; 724 error_set = FALSE; 725 our_credentials = NULL; 726 727 if (!_dbus_string_init (&ringdir)) 728 { 729 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 730 return NULL; 731 } 732 733 if (credentials != NULL) 734 { 735 our_credentials = _dbus_credentials_copy (credentials); 736 } 737 else 738 { 739 our_credentials = _dbus_credentials_new_from_current_process (); 740 } 741 742 if (our_credentials == NULL) 743 goto failed; 744 745 if (_dbus_credentials_are_anonymous (our_credentials)) 746 { 747 if (!_dbus_credentials_add_from_current_process (our_credentials)) 748 goto failed; 749 } 750 751 if (!_dbus_append_keyring_directory_for_credentials (&ringdir, 752 our_credentials)) 753 goto failed; 754 755 keyring = _dbus_keyring_new (); 756 if (keyring == NULL) 757 goto failed; 758 759 _dbus_assert (keyring->credentials == NULL); 760 keyring->credentials = our_credentials; 761 our_credentials = NULL; /* so we don't unref it again later */ 762 763 /* should have been validated already, but paranoia check here */ 764 if (!_dbus_keyring_validate_context (context)) 765 { 766 error_set = TRUE; 767 dbus_set_error_const (error, 768 DBUS_ERROR_FAILED, 769 "Invalid context in keyring creation"); 770 goto failed; 771 } 772 773 /* Save keyring dir in the keyring object */ 774 if (!_dbus_string_copy (&ringdir, 0, 775 &keyring->directory, 0)) 776 goto failed; 777 778 /* Create keyring->filename based on keyring dir and context */ 779 if (!_dbus_string_copy (&keyring->directory, 0, 780 &keyring->filename, 0)) 781 goto failed; 782 783 if (!_dbus_concat_dir_and_file (&keyring->filename, 784 context)) 785 goto failed; 786 787 /* Create lockfile name */ 788 if (!_dbus_string_copy (&keyring->filename, 0, 789 &keyring->filename_lock, 0)) 790 goto failed; 791 792 if (!_dbus_string_append (&keyring->filename_lock, ".lock")) 793 goto failed; 794 795 /* Reload keyring */ 796 dbus_error_init (&tmp_error); 797 if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error)) 798 { 799 _dbus_verbose ("didn't load an existing keyring: %s\n", 800 tmp_error.message); 801 dbus_error_free (&tmp_error); 802 } 803 804 /* We don't fail fatally if we can't create the directory, 805 * but the keyring will probably always be empty 806 * unless someone else manages to create it 807 */ 808 dbus_error_init (&tmp_error); 809 if (!_dbus_create_directory (&keyring->directory, 810 &tmp_error)) 811 { 812 _dbus_verbose ("Creating keyring directory: %s\n", 813 tmp_error.message); 814 dbus_error_free (&tmp_error); 815 } 816 817 _dbus_string_free (&ringdir); 818 819 return keyring; 820 821 failed: 822 if (!error_set) 823 dbus_set_error_const (error, 824 DBUS_ERROR_NO_MEMORY, 825 NULL); 826 if (our_credentials) 827 _dbus_credentials_unref (our_credentials); 828 if (keyring) 829 _dbus_keyring_unref (keyring); 830 _dbus_string_free (&ringdir); 831 return NULL; 832 833} 834 835/** 836 * Checks whether the context is a valid context. 837 * Contexts that might cause confusion when used 838 * in filenames are not allowed (contexts can't 839 * start with a dot or contain dir separators). 840 * 841 * @todo this is the most inefficient implementation 842 * imaginable. 843 * 844 * @param context the context 845 * @returns #TRUE if valid 846 */ 847dbus_bool_t 848_dbus_keyring_validate_context (const DBusString *context) 849{ 850 if (_dbus_string_get_length (context) == 0) 851 { 852 _dbus_verbose ("context is zero-length\n"); 853 return FALSE; 854 } 855 856 if (!_dbus_string_validate_ascii (context, 0, 857 _dbus_string_get_length (context))) 858 { 859 _dbus_verbose ("context not valid ascii\n"); 860 return FALSE; 861 } 862 863 /* no directory separators */ 864 if (_dbus_string_find (context, 0, "/", NULL)) 865 { 866 _dbus_verbose ("context contains a slash\n"); 867 return FALSE; 868 } 869 870 if (_dbus_string_find (context, 0, "\\", NULL)) 871 { 872 _dbus_verbose ("context contains a backslash\n"); 873 return FALSE; 874 } 875 876 /* prevent attempts to use dotfiles or ".." or ".lock" 877 * all of which might allow some kind of attack 878 */ 879 if (_dbus_string_find (context, 0, ".", NULL)) 880 { 881 _dbus_verbose ("context contains a dot\n"); 882 return FALSE; 883 } 884 885 /* no spaces/tabs, those are used for separators in the protocol */ 886 if (_dbus_string_find_blank (context, 0, NULL)) 887 { 888 _dbus_verbose ("context contains a blank\n"); 889 return FALSE; 890 } 891 892 if (_dbus_string_find (context, 0, "\n", NULL)) 893 { 894 _dbus_verbose ("context contains a newline\n"); 895 return FALSE; 896 } 897 898 if (_dbus_string_find (context, 0, "\r", NULL)) 899 { 900 _dbus_verbose ("context contains a carriage return\n"); 901 return FALSE; 902 } 903 904 return TRUE; 905} 906 907static DBusKey* 908find_recent_key (DBusKeyring *keyring) 909{ 910 int i; 911 long tv_sec, tv_usec; 912 913 _dbus_get_current_time (&tv_sec, &tv_usec); 914 915 i = 0; 916 while (i < keyring->n_keys) 917 { 918 DBusKey *key = &keyring->keys[i]; 919 920 _dbus_verbose ("Key %d is %ld seconds old\n", 921 i, tv_sec - key->creation_time); 922 923 if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time) 924 return key; 925 926 ++i; 927 } 928 929 return NULL; 930} 931 932/** 933 * Gets a recent key to use for authentication. 934 * If no recent key exists, creates one. Returns 935 * the key ID. If a key can't be written to the keyring 936 * file so no recent key can be created, returns -1. 937 * All valid keys are > 0. 938 * 939 * @param keyring the keyring 940 * @param error error on failure 941 * @returns key ID to use for auth, or -1 on failure 942 */ 943int 944_dbus_keyring_get_best_key (DBusKeyring *keyring, 945 DBusError *error) 946{ 947 DBusKey *key; 948 949 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 950 951 key = find_recent_key (keyring); 952 if (key) 953 return key->id; 954 955 /* All our keys are too old, or we've never loaded the 956 * keyring. Create a new one. 957 */ 958 if (!_dbus_keyring_reload (keyring, TRUE, 959 error)) 960 return -1; 961 962 key = find_recent_key (keyring); 963 if (key) 964 return key->id; 965 else 966 { 967 dbus_set_error_const (error, 968 DBUS_ERROR_FAILED, 969 "No recent-enough key found in keyring, and unable to create a new key"); 970 return -1; 971 } 972} 973 974/** 975 * Checks whether the keyring is for the same user as the given credentials. 976 * 977 * @param keyring the keyring 978 * @param credentials the credentials to check 979 * 980 * @returns #TRUE if the keyring belongs to the given user 981 */ 982dbus_bool_t 983_dbus_keyring_is_for_credentials (DBusKeyring *keyring, 984 DBusCredentials *credentials) 985{ 986 return _dbus_credentials_same_user (keyring->credentials, 987 credentials); 988} 989 990/** 991 * Gets the hex-encoded secret key for the given ID. 992 * Returns #FALSE if not enough memory. Returns #TRUE 993 * but empty key on any other error such as unknown 994 * key ID. 995 * 996 * @param keyring the keyring 997 * @param key_id the key ID 998 * @param hex_key string to append hex-encoded key to 999 * @returns #TRUE if we had enough memory 1000 */ 1001dbus_bool_t 1002_dbus_keyring_get_hex_key (DBusKeyring *keyring, 1003 int key_id, 1004 DBusString *hex_key) 1005{ 1006 DBusKey *key; 1007 1008 key = find_key_by_id (keyring->keys, 1009 keyring->n_keys, 1010 key_id); 1011 if (key == NULL) 1012 return TRUE; /* had enough memory, so TRUE */ 1013 1014 return _dbus_string_hex_encode (&key->secret, 0, 1015 hex_key, 1016 _dbus_string_get_length (hex_key)); 1017} 1018 1019/** @} */ /* end of exposed API */ 1020 1021#ifdef DBUS_BUILD_TESTS 1022#include "dbus-test.h" 1023#include <stdio.h> 1024 1025dbus_bool_t 1026_dbus_keyring_test (void) 1027{ 1028 DBusString context; 1029 DBusKeyring *ring1; 1030 DBusKeyring *ring2; 1031 int id; 1032 DBusError error; 1033 int i; 1034 1035 ring1 = NULL; 1036 ring2 = NULL; 1037 1038 /* Context validation */ 1039 1040 _dbus_string_init_const (&context, "foo"); 1041 _dbus_assert (_dbus_keyring_validate_context (&context)); 1042 _dbus_string_init_const (&context, "org_freedesktop_blah"); 1043 _dbus_assert (_dbus_keyring_validate_context (&context)); 1044 1045 _dbus_string_init_const (&context, ""); 1046 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1047 _dbus_string_init_const (&context, ".foo"); 1048 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1049 _dbus_string_init_const (&context, "bar.foo"); 1050 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1051 _dbus_string_init_const (&context, "bar/foo"); 1052 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1053 _dbus_string_init_const (&context, "bar\\foo"); 1054 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1055 _dbus_string_init_const (&context, "foo\xfa\xf0"); 1056 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1057 _dbus_string_init_const (&context, "foo\x80"); 1058 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1059 _dbus_string_init_const (&context, "foo\x7f"); 1060 _dbus_assert (_dbus_keyring_validate_context (&context)); 1061 _dbus_string_init_const (&context, "foo bar"); 1062 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1063 1064 if (!_dbus_string_init (&context)) 1065 _dbus_assert_not_reached ("no memory"); 1066 if (!_dbus_string_append_byte (&context, '\0')) 1067 _dbus_assert_not_reached ("no memory"); 1068 _dbus_assert (!_dbus_keyring_validate_context (&context)); 1069 _dbus_string_free (&context); 1070 1071 /* Now verify that if we create a key in keyring 1, 1072 * it is properly loaded in keyring 2 1073 */ 1074 1075 _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite"); 1076 dbus_error_init (&error); 1077 ring1 = _dbus_keyring_new_for_credentials (NULL, &context, 1078 &error); 1079 _dbus_assert (ring1 != NULL); 1080 _dbus_assert (error.name == NULL); 1081 1082 id = _dbus_keyring_get_best_key (ring1, &error); 1083 if (id < 0) 1084 { 1085 fprintf (stderr, "Could not load keyring: %s\n", error.message); 1086 dbus_error_free (&error); 1087 goto failure; 1088 } 1089 1090 ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error); 1091 _dbus_assert (ring2 != NULL); 1092 _dbus_assert (error.name == NULL); 1093 1094 if (ring1->n_keys != ring2->n_keys) 1095 { 1096 fprintf (stderr, "Different number of keys in keyrings\n"); 1097 goto failure; 1098 } 1099 1100 /* We guarantee we load and save keeping keys in a fixed 1101 * order 1102 */ 1103 i = 0; 1104 while (i < ring1->n_keys) 1105 { 1106 if (ring1->keys[i].id != ring2->keys[i].id) 1107 { 1108 fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n", 1109 ring1->keys[i].id, ring2->keys[i].id); 1110 goto failure; 1111 } 1112 1113 if (ring1->keys[i].creation_time != ring2->keys[i].creation_time) 1114 { 1115 fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n", 1116 ring1->keys[i].creation_time, ring2->keys[i].creation_time); 1117 goto failure; 1118 } 1119 1120 if (!_dbus_string_equal (&ring1->keys[i].secret, 1121 &ring2->keys[i].secret)) 1122 { 1123 fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n"); 1124 goto failure; 1125 } 1126 1127 ++i; 1128 } 1129 1130 printf (" %d keys in test\n", ring1->n_keys); 1131 1132 /* Test ref/unref */ 1133 _dbus_keyring_ref (ring1); 1134 _dbus_keyring_ref (ring2); 1135 _dbus_keyring_unref (ring1); 1136 _dbus_keyring_unref (ring2); 1137 1138 1139 /* really unref */ 1140 _dbus_keyring_unref (ring1); 1141 _dbus_keyring_unref (ring2); 1142 1143 return TRUE; 1144 1145 failure: 1146 if (ring1) 1147 _dbus_keyring_unref (ring1); 1148 if (ring2) 1149 _dbus_keyring_unref (ring2); 1150 1151 return FALSE; 1152} 1153 1154#endif /* DBUS_BUILD_TESTS */ 1155 1156