00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-keyring.h"
00025 #include "dbus-userdb.h"
00026 #include "dbus-protocol.h"
00027 #include <dbus/dbus-string.h>
00028 #include <dbus/dbus-list.h>
00029 #include <dbus/dbus-sysdeps.h>
00030
00067 #define NEW_KEY_TIMEOUT_SECONDS (60*5)
00068
00073 #define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2))
00074
00077 #define MAX_TIME_TRAVEL_SECONDS (60*5)
00078
00083 #ifdef DBUS_BUILD_TESTS
00084 #define MAX_KEYS_IN_FILE 10
00085 #else
00086 #define MAX_KEYS_IN_FILE 256
00087 #endif
00088
00092 typedef struct
00093 {
00094 dbus_int32_t id;
00096 long creation_time;
00101 DBusString secret;
00103 } DBusKey;
00104
00111 struct DBusKeyring
00112 {
00113 int refcount;
00114 DBusString username;
00115 DBusString directory;
00116 DBusString filename;
00117 DBusString filename_lock;
00118 DBusKey *keys;
00119 int n_keys;
00120 };
00121
00122 static DBusKeyring*
00123 _dbus_keyring_new (void)
00124 {
00125 DBusKeyring *keyring;
00126
00127 keyring = dbus_new0 (DBusKeyring, 1);
00128 if (keyring == NULL)
00129 goto out_0;
00130
00131 if (!_dbus_string_init (&keyring->directory))
00132 goto out_1;
00133
00134 if (!_dbus_string_init (&keyring->filename))
00135 goto out_2;
00136
00137 if (!_dbus_string_init (&keyring->filename_lock))
00138 goto out_3;
00139
00140 if (!_dbus_string_init (&keyring->username))
00141 goto out_4;
00142
00143 keyring->refcount = 1;
00144 keyring->keys = NULL;
00145 keyring->n_keys = 0;
00146
00147 return keyring;
00148
00149 out_4:
00150 _dbus_string_free (&keyring->filename_lock);
00151 out_3:
00152 _dbus_string_free (&keyring->filename);
00153 out_2:
00154 _dbus_string_free (&keyring->directory);
00155 out_1:
00156 dbus_free (keyring);
00157 out_0:
00158 return NULL;
00159 }
00160
00161 static void
00162 free_keys (DBusKey *keys,
00163 int n_keys)
00164 {
00165 int i;
00166
00167
00168
00169 i = 0;
00170 while (i < n_keys)
00171 {
00172 _dbus_string_free (&keys[i].secret);
00173 ++i;
00174 }
00175
00176 dbus_free (keys);
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00196 #define MAX_LOCK_TIMEOUTS 32
00197
00198 #define LOCK_TIMEOUT_MILLISECONDS 250
00199
00200 static dbus_bool_t
00201 _dbus_keyring_lock (DBusKeyring *keyring)
00202 {
00203 int n_timeouts;
00204
00205 n_timeouts = 0;
00206 while (n_timeouts < MAX_LOCK_TIMEOUTS)
00207 {
00208 DBusError error;
00209
00210 dbus_error_init (&error);
00211 if (_dbus_create_file_exclusively (&keyring->filename_lock,
00212 &error))
00213 break;
00214
00215 _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n",
00216 LOCK_TIMEOUT_MILLISECONDS, error.message);
00217 dbus_error_free (&error);
00218
00219 _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS);
00220
00221 ++n_timeouts;
00222 }
00223
00224 if (n_timeouts == MAX_LOCK_TIMEOUTS)
00225 {
00226 DBusError error;
00227
00228 _dbus_verbose ("Lock file timed out %d times, assuming stale\n",
00229 n_timeouts);
00230
00231 dbus_error_init (&error);
00232
00233 if (!_dbus_delete_file (&keyring->filename_lock, &error))
00234 {
00235 _dbus_verbose ("Couldn't delete old lock file: %s\n",
00236 error.message);
00237 dbus_error_free (&error);
00238 return FALSE;
00239 }
00240
00241 if (!_dbus_create_file_exclusively (&keyring->filename_lock,
00242 &error))
00243 {
00244 _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n",
00245 error.message);
00246 dbus_error_free (&error);
00247 return FALSE;
00248 }
00249 }
00250
00251 return TRUE;
00252 }
00253
00254 static void
00255 _dbus_keyring_unlock (DBusKeyring *keyring)
00256 {
00257 DBusError error;
00258 dbus_error_init (&error);
00259 if (!_dbus_delete_file (&keyring->filename_lock, &error))
00260 {
00261 _dbus_warn ("Failed to delete lock file: %s\n",
00262 error.message);
00263 dbus_error_free (&error);
00264 }
00265 }
00266
00267 static DBusKey*
00268 find_key_by_id (DBusKey *keys,
00269 int n_keys,
00270 int id)
00271 {
00272 int i;
00273
00274 i = 0;
00275 while (i < n_keys)
00276 {
00277 if (keys[i].id == id)
00278 return &keys[i];
00279
00280 ++i;
00281 }
00282
00283 return NULL;
00284 }
00285
00286 static dbus_bool_t
00287 add_new_key (DBusKey **keys_p,
00288 int *n_keys_p,
00289 DBusError *error)
00290 {
00291 DBusKey *new;
00292 DBusString bytes;
00293 int id;
00294 long timestamp;
00295 const unsigned char *s;
00296 dbus_bool_t retval;
00297 DBusKey *keys;
00298 int n_keys;
00299
00300 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00301
00302 if (!_dbus_string_init (&bytes))
00303 {
00304 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00305 return FALSE;
00306 }
00307
00308 keys = *keys_p;
00309 n_keys = *n_keys_p;
00310 retval = FALSE;
00311
00312
00313 retry:
00314
00315 if (!_dbus_generate_random_bytes (&bytes, 4))
00316 {
00317 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00318 goto out;
00319 }
00320
00321 s = (const unsigned char*) _dbus_string_get_const_data (&bytes);
00322
00323 id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
00324 if (id < 0)
00325 id = - id;
00326 _dbus_assert (id >= 0);
00327
00328 if (find_key_by_id (keys, n_keys, id) != NULL)
00329 {
00330 _dbus_string_set_length (&bytes, 0);
00331 _dbus_verbose ("Key ID %d already existed, trying another one\n",
00332 id);
00333 goto retry;
00334 }
00335
00336 _dbus_verbose ("Creating key with ID %d\n", id);
00337
00338 #define KEY_LENGTH_BYTES 24
00339 _dbus_string_set_length (&bytes, 0);
00340 if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES))
00341 {
00342 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00343 goto out;
00344 }
00345
00346 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1));
00347 if (new == NULL)
00348 {
00349 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00350 goto out;
00351 }
00352
00353 keys = new;
00354 *keys_p = keys;
00355 n_keys += 1;
00356
00357 if (!_dbus_string_init (&keys[n_keys-1].secret))
00358 {
00359 n_keys -= 1;
00360 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00361 goto out;
00362 }
00363
00364 _dbus_get_current_time (×tamp, NULL);
00365
00366 keys[n_keys-1].id = id;
00367 keys[n_keys-1].creation_time = timestamp;
00368 if (!_dbus_string_move (&bytes, 0,
00369 &keys[n_keys-1].secret,
00370 0))
00371 {
00372 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00373 _dbus_string_free (&keys[n_keys-1].secret);
00374 n_keys -= 1;
00375 goto out;
00376 }
00377
00378 retval = TRUE;
00379
00380 out:
00381 *n_keys_p = n_keys;
00382
00383 _dbus_string_free (&bytes);
00384 return retval;
00385 }
00386
00401 static dbus_bool_t
00402 _dbus_keyring_reload (DBusKeyring *keyring,
00403 dbus_bool_t add_new,
00404 DBusError *error)
00405 {
00406 DBusString contents;
00407 DBusString line;
00408 dbus_bool_t retval;
00409 dbus_bool_t have_lock;
00410 DBusKey *keys;
00411 int n_keys;
00412 int i;
00413 long now;
00414 DBusError tmp_error;
00415
00416 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00417
00418 if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error))
00419 return FALSE;
00420
00421 if (!_dbus_string_init (&contents))
00422 {
00423 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00424 return FALSE;
00425 }
00426
00427 if (!_dbus_string_init (&line))
00428 {
00429 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00430 _dbus_string_free (&contents);
00431 return FALSE;
00432 }
00433
00434 keys = NULL;
00435 n_keys = 0;
00436 retval = FALSE;
00437 have_lock = FALSE;
00438
00439 _dbus_get_current_time (&now, NULL);
00440
00441 if (add_new)
00442 {
00443 if (!_dbus_keyring_lock (keyring))
00444 {
00445 dbus_set_error (error, DBUS_ERROR_FAILED,
00446 "Could not lock keyring file to add to it");
00447 goto out;
00448 }
00449
00450 have_lock = TRUE;
00451 }
00452
00453 dbus_error_init (&tmp_error);
00454 if (!_dbus_file_get_contents (&contents,
00455 &keyring->filename,
00456 &tmp_error))
00457 {
00458 _dbus_verbose ("Failed to load keyring file: %s\n",
00459 tmp_error.message);
00460
00461 dbus_error_free (&tmp_error);
00462 }
00463
00464 if (!_dbus_string_validate_ascii (&contents, 0,
00465 _dbus_string_get_length (&contents)))
00466 {
00467 _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n");
00468 _dbus_string_set_length (&contents, 0);
00469 }
00470
00471
00472
00473
00474 while (_dbus_string_pop_line (&contents, &line))
00475 {
00476 int next;
00477 long val;
00478 int id;
00479 long timestamp;
00480 int len;
00481 int end;
00482 DBusKey *new;
00483
00484
00485 if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE))
00486 break;
00487
00488 next = 0;
00489 if (!_dbus_string_parse_int (&line, 0, &val, &next))
00490 {
00491 _dbus_verbose ("could not parse secret key ID at start of line\n");
00492 continue;
00493 }
00494
00495 if (val > _DBUS_INT32_MAX || val < 0)
00496 {
00497 _dbus_verbose ("invalid secret key ID at start of line\n");
00498 continue;
00499 }
00500
00501 id = val;
00502
00503 _dbus_string_skip_blank (&line, next, &next);
00504
00505 if (!_dbus_string_parse_int (&line, next, ×tamp, &next))
00506 {
00507 _dbus_verbose ("could not parse secret key timestamp\n");
00508 continue;
00509 }
00510
00511 if (timestamp < 0 ||
00512 (now + MAX_TIME_TRAVEL_SECONDS) < timestamp ||
00513 (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp)
00514 {
00515 _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n",
00516 now - timestamp, timestamp, now);
00517 continue;
00518 }
00519
00520 _dbus_string_skip_blank (&line, next, &next);
00521
00522 len = _dbus_string_get_length (&line);
00523
00524 if ((len - next) == 0)
00525 {
00526 _dbus_verbose ("no secret key after ID and timestamp\n");
00527 continue;
00528 }
00529
00530
00531 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1));
00532 if (new == NULL)
00533 {
00534 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00535 goto out;
00536 }
00537
00538 keys = new;
00539 n_keys += 1;
00540
00541 if (!_dbus_string_init (&keys[n_keys-1].secret))
00542 {
00543 n_keys -= 1;
00544 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00545 goto out;
00546 }
00547
00548 keys[n_keys-1].id = id;
00549 keys[n_keys-1].creation_time = timestamp;
00550 if (!_dbus_string_hex_decode (&line, next, &end,
00551 &keys[n_keys-1].secret, 0))
00552 {
00553 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00554 goto out;
00555 }
00556
00557 if (_dbus_string_get_length (&line) != end)
00558 {
00559 _dbus_verbose ("invalid hex encoding in keyring file\n");
00560 _dbus_string_free (&keys[n_keys - 1].secret);
00561 n_keys -= 1;
00562 continue;
00563 }
00564 }
00565
00566 _dbus_verbose ("Successfully loaded %d existing keys\n",
00567 n_keys);
00568
00569 if (add_new)
00570 {
00571 if (!add_new_key (&keys, &n_keys, error))
00572 {
00573 _dbus_verbose ("Failed to generate new key: %s\n",
00574 error ? error->message : "(unknown)");
00575 goto out;
00576 }
00577
00578 _dbus_string_set_length (&contents, 0);
00579
00580 i = 0;
00581 while (i < n_keys)
00582 {
00583 if (!_dbus_string_append_int (&contents,
00584 keys[i].id))
00585 goto nomem;
00586
00587 if (!_dbus_string_append_byte (&contents, ' '))
00588 goto nomem;
00589
00590 if (!_dbus_string_append_int (&contents,
00591 keys[i].creation_time))
00592 goto nomem;
00593
00594 if (!_dbus_string_append_byte (&contents, ' '))
00595 goto nomem;
00596
00597 if (!_dbus_string_hex_encode (&keys[i].secret, 0,
00598 &contents,
00599 _dbus_string_get_length (&contents)))
00600 goto nomem;
00601
00602 if (!_dbus_string_append_byte (&contents, '\n'))
00603 goto nomem;
00604
00605 ++i;
00606 continue;
00607
00608 nomem:
00609 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00610 goto out;
00611 }
00612
00613 if (!_dbus_string_save_to_file (&contents, &keyring->filename,
00614 error))
00615 goto out;
00616 }
00617
00618 if (keyring->keys)
00619 free_keys (keyring->keys, keyring->n_keys);
00620 keyring->keys = keys;
00621 keyring->n_keys = n_keys;
00622 keys = NULL;
00623 n_keys = 0;
00624
00625 retval = TRUE;
00626
00627 out:
00628 if (have_lock)
00629 _dbus_keyring_unlock (keyring);
00630
00631 if (! ((retval == TRUE && (error == NULL || error->name == NULL)) ||
00632 (retval == FALSE && (error == NULL || error->name != NULL))))
00633 {
00634 if (error && error->name)
00635 _dbus_verbose ("error is %s: %s\n", error->name, error->message);
00636 _dbus_warn ("returning %d but error pointer %p name %s\n",
00637 retval, error, error->name ? error->name : "(none)");
00638 _dbus_assert_not_reached ("didn't handle errors properly");
00639 }
00640
00641 if (keys != NULL)
00642 {
00643 i = 0;
00644 while (i < n_keys)
00645 {
00646 _dbus_string_zero (&keys[i].secret);
00647 _dbus_string_free (&keys[i].secret);
00648 ++i;
00649 }
00650
00651 dbus_free (keys);
00652 }
00653
00654 _dbus_string_free (&contents);
00655 _dbus_string_free (&line);
00656
00657 return retval;
00658 }
00659
00661
00674 DBusKeyring *
00675 _dbus_keyring_ref (DBusKeyring *keyring)
00676 {
00677 keyring->refcount += 1;
00678
00679 return keyring;
00680 }
00681
00688 void
00689 _dbus_keyring_unref (DBusKeyring *keyring)
00690 {
00691 keyring->refcount -= 1;
00692
00693 if (keyring->refcount == 0)
00694 {
00695 _dbus_string_free (&keyring->username);
00696 _dbus_string_free (&keyring->filename);
00697 _dbus_string_free (&keyring->filename_lock);
00698 _dbus_string_free (&keyring->directory);
00699 free_keys (keyring->keys, keyring->n_keys);
00700 dbus_free (keyring);
00701 }
00702 }
00703
00714 DBusKeyring*
00715 _dbus_keyring_new_homedir (const DBusString *username,
00716 const DBusString *context,
00717 DBusError *error)
00718 {
00719 DBusString homedir;
00720 DBusKeyring *keyring;
00721 dbus_bool_t error_set;
00722 DBusString dotdir;
00723 DBusError tmp_error;
00724
00725 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00726
00727 if (_dbus_check_setuid ())
00728 {
00729 dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
00730 "Unable to create DBus keyring when setuid");
00731 return NULL;
00732 }
00733
00734 keyring = NULL;
00735 error_set = FALSE;
00736
00737 if (!_dbus_string_init (&homedir))
00738 {
00739 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00740 return NULL;
00741 }
00742
00743 _dbus_string_init_const (&dotdir, ".dbus-keyrings");
00744
00745 if (username == NULL)
00746 {
00747 const DBusString *const_homedir;
00748
00749 if (!_dbus_username_from_current_process (&username) ||
00750 !_dbus_homedir_from_current_process (&const_homedir))
00751 goto failed;
00752
00753 if (!_dbus_string_copy (const_homedir, 0,
00754 &homedir, 0))
00755 goto failed;
00756 }
00757 else
00758 {
00759 if (!_dbus_homedir_from_username (username, &homedir))
00760 goto failed;
00761 }
00762
00763 #ifdef DBUS_BUILD_TESTS
00764 {
00765 const char *override;
00766
00767 override = _dbus_getenv ("DBUS_TEST_HOMEDIR");
00768 if (override != NULL && *override != '\0')
00769 {
00770 _dbus_string_set_length (&homedir, 0);
00771 if (!_dbus_string_append (&homedir, override))
00772 goto failed;
00773
00774 _dbus_verbose ("Using fake homedir for testing: %s\n",
00775 _dbus_string_get_const_data (&homedir));
00776 }
00777 else
00778 {
00779 static dbus_bool_t already_warned = FALSE;
00780 if (!already_warned)
00781 {
00782 _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n");
00783 already_warned = TRUE;
00784 }
00785 }
00786 }
00787 #endif
00788
00789 _dbus_assert (username != NULL);
00790
00791 keyring = _dbus_keyring_new ();
00792 if (keyring == NULL)
00793 goto failed;
00794
00795
00796 if (!_dbus_keyring_validate_context (context))
00797 {
00798 error_set = TRUE;
00799 dbus_set_error_const (error,
00800 DBUS_ERROR_FAILED,
00801 "Invalid context in keyring creation");
00802 goto failed;
00803 }
00804
00805 if (!_dbus_string_copy (username, 0,
00806 &keyring->username, 0))
00807 goto failed;
00808
00809 if (!_dbus_string_copy (&homedir, 0,
00810 &keyring->directory, 0))
00811 goto failed;
00812
00813 if (!_dbus_concat_dir_and_file (&keyring->directory,
00814 &dotdir))
00815 goto failed;
00816
00817 if (!_dbus_string_copy (&keyring->directory, 0,
00818 &keyring->filename, 0))
00819 goto failed;
00820
00821 if (!_dbus_concat_dir_and_file (&keyring->filename,
00822 context))
00823 goto failed;
00824
00825 if (!_dbus_string_copy (&keyring->filename, 0,
00826 &keyring->filename_lock, 0))
00827 goto failed;
00828
00829 if (!_dbus_string_append (&keyring->filename_lock, ".lock"))
00830 goto failed;
00831
00832 dbus_error_init (&tmp_error);
00833 if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error))
00834 {
00835 _dbus_verbose ("didn't load an existing keyring: %s\n",
00836 tmp_error.message);
00837 dbus_error_free (&tmp_error);
00838 }
00839
00840
00841
00842
00843
00844 dbus_error_init (&tmp_error);
00845 if (!_dbus_create_directory (&keyring->directory,
00846 &tmp_error))
00847 {
00848 _dbus_verbose ("Creating keyring directory: %s\n",
00849 tmp_error.message);
00850 dbus_error_free (&tmp_error);
00851 }
00852
00853 _dbus_string_free (&homedir);
00854
00855 return keyring;
00856
00857 failed:
00858 if (!error_set)
00859 dbus_set_error_const (error,
00860 DBUS_ERROR_NO_MEMORY,
00861 NULL);
00862 if (keyring)
00863 _dbus_keyring_unref (keyring);
00864 _dbus_string_free (&homedir);
00865 return NULL;
00866
00867 }
00868
00881 dbus_bool_t
00882 _dbus_keyring_validate_context (const DBusString *context)
00883 {
00884 if (_dbus_string_get_length (context) == 0)
00885 {
00886 _dbus_verbose ("context is zero-length\n");
00887 return FALSE;
00888 }
00889
00890 if (!_dbus_string_validate_ascii (context, 0,
00891 _dbus_string_get_length (context)))
00892 {
00893 _dbus_verbose ("context not valid ascii\n");
00894 return FALSE;
00895 }
00896
00897
00898 if (_dbus_string_find (context, 0, "/", NULL))
00899 {
00900 _dbus_verbose ("context contains a slash\n");
00901 return FALSE;
00902 }
00903
00904 if (_dbus_string_find (context, 0, "\\", NULL))
00905 {
00906 _dbus_verbose ("context contains a backslash\n");
00907 return FALSE;
00908 }
00909
00910
00911
00912
00913 if (_dbus_string_find (context, 0, ".", NULL))
00914 {
00915 _dbus_verbose ("context contains a dot\n");
00916 return FALSE;
00917 }
00918
00919
00920 if (_dbus_string_find_blank (context, 0, NULL))
00921 {
00922 _dbus_verbose ("context contains a blank\n");
00923 return FALSE;
00924 }
00925
00926 if (_dbus_string_find (context, 0, "\n", NULL))
00927 {
00928 _dbus_verbose ("context contains a newline\n");
00929 return FALSE;
00930 }
00931
00932 if (_dbus_string_find (context, 0, "\r", NULL))
00933 {
00934 _dbus_verbose ("context contains a carriage return\n");
00935 return FALSE;
00936 }
00937
00938 return TRUE;
00939 }
00940
00941 static DBusKey*
00942 find_recent_key (DBusKeyring *keyring)
00943 {
00944 int i;
00945 long tv_sec, tv_usec;
00946
00947 _dbus_get_current_time (&tv_sec, &tv_usec);
00948
00949 i = 0;
00950 while (i < keyring->n_keys)
00951 {
00952 DBusKey *key = &keyring->keys[i];
00953
00954 _dbus_verbose ("Key %d is %ld seconds old\n",
00955 i, tv_sec - key->creation_time);
00956
00957 if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time)
00958 return key;
00959
00960 ++i;
00961 }
00962
00963 return NULL;
00964 }
00965
00977 int
00978 _dbus_keyring_get_best_key (DBusKeyring *keyring,
00979 DBusError *error)
00980 {
00981 DBusKey *key;
00982
00983 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00984
00985 key = find_recent_key (keyring);
00986 if (key)
00987 return key->id;
00988
00989
00990
00991
00992 if (!_dbus_keyring_reload (keyring, TRUE,
00993 error))
00994 return -1;
00995
00996 key = find_recent_key (keyring);
00997 if (key)
00998 return key->id;
00999 else
01000 {
01001 dbus_set_error_const (error,
01002 DBUS_ERROR_FAILED,
01003 "No recent-enough key found in keyring, and unable to create a new key");
01004 return -1;
01005 }
01006 }
01007
01016 dbus_bool_t
01017 _dbus_keyring_is_for_user (DBusKeyring *keyring,
01018 const DBusString *username)
01019 {
01020 return _dbus_string_equal (&keyring->username,
01021 username);
01022 }
01023
01035 dbus_bool_t
01036 _dbus_keyring_get_hex_key (DBusKeyring *keyring,
01037 int key_id,
01038 DBusString *hex_key)
01039 {
01040 DBusKey *key;
01041
01042 key = find_key_by_id (keyring->keys,
01043 keyring->n_keys,
01044 key_id);
01045 if (key == NULL)
01046 return TRUE;
01047
01048 return _dbus_string_hex_encode (&key->secret, 0,
01049 hex_key,
01050 _dbus_string_get_length (hex_key));
01051 }
01052
01054
01055 #ifdef DBUS_BUILD_TESTS
01056 #include "dbus-test.h"
01057 #include <stdio.h>
01058
01059 dbus_bool_t
01060 _dbus_keyring_test (void)
01061 {
01062 DBusString context;
01063 DBusKeyring *ring1;
01064 DBusKeyring *ring2;
01065 int id;
01066 DBusError error;
01067 int i;
01068
01069 ring1 = NULL;
01070 ring2 = NULL;
01071
01072
01073
01074 _dbus_string_init_const (&context, "foo");
01075 _dbus_assert (_dbus_keyring_validate_context (&context));
01076 _dbus_string_init_const (&context, "org_freedesktop_blah");
01077 _dbus_assert (_dbus_keyring_validate_context (&context));
01078
01079 _dbus_string_init_const (&context, "");
01080 _dbus_assert (!_dbus_keyring_validate_context (&context));
01081 _dbus_string_init_const (&context, ".foo");
01082 _dbus_assert (!_dbus_keyring_validate_context (&context));
01083 _dbus_string_init_const (&context, "bar.foo");
01084 _dbus_assert (!_dbus_keyring_validate_context (&context));
01085 _dbus_string_init_const (&context, "bar/foo");
01086 _dbus_assert (!_dbus_keyring_validate_context (&context));
01087 _dbus_string_init_const (&context, "bar\\foo");
01088 _dbus_assert (!_dbus_keyring_validate_context (&context));
01089 _dbus_string_init_const (&context, "foo\xfa\xf0");
01090 _dbus_assert (!_dbus_keyring_validate_context (&context));
01091 _dbus_string_init_const (&context, "foo\x80");
01092 _dbus_assert (!_dbus_keyring_validate_context (&context));
01093 _dbus_string_init_const (&context, "foo\x7f");
01094 _dbus_assert (_dbus_keyring_validate_context (&context));
01095 _dbus_string_init_const (&context, "foo bar");
01096 _dbus_assert (!_dbus_keyring_validate_context (&context));
01097
01098 if (!_dbus_string_init (&context))
01099 _dbus_assert_not_reached ("no memory");
01100 if (!_dbus_string_append_byte (&context, '\0'))
01101 _dbus_assert_not_reached ("no memory");
01102 _dbus_assert (!_dbus_keyring_validate_context (&context));
01103 _dbus_string_free (&context);
01104
01105
01106
01107
01108
01109 _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite");
01110 dbus_error_init (&error);
01111 ring1 = _dbus_keyring_new_homedir (NULL, &context,
01112 &error);
01113 _dbus_assert (ring1);
01114 _dbus_assert (error.name == NULL);
01115
01116 id = _dbus_keyring_get_best_key (ring1, &error);
01117 if (id < 0)
01118 {
01119 fprintf (stderr, "Could not load keyring: %s\n", error.message);
01120 dbus_error_free (&error);
01121 goto failure;
01122 }
01123
01124 ring2 = _dbus_keyring_new_homedir (NULL, &context, &error);
01125 _dbus_assert (ring2);
01126 _dbus_assert (error.name == NULL);
01127
01128 if (ring1->n_keys != ring2->n_keys)
01129 {
01130 fprintf (stderr, "Different number of keys in keyrings\n");
01131 goto failure;
01132 }
01133
01134
01135
01136
01137 i = 0;
01138 while (i < ring1->n_keys)
01139 {
01140 if (ring1->keys[i].id != ring2->keys[i].id)
01141 {
01142 fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n",
01143 ring1->keys[i].id, ring2->keys[i].id);
01144 goto failure;
01145 }
01146
01147 if (ring1->keys[i].creation_time != ring2->keys[i].creation_time)
01148 {
01149 fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n",
01150 ring1->keys[i].creation_time, ring2->keys[i].creation_time);
01151 goto failure;
01152 }
01153
01154 if (!_dbus_string_equal (&ring1->keys[i].secret,
01155 &ring2->keys[i].secret))
01156 {
01157 fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n");
01158 goto failure;
01159 }
01160
01161 ++i;
01162 }
01163
01164 printf (" %d keys in test\n", ring1->n_keys);
01165
01166
01167 _dbus_keyring_ref (ring1);
01168 _dbus_keyring_ref (ring2);
01169 _dbus_keyring_unref (ring1);
01170 _dbus_keyring_unref (ring2);
01171
01172
01173
01174 _dbus_keyring_unref (ring1);
01175 _dbus_keyring_unref (ring2);
01176
01177 return TRUE;
01178
01179 failure:
01180 if (ring1)
01181 _dbus_keyring_unref (ring1);
01182 if (ring2)
01183 _dbus_keyring_unref (ring2);
01184
01185 return FALSE;
01186 }
01187
01188 #endif
01189