D-Bus 1.2.24
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-keyring.c Store secret cookies in your homedir 00003 * 00004 * Copyright (C) 2003, 2004 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include "dbus-keyring.h" 00025 #include "dbus-protocol.h" 00026 #include <dbus/dbus-string.h> 00027 #include <dbus/dbus-list.h> 00028 #include <dbus/dbus-sysdeps.h> 00029 00066 #define NEW_KEY_TIMEOUT_SECONDS (60*5) 00067 00072 #define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2)) 00073 00076 #define MAX_TIME_TRAVEL_SECONDS (60*5) 00077 00082 #ifdef DBUS_BUILD_TESTS 00083 #define MAX_KEYS_IN_FILE 10 00084 #else 00085 #define MAX_KEYS_IN_FILE 256 00086 #endif 00087 00091 typedef struct 00092 { 00093 dbus_int32_t id; 00095 long creation_time; 00100 DBusString secret; 00102 } DBusKey; 00103 00110 struct DBusKeyring 00111 { 00112 int refcount; 00113 DBusString directory; 00114 DBusString filename; 00115 DBusString filename_lock; 00116 DBusKey *keys; 00117 int n_keys; 00118 DBusCredentials *credentials; 00119 }; 00120 00121 static DBusKeyring* 00122 _dbus_keyring_new (void) 00123 { 00124 DBusKeyring *keyring; 00125 00126 keyring = dbus_new0 (DBusKeyring, 1); 00127 if (keyring == NULL) 00128 goto out_0; 00129 00130 if (!_dbus_string_init (&keyring->directory)) 00131 goto out_1; 00132 00133 if (!_dbus_string_init (&keyring->filename)) 00134 goto out_2; 00135 00136 if (!_dbus_string_init (&keyring->filename_lock)) 00137 goto out_3; 00138 00139 keyring->refcount = 1; 00140 keyring->keys = NULL; 00141 keyring->n_keys = 0; 00142 00143 return keyring; 00144 00145 /* out_4: */ 00146 _dbus_string_free (&keyring->filename_lock); 00147 out_3: 00148 _dbus_string_free (&keyring->filename); 00149 out_2: 00150 _dbus_string_free (&keyring->directory); 00151 out_1: 00152 dbus_free (keyring); 00153 out_0: 00154 return NULL; 00155 } 00156 00157 static void 00158 free_keys (DBusKey *keys, 00159 int n_keys) 00160 { 00161 int i; 00162 00163 /* should be safe for args NULL, 0 */ 00164 00165 i = 0; 00166 while (i < n_keys) 00167 { 00168 _dbus_string_free (&keys[i].secret); 00169 ++i; 00170 } 00171 00172 dbus_free (keys); 00173 } 00174 00175 /* Our locking scheme is highly unreliable. However, there is 00176 * unfortunately no reliable locking scheme in user home directories; 00177 * between bugs in Linux NFS, people using Tru64 or other total crap 00178 * NFS, AFS, random-file-system-of-the-week, and so forth, fcntl() in 00179 * homedirs simply generates tons of bug reports. This has been 00180 * learned through hard experience with GConf, unfortunately. 00181 * 00182 * This bad hack might work better for the kind of lock we have here, 00183 * which we don't expect to hold for any length of time. Crashing 00184 * while we hold it should be unlikely, and timing out such that we 00185 * delete a stale lock should also be unlikely except when the 00186 * filesystem is running really slowly. Stuff might break in corner 00187 * cases but as long as it's not a security-level breakage it should 00188 * be OK. 00189 */ 00190 00192 #define MAX_LOCK_TIMEOUTS 32 00193 00194 #define LOCK_TIMEOUT_MILLISECONDS 250 00195 00196 static dbus_bool_t 00197 _dbus_keyring_lock (DBusKeyring *keyring) 00198 { 00199 int n_timeouts; 00200 00201 n_timeouts = 0; 00202 while (n_timeouts < MAX_LOCK_TIMEOUTS) 00203 { 00204 DBusError error = DBUS_ERROR_INIT; 00205 00206 if (_dbus_create_file_exclusively (&keyring->filename_lock, 00207 &error)) 00208 break; 00209 00210 _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n", 00211 LOCK_TIMEOUT_MILLISECONDS, error.message); 00212 dbus_error_free (&error); 00213 00214 _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS); 00215 00216 ++n_timeouts; 00217 } 00218 00219 if (n_timeouts == MAX_LOCK_TIMEOUTS) 00220 { 00221 DBusError error = DBUS_ERROR_INIT; 00222 00223 _dbus_verbose ("Lock file timed out %d times, assuming stale\n", 00224 n_timeouts); 00225 00226 if (!_dbus_delete_file (&keyring->filename_lock, &error)) 00227 { 00228 _dbus_verbose ("Couldn't delete old lock file: %s\n", 00229 error.message); 00230 dbus_error_free (&error); 00231 return FALSE; 00232 } 00233 00234 if (!_dbus_create_file_exclusively (&keyring->filename_lock, 00235 &error)) 00236 { 00237 _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n", 00238 error.message); 00239 dbus_error_free (&error); 00240 return FALSE; 00241 } 00242 } 00243 00244 return TRUE; 00245 } 00246 00247 static void 00248 _dbus_keyring_unlock (DBusKeyring *keyring) 00249 { 00250 DBusError error = DBUS_ERROR_INIT; 00251 00252 if (!_dbus_delete_file (&keyring->filename_lock, &error)) 00253 { 00254 _dbus_warn ("Failed to delete lock file: %s\n", 00255 error.message); 00256 dbus_error_free (&error); 00257 } 00258 } 00259 00260 static DBusKey* 00261 find_key_by_id (DBusKey *keys, 00262 int n_keys, 00263 int id) 00264 { 00265 int i; 00266 00267 i = 0; 00268 while (i < n_keys) 00269 { 00270 if (keys[i].id == id) 00271 return &keys[i]; 00272 00273 ++i; 00274 } 00275 00276 return NULL; 00277 } 00278 00279 static dbus_bool_t 00280 add_new_key (DBusKey **keys_p, 00281 int *n_keys_p, 00282 DBusError *error) 00283 { 00284 DBusKey *new; 00285 DBusString bytes; 00286 int id; 00287 long timestamp; 00288 const unsigned char *s; 00289 dbus_bool_t retval; 00290 DBusKey *keys; 00291 int n_keys; 00292 00293 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00294 00295 if (!_dbus_string_init (&bytes)) 00296 { 00297 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00298 return FALSE; 00299 } 00300 00301 keys = *keys_p; 00302 n_keys = *n_keys_p; 00303 retval = FALSE; 00304 00305 /* Generate an integer ID and then the actual key. */ 00306 retry: 00307 00308 if (!_dbus_generate_random_bytes (&bytes, 4)) 00309 { 00310 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00311 goto out; 00312 } 00313 00314 s = (const unsigned char*) _dbus_string_get_const_data (&bytes); 00315 00316 id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); 00317 if (id < 0) 00318 id = - id; 00319 _dbus_assert (id >= 0); 00320 00321 if (find_key_by_id (keys, n_keys, id) != NULL) 00322 { 00323 _dbus_string_set_length (&bytes, 0); 00324 _dbus_verbose ("Key ID %d already existed, trying another one\n", 00325 id); 00326 goto retry; 00327 } 00328 00329 _dbus_verbose ("Creating key with ID %d\n", id); 00330 00331 #define KEY_LENGTH_BYTES 24 00332 _dbus_string_set_length (&bytes, 0); 00333 if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES)) 00334 { 00335 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00336 goto out; 00337 } 00338 00339 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); 00340 if (new == NULL) 00341 { 00342 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00343 goto out; 00344 } 00345 00346 keys = new; 00347 *keys_p = keys; /* otherwise *keys_p ends up invalid */ 00348 n_keys += 1; 00349 00350 if (!_dbus_string_init (&keys[n_keys-1].secret)) 00351 { 00352 n_keys -= 1; /* we don't want to free the one we didn't init */ 00353 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00354 goto out; 00355 } 00356 00357 _dbus_get_current_time (×tamp, NULL); 00358 00359 keys[n_keys-1].id = id; 00360 keys[n_keys-1].creation_time = timestamp; 00361 if (!_dbus_string_move (&bytes, 0, 00362 &keys[n_keys-1].secret, 00363 0)) 00364 { 00365 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00366 _dbus_string_free (&keys[n_keys-1].secret); 00367 n_keys -= 1; 00368 goto out; 00369 } 00370 00371 retval = TRUE; 00372 00373 out: 00374 *n_keys_p = n_keys; 00375 00376 _dbus_string_free (&bytes); 00377 return retval; 00378 } 00379 00394 static dbus_bool_t 00395 _dbus_keyring_reload (DBusKeyring *keyring, 00396 dbus_bool_t add_new, 00397 DBusError *error) 00398 { 00399 DBusString contents; 00400 DBusString line; 00401 dbus_bool_t retval; 00402 dbus_bool_t have_lock; 00403 DBusKey *keys; 00404 int n_keys; 00405 int i; 00406 long now; 00407 DBusError tmp_error; 00408 00409 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00410 00411 if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error)) 00412 return FALSE; 00413 00414 if (!_dbus_string_init (&contents)) 00415 { 00416 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00417 return FALSE; 00418 } 00419 00420 if (!_dbus_string_init (&line)) 00421 { 00422 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00423 _dbus_string_free (&contents); 00424 return FALSE; 00425 } 00426 00427 keys = NULL; 00428 n_keys = 0; 00429 retval = FALSE; 00430 have_lock = FALSE; 00431 00432 _dbus_get_current_time (&now, NULL); 00433 00434 if (add_new) 00435 { 00436 if (!_dbus_keyring_lock (keyring)) 00437 { 00438 dbus_set_error (error, DBUS_ERROR_FAILED, 00439 "Could not lock keyring file to add to it"); 00440 goto out; 00441 } 00442 00443 have_lock = TRUE; 00444 } 00445 00446 dbus_error_init (&tmp_error); 00447 if (!_dbus_file_get_contents (&contents, 00448 &keyring->filename, 00449 &tmp_error)) 00450 { 00451 _dbus_verbose ("Failed to load keyring file: %s\n", 00452 tmp_error.message); 00453 /* continue with empty keyring file, so we recreate it */ 00454 dbus_error_free (&tmp_error); 00455 } 00456 00457 if (!_dbus_string_validate_ascii (&contents, 0, 00458 _dbus_string_get_length (&contents))) 00459 { 00460 _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n"); 00461 _dbus_string_set_length (&contents, 0); 00462 } 00463 00464 /* FIXME this is badly inefficient for large keyring files 00465 * (not that large keyring files exist outside of test suites) 00466 */ 00467 while (_dbus_string_pop_line (&contents, &line)) 00468 { 00469 int next; 00470 long val; 00471 int id; 00472 long timestamp; 00473 int len; 00474 int end; 00475 DBusKey *new; 00476 00477 /* Don't load more than the max. */ 00478 if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE)) 00479 break; 00480 00481 next = 0; 00482 if (!_dbus_string_parse_int (&line, 0, &val, &next)) 00483 { 00484 _dbus_verbose ("could not parse secret key ID at start of line\n"); 00485 continue; 00486 } 00487 00488 if (val > _DBUS_INT32_MAX || val < 0) 00489 { 00490 _dbus_verbose ("invalid secret key ID at start of line\n"); 00491 continue; 00492 } 00493 00494 id = val; 00495 00496 _dbus_string_skip_blank (&line, next, &next); 00497 00498 if (!_dbus_string_parse_int (&line, next, ×tamp, &next)) 00499 { 00500 _dbus_verbose ("could not parse secret key timestamp\n"); 00501 continue; 00502 } 00503 00504 if (timestamp < 0 || 00505 (now + MAX_TIME_TRAVEL_SECONDS) < timestamp || 00506 (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp) 00507 { 00508 _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n", 00509 now - timestamp, timestamp, now); 00510 continue; 00511 } 00512 00513 _dbus_string_skip_blank (&line, next, &next); 00514 00515 len = _dbus_string_get_length (&line); 00516 00517 if ((len - next) == 0) 00518 { 00519 _dbus_verbose ("no secret key after ID and timestamp\n"); 00520 continue; 00521 } 00522 00523 /* We have all three parts */ 00524 new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); 00525 if (new == NULL) 00526 { 00527 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00528 goto out; 00529 } 00530 00531 keys = new; 00532 n_keys += 1; 00533 00534 if (!_dbus_string_init (&keys[n_keys-1].secret)) 00535 { 00536 n_keys -= 1; /* we don't want to free the one we didn't init */ 00537 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00538 goto out; 00539 } 00540 00541 keys[n_keys-1].id = id; 00542 keys[n_keys-1].creation_time = timestamp; 00543 if (!_dbus_string_hex_decode (&line, next, &end, 00544 &keys[n_keys-1].secret, 0)) 00545 { 00546 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00547 goto out; 00548 } 00549 00550 if (_dbus_string_get_length (&line) != end) 00551 { 00552 _dbus_verbose ("invalid hex encoding in keyring file\n"); 00553 _dbus_string_free (&keys[n_keys - 1].secret); 00554 n_keys -= 1; 00555 continue; 00556 } 00557 } 00558 00559 _dbus_verbose ("Successfully loaded %d existing keys\n", 00560 n_keys); 00561 00562 if (add_new) 00563 { 00564 if (!add_new_key (&keys, &n_keys, error)) 00565 { 00566 _dbus_verbose ("Failed to generate new key: %s\n", 00567 error ? error->message : "(unknown)"); 00568 goto out; 00569 } 00570 00571 _dbus_string_set_length (&contents, 0); 00572 00573 i = 0; 00574 while (i < n_keys) 00575 { 00576 if (!_dbus_string_append_int (&contents, 00577 keys[i].id)) 00578 goto nomem; 00579 00580 if (!_dbus_string_append_byte (&contents, ' ')) 00581 goto nomem; 00582 00583 if (!_dbus_string_append_int (&contents, 00584 keys[i].creation_time)) 00585 goto nomem; 00586 00587 if (!_dbus_string_append_byte (&contents, ' ')) 00588 goto nomem; 00589 00590 if (!_dbus_string_hex_encode (&keys[i].secret, 0, 00591 &contents, 00592 _dbus_string_get_length (&contents))) 00593 goto nomem; 00594 00595 if (!_dbus_string_append_byte (&contents, '\n')) 00596 goto nomem; 00597 00598 ++i; 00599 continue; 00600 00601 nomem: 00602 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00603 goto out; 00604 } 00605 00606 if (!_dbus_string_save_to_file (&contents, &keyring->filename, 00607 error)) 00608 goto out; 00609 } 00610 00611 if (keyring->keys) 00612 free_keys (keyring->keys, keyring->n_keys); 00613 keyring->keys = keys; 00614 keyring->n_keys = n_keys; 00615 keys = NULL; 00616 n_keys = 0; 00617 00618 retval = TRUE; 00619 00620 out: 00621 if (have_lock) 00622 _dbus_keyring_unlock (keyring); 00623 00624 if (! ((retval == TRUE && (error == NULL || error->name == NULL)) || 00625 (retval == FALSE && (error == NULL || error->name != NULL)))) 00626 { 00627 if (error && error->name) 00628 _dbus_verbose ("error is %s: %s\n", error->name, error->message); 00629 _dbus_warn ("returning %d but error pointer %p name %s\n", 00630 retval, error, error->name ? error->name : "(none)"); 00631 _dbus_assert_not_reached ("didn't handle errors properly"); 00632 } 00633 00634 if (keys != NULL) 00635 { 00636 i = 0; 00637 while (i < n_keys) 00638 { 00639 _dbus_string_zero (&keys[i].secret); 00640 _dbus_string_free (&keys[i].secret); 00641 ++i; 00642 } 00643 00644 dbus_free (keys); 00645 } 00646 00647 _dbus_string_free (&contents); 00648 _dbus_string_free (&line); 00649 00650 return retval; 00651 } 00652 /* end of internals */ 00654 00667 DBusKeyring * 00668 _dbus_keyring_ref (DBusKeyring *keyring) 00669 { 00670 keyring->refcount += 1; 00671 00672 return keyring; 00673 } 00674 00681 void 00682 _dbus_keyring_unref (DBusKeyring *keyring) 00683 { 00684 keyring->refcount -= 1; 00685 00686 if (keyring->refcount == 0) 00687 { 00688 if (keyring->credentials) 00689 _dbus_credentials_unref (keyring->credentials); 00690 00691 _dbus_string_free (&keyring->filename); 00692 _dbus_string_free (&keyring->filename_lock); 00693 _dbus_string_free (&keyring->directory); 00694 free_keys (keyring->keys, keyring->n_keys); 00695 dbus_free (keyring); 00696 } 00697 } 00698 00709 DBusKeyring* 00710 _dbus_keyring_new_for_credentials (DBusCredentials *credentials, 00711 const DBusString *context, 00712 DBusError *error) 00713 { 00714 DBusString ringdir; 00715 DBusKeyring *keyring; 00716 dbus_bool_t error_set; 00717 DBusError tmp_error; 00718 DBusCredentials *our_credentials; 00719 00720 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00721 00722 keyring = NULL; 00723 error_set = FALSE; 00724 our_credentials = NULL; 00725 00726 if (!_dbus_string_init (&ringdir)) 00727 { 00728 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00729 return NULL; 00730 } 00731 00732 if (credentials != NULL) 00733 { 00734 our_credentials = _dbus_credentials_copy (credentials); 00735 } 00736 else 00737 { 00738 our_credentials = _dbus_credentials_new_from_current_process (); 00739 } 00740 00741 if (our_credentials == NULL) 00742 goto failed; 00743 00744 if (_dbus_credentials_are_anonymous (our_credentials)) 00745 { 00746 if (!_dbus_credentials_add_from_current_process (our_credentials)) 00747 goto failed; 00748 } 00749 00750 if (!_dbus_append_keyring_directory_for_credentials (&ringdir, 00751 our_credentials)) 00752 goto failed; 00753 00754 keyring = _dbus_keyring_new (); 00755 if (keyring == NULL) 00756 goto failed; 00757 00758 _dbus_assert (keyring->credentials == NULL); 00759 keyring->credentials = our_credentials; 00760 our_credentials = NULL; /* so we don't unref it again later */ 00761 00762 /* should have been validated already, but paranoia check here */ 00763 if (!_dbus_keyring_validate_context (context)) 00764 { 00765 error_set = TRUE; 00766 dbus_set_error_const (error, 00767 DBUS_ERROR_FAILED, 00768 "Invalid context in keyring creation"); 00769 goto failed; 00770 } 00771 00772 /* Save keyring dir in the keyring object */ 00773 if (!_dbus_string_copy (&ringdir, 0, 00774 &keyring->directory, 0)) 00775 goto failed; 00776 00777 /* Create keyring->filename based on keyring dir and context */ 00778 if (!_dbus_string_copy (&keyring->directory, 0, 00779 &keyring->filename, 0)) 00780 goto failed; 00781 00782 if (!_dbus_concat_dir_and_file (&keyring->filename, 00783 context)) 00784 goto failed; 00785 00786 /* Create lockfile name */ 00787 if (!_dbus_string_copy (&keyring->filename, 0, 00788 &keyring->filename_lock, 0)) 00789 goto failed; 00790 00791 if (!_dbus_string_append (&keyring->filename_lock, ".lock")) 00792 goto failed; 00793 00794 /* Reload keyring */ 00795 dbus_error_init (&tmp_error); 00796 if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error)) 00797 { 00798 _dbus_verbose ("didn't load an existing keyring: %s\n", 00799 tmp_error.message); 00800 dbus_error_free (&tmp_error); 00801 } 00802 00803 /* We don't fail fatally if we can't create the directory, 00804 * but the keyring will probably always be empty 00805 * unless someone else manages to create it 00806 */ 00807 dbus_error_init (&tmp_error); 00808 if (!_dbus_create_directory (&keyring->directory, 00809 &tmp_error)) 00810 { 00811 _dbus_verbose ("Creating keyring directory: %s\n", 00812 tmp_error.message); 00813 dbus_error_free (&tmp_error); 00814 } 00815 00816 _dbus_string_free (&ringdir); 00817 00818 return keyring; 00819 00820 failed: 00821 if (!error_set) 00822 dbus_set_error_const (error, 00823 DBUS_ERROR_NO_MEMORY, 00824 NULL); 00825 if (our_credentials) 00826 _dbus_credentials_unref (our_credentials); 00827 if (keyring) 00828 _dbus_keyring_unref (keyring); 00829 _dbus_string_free (&ringdir); 00830 return NULL; 00831 00832 } 00833 00846 dbus_bool_t 00847 _dbus_keyring_validate_context (const DBusString *context) 00848 { 00849 if (_dbus_string_get_length (context) == 0) 00850 { 00851 _dbus_verbose ("context is zero-length\n"); 00852 return FALSE; 00853 } 00854 00855 if (!_dbus_string_validate_ascii (context, 0, 00856 _dbus_string_get_length (context))) 00857 { 00858 _dbus_verbose ("context not valid ascii\n"); 00859 return FALSE; 00860 } 00861 00862 /* no directory separators */ 00863 if (_dbus_string_find (context, 0, "/", NULL)) 00864 { 00865 _dbus_verbose ("context contains a slash\n"); 00866 return FALSE; 00867 } 00868 00869 if (_dbus_string_find (context, 0, "\\", NULL)) 00870 { 00871 _dbus_verbose ("context contains a backslash\n"); 00872 return FALSE; 00873 } 00874 00875 /* prevent attempts to use dotfiles or ".." or ".lock" 00876 * all of which might allow some kind of attack 00877 */ 00878 if (_dbus_string_find (context, 0, ".", NULL)) 00879 { 00880 _dbus_verbose ("context contains a dot\n"); 00881 return FALSE; 00882 } 00883 00884 /* no spaces/tabs, those are used for separators in the protocol */ 00885 if (_dbus_string_find_blank (context, 0, NULL)) 00886 { 00887 _dbus_verbose ("context contains a blank\n"); 00888 return FALSE; 00889 } 00890 00891 if (_dbus_string_find (context, 0, "\n", NULL)) 00892 { 00893 _dbus_verbose ("context contains a newline\n"); 00894 return FALSE; 00895 } 00896 00897 if (_dbus_string_find (context, 0, "\r", NULL)) 00898 { 00899 _dbus_verbose ("context contains a carriage return\n"); 00900 return FALSE; 00901 } 00902 00903 return TRUE; 00904 } 00905 00906 static DBusKey* 00907 find_recent_key (DBusKeyring *keyring) 00908 { 00909 int i; 00910 long tv_sec, tv_usec; 00911 00912 _dbus_get_current_time (&tv_sec, &tv_usec); 00913 00914 i = 0; 00915 while (i < keyring->n_keys) 00916 { 00917 DBusKey *key = &keyring->keys[i]; 00918 00919 _dbus_verbose ("Key %d is %ld seconds old\n", 00920 i, tv_sec - key->creation_time); 00921 00922 if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time) 00923 return key; 00924 00925 ++i; 00926 } 00927 00928 return NULL; 00929 } 00930 00942 int 00943 _dbus_keyring_get_best_key (DBusKeyring *keyring, 00944 DBusError *error) 00945 { 00946 DBusKey *key; 00947 00948 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00949 00950 key = find_recent_key (keyring); 00951 if (key) 00952 return key->id; 00953 00954 /* All our keys are too old, or we've never loaded the 00955 * keyring. Create a new one. 00956 */ 00957 if (!_dbus_keyring_reload (keyring, TRUE, 00958 error)) 00959 return -1; 00960 00961 key = find_recent_key (keyring); 00962 if (key) 00963 return key->id; 00964 else 00965 { 00966 dbus_set_error_const (error, 00967 DBUS_ERROR_FAILED, 00968 "No recent-enough key found in keyring, and unable to create a new key"); 00969 return -1; 00970 } 00971 } 00972 00981 dbus_bool_t 00982 _dbus_keyring_is_for_credentials (DBusKeyring *keyring, 00983 DBusCredentials *credentials) 00984 { 00985 return _dbus_credentials_same_user (keyring->credentials, 00986 credentials); 00987 } 00988 01000 dbus_bool_t 01001 _dbus_keyring_get_hex_key (DBusKeyring *keyring, 01002 int key_id, 01003 DBusString *hex_key) 01004 { 01005 DBusKey *key; 01006 01007 key = find_key_by_id (keyring->keys, 01008 keyring->n_keys, 01009 key_id); 01010 if (key == NULL) 01011 return TRUE; /* had enough memory, so TRUE */ 01012 01013 return _dbus_string_hex_encode (&key->secret, 0, 01014 hex_key, 01015 _dbus_string_get_length (hex_key)); 01016 } 01017 /* end of exposed API */ 01019 01020 #ifdef DBUS_BUILD_TESTS 01021 #include "dbus-test.h" 01022 #include <stdio.h> 01023 01024 dbus_bool_t 01025 _dbus_keyring_test (void) 01026 { 01027 DBusString context; 01028 DBusKeyring *ring1; 01029 DBusKeyring *ring2; 01030 int id; 01031 DBusError error; 01032 int i; 01033 01034 ring1 = NULL; 01035 ring2 = NULL; 01036 01037 /* Context validation */ 01038 01039 _dbus_string_init_const (&context, "foo"); 01040 _dbus_assert (_dbus_keyring_validate_context (&context)); 01041 _dbus_string_init_const (&context, "org_freedesktop_blah"); 01042 _dbus_assert (_dbus_keyring_validate_context (&context)); 01043 01044 _dbus_string_init_const (&context, ""); 01045 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01046 _dbus_string_init_const (&context, ".foo"); 01047 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01048 _dbus_string_init_const (&context, "bar.foo"); 01049 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01050 _dbus_string_init_const (&context, "bar/foo"); 01051 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01052 _dbus_string_init_const (&context, "bar\\foo"); 01053 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01054 _dbus_string_init_const (&context, "foo\xfa\xf0"); 01055 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01056 _dbus_string_init_const (&context, "foo\x80"); 01057 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01058 _dbus_string_init_const (&context, "foo\x7f"); 01059 _dbus_assert (_dbus_keyring_validate_context (&context)); 01060 _dbus_string_init_const (&context, "foo bar"); 01061 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01062 01063 if (!_dbus_string_init (&context)) 01064 _dbus_assert_not_reached ("no memory"); 01065 if (!_dbus_string_append_byte (&context, '\0')) 01066 _dbus_assert_not_reached ("no memory"); 01067 _dbus_assert (!_dbus_keyring_validate_context (&context)); 01068 _dbus_string_free (&context); 01069 01070 /* Now verify that if we create a key in keyring 1, 01071 * it is properly loaded in keyring 2 01072 */ 01073 01074 _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite"); 01075 dbus_error_init (&error); 01076 ring1 = _dbus_keyring_new_for_credentials (NULL, &context, 01077 &error); 01078 _dbus_assert (ring1 != NULL); 01079 _dbus_assert (error.name == NULL); 01080 01081 id = _dbus_keyring_get_best_key (ring1, &error); 01082 if (id < 0) 01083 { 01084 fprintf (stderr, "Could not load keyring: %s\n", error.message); 01085 dbus_error_free (&error); 01086 goto failure; 01087 } 01088 01089 ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error); 01090 _dbus_assert (ring2 != NULL); 01091 _dbus_assert (error.name == NULL); 01092 01093 if (ring1->n_keys != ring2->n_keys) 01094 { 01095 fprintf (stderr, "Different number of keys in keyrings\n"); 01096 goto failure; 01097 } 01098 01099 /* We guarantee we load and save keeping keys in a fixed 01100 * order 01101 */ 01102 i = 0; 01103 while (i < ring1->n_keys) 01104 { 01105 if (ring1->keys[i].id != ring2->keys[i].id) 01106 { 01107 fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n", 01108 ring1->keys[i].id, ring2->keys[i].id); 01109 goto failure; 01110 } 01111 01112 if (ring1->keys[i].creation_time != ring2->keys[i].creation_time) 01113 { 01114 fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n", 01115 ring1->keys[i].creation_time, ring2->keys[i].creation_time); 01116 goto failure; 01117 } 01118 01119 if (!_dbus_string_equal (&ring1->keys[i].secret, 01120 &ring2->keys[i].secret)) 01121 { 01122 fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n"); 01123 goto failure; 01124 } 01125 01126 ++i; 01127 } 01128 01129 printf (" %d keys in test\n", ring1->n_keys); 01130 01131 /* Test ref/unref */ 01132 _dbus_keyring_ref (ring1); 01133 _dbus_keyring_ref (ring2); 01134 _dbus_keyring_unref (ring1); 01135 _dbus_keyring_unref (ring2); 01136 01137 01138 /* really unref */ 01139 _dbus_keyring_unref (ring1); 01140 _dbus_keyring_unref (ring2); 01141 01142 return TRUE; 01143 01144 failure: 01145 if (ring1) 01146 _dbus_keyring_unref (ring1); 01147 if (ring2) 01148 _dbus_keyring_unref (ring2); 01149 01150 return FALSE; 01151 } 01152 01153 #endif /* DBUS_BUILD_TESTS */ 01154