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