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