X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-keyring.c;h=f0c64de3ebc50d20ff71b27c29f942b4deddc171;hb=61d97215c317a4154df47fbfb882aab60b92fbab;hp=d63bc3e81e017e3b03e0b6f82dddc53087bcb15e;hpb=2e9393ffda9630373018e02680fbd204e9f6ac99;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c index d63bc3e..f0c64de 100644 --- a/dbus/dbus-keyring.c +++ b/dbus/dbus-keyring.c @@ -1,9 +1,9 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-keyring.c Store secret cookies in your homedir * - * Copyright (C) 2003 Red Hat Inc. + * Copyright (C) 2003, 2004 Red Hat Inc. * - * Licensed under the Academic Free License version 1.2 + * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,11 +17,13 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ +#include #include "dbus-keyring.h" +#include "dbus-protocol.h" #include #include #include @@ -41,6 +43,10 @@ * file in the user's homedir. However they are transient (only used * by a single server instance for a fixed period of time, then * discarded). Also, the keys are not sent over the wire. + * + * @todo there's a memory leak on some codepath in here, I saw it once + * when running make check - probably some specific initial cookies + * present in the cookie file, then depending on what we do with them. */ /** @@ -70,6 +76,19 @@ */ #define MAX_TIME_TRAVEL_SECONDS (60*5) +/** + * Maximum number of keys in the keyring before + * we just ignore the rest + */ +#ifdef DBUS_ENABLE_EMBEDDED_TESTS +#define MAX_KEYS_IN_FILE 10 +#else +#define MAX_KEYS_IN_FILE 256 +#endif + +/** + * A single key from the cookie file + */ typedef struct { dbus_int32_t id; /**< identifier used to refer to the key */ @@ -92,12 +111,12 @@ typedef struct struct DBusKeyring { int refcount; /**< Reference count */ - DBusString username; /**< Username keyring is for */ DBusString directory; /**< Directory the below two items are inside */ DBusString filename; /**< Keyring filename */ DBusString filename_lock; /**< Name of lockfile */ DBusKey *keys; /**< Keys loaded from the file */ int n_keys; /**< Number of keys */ + DBusCredentials *credentials; /**< Credentials containing user the keyring is for */ }; static DBusKeyring* @@ -117,9 +136,6 @@ _dbus_keyring_new (void) if (!_dbus_string_init (&keyring->filename_lock)) goto out_3; - - if (!_dbus_string_init (&keyring->username)) - goto out_4; keyring->refcount = 1; keyring->keys = NULL; @@ -127,8 +143,6 @@ _dbus_keyring_new (void) return keyring; - out_4: - _dbus_string_free (&keyring->username); out_3: _dbus_string_free (&keyring->filename); out_2: @@ -186,9 +200,8 @@ _dbus_keyring_lock (DBusKeyring *keyring) n_timeouts = 0; while (n_timeouts < MAX_LOCK_TIMEOUTS) { - DBusError error; + DBusError error = DBUS_ERROR_INIT; - dbus_error_init (&error); if (_dbus_create_file_exclusively (&keyring->filename_lock, &error)) break; @@ -204,13 +217,11 @@ _dbus_keyring_lock (DBusKeyring *keyring) if (n_timeouts == MAX_LOCK_TIMEOUTS) { - DBusError error; - + DBusError error = DBUS_ERROR_INIT; + _dbus_verbose ("Lock file timed out %d times, assuming stale\n", n_timeouts); - dbus_error_init (&error); - if (!_dbus_delete_file (&keyring->filename_lock, &error)) { _dbus_verbose ("Couldn't delete old lock file: %s\n", @@ -235,8 +246,8 @@ _dbus_keyring_lock (DBusKeyring *keyring) static void _dbus_keyring_unlock (DBusKeyring *keyring) { - DBusError error; - dbus_error_init (&error); + DBusError error = DBUS_ERROR_INIT; + if (!_dbus_delete_file (&keyring->filename_lock, &error)) { _dbus_warn ("Failed to delete lock file: %s\n", @@ -272,7 +283,7 @@ add_new_key (DBusKey **keys_p, DBusKey *new; DBusString bytes; int id; - unsigned long timestamp; + long timestamp; const unsigned char *s; dbus_bool_t retval; DBusKey *keys; @@ -332,6 +343,7 @@ add_new_key (DBusKey **keys_p, } keys = new; + *keys_p = keys; /* otherwise *keys_p ends up invalid */ n_keys += 1; if (!_dbus_string_init (&keys[n_keys-1].secret)) @@ -341,7 +353,7 @@ add_new_key (DBusKey **keys_p, goto out; } - _dbus_get_current_time (×tamp, NULL); + _dbus_get_real_time (×tamp, NULL); keys[n_keys-1].id = id; keys[n_keys-1].creation_time = timestamp; @@ -350,17 +362,15 @@ add_new_key (DBusKey **keys_p, 0)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&keys[n_keys-1].secret); + n_keys -= 1; goto out; } retval = TRUE; out: - if (retval) - { - *n_keys_p = n_keys; - *keys_p = keys; - } + *n_keys_p = n_keys; _dbus_string_free (&bytes); return retval; @@ -397,6 +407,9 @@ _dbus_keyring_reload (DBusKeyring *keyring, _DBUS_ASSERT_ERROR_IS_CLEAR (error); + if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error)) + return FALSE; + if (!_dbus_string_init (&contents)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); @@ -409,13 +422,13 @@ _dbus_keyring_reload (DBusKeyring *keyring, _dbus_string_free (&contents); return FALSE; } - + keys = NULL; n_keys = 0; retval = FALSE; have_lock = FALSE; - _dbus_get_current_time (&now, NULL); + _dbus_get_real_time (&now, NULL); if (add_new) { @@ -446,7 +459,10 @@ _dbus_keyring_reload (DBusKeyring *keyring, _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n"); _dbus_string_set_length (&contents, 0); } - + + /* FIXME this is badly inefficient for large keyring files + * (not that large keyring files exist outside of test suites) + */ while (_dbus_string_pop_line (&contents, &line)) { int next; @@ -454,7 +470,12 @@ _dbus_keyring_reload (DBusKeyring *keyring, int id; long timestamp; int len; + int end; DBusKey *new; + + /* Don't load more than the max. */ + if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE)) + break; next = 0; if (!_dbus_string_parse_int (&line, 0, &val, &next)) @@ -463,7 +484,7 @@ _dbus_keyring_reload (DBusKeyring *keyring, continue; } - if (val > _DBUS_INT_MAX || val < 0) + if (val > _DBUS_INT32_MAX || val < 0) { _dbus_verbose ("invalid secret key ID at start of line\n"); continue; @@ -518,13 +539,20 @@ _dbus_keyring_reload (DBusKeyring *keyring, keys[n_keys-1].id = id; keys[n_keys-1].creation_time = timestamp; - if (!_dbus_string_hex_decode (&line, next, - &keys[n_keys-1].secret, - 0)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto out; - } + if (!_dbus_string_hex_decode (&line, next, &end, + &keys[n_keys-1].secret, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (_dbus_string_get_length (&line) != end) + { + _dbus_verbose ("invalid hex encoding in keyring file\n"); + _dbus_string_free (&keys[n_keys - 1].secret); + n_keys -= 1; + continue; + } } _dbus_verbose ("Successfully loaded %d existing keys\n", @@ -535,7 +563,7 @@ _dbus_keyring_reload (DBusKeyring *keyring, if (!add_new_key (&keys, &n_keys, error)) { _dbus_verbose ("Failed to generate new key: %s\n", - error ? "(unknown)" : error->message); + error ? error->message : "(unknown)"); goto out; } @@ -575,11 +603,12 @@ _dbus_keyring_reload (DBusKeyring *keyring, } if (!_dbus_string_save_to_file (&contents, &keyring->filename, - error)) + FALSE, error)) goto out; } - dbus_free (keyring->keys); + if (keyring->keys) + free_keys (keyring->keys, keyring->n_keys); keyring->keys = keys; keyring->n_keys = n_keys; keys = NULL; @@ -632,11 +661,14 @@ _dbus_keyring_reload (DBusKeyring *keyring, * Increments reference count of the keyring * * @param keyring the keyring + * @returns the keyring */ -void +DBusKeyring * _dbus_keyring_ref (DBusKeyring *keyring) { keyring->refcount += 1; + + return keyring; } /** @@ -652,7 +684,9 @@ _dbus_keyring_unref (DBusKeyring *keyring) if (keyring->refcount == 0) { - _dbus_string_free (&keyring->username); + if (keyring->credentials) + _dbus_credentials_unref (keyring->credentials); + _dbus_string_free (&keyring->filename); _dbus_string_free (&keyring->filename_lock); _dbus_string_free (&keyring->directory); @@ -662,82 +696,75 @@ _dbus_keyring_unref (DBusKeyring *keyring) } /** - * Creates a new keyring that lives in the ~/.dbus-keyrings - * directory of the given user. If the username is #NULL, - * uses the user owning the current process. + * Creates a new keyring that lives in the ~/.dbus-keyrings directory + * of the user represented by @p credentials. If the @p credentials are + * #NULL or empty, uses those of the current process. * - * @param username username to get keyring for, or #NULL + * @param credentials a set of credentials representing a user or #NULL * @param context which keyring to get * @param error return location for errors * @returns the keyring or #NULL on error */ DBusKeyring* -_dbus_keyring_new_homedir (const DBusString *username, - const DBusString *context, - DBusError *error) +_dbus_keyring_new_for_credentials (DBusCredentials *credentials, + const DBusString *context, + DBusError *error) { - DBusString homedir; + DBusString ringdir; DBusKeyring *keyring; dbus_bool_t error_set; - DBusString dotdir; DBusError tmp_error; - + DBusCredentials *our_credentials; + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (_dbus_check_setuid ()) + { + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Unable to create DBus keyring when setuid"); + return NULL; + } keyring = NULL; error_set = FALSE; + our_credentials = NULL; - if (!_dbus_string_init (&homedir)) - return FALSE; - - _dbus_string_init_const (&dotdir, ".dbus-keyrings"); - - if (username == NULL) + if (!_dbus_string_init (&ringdir)) { - const DBusString *const_homedir; - - if (!_dbus_user_info_from_current_process (&username, - &const_homedir, - NULL)) - goto failed; + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } - if (!_dbus_string_copy (const_homedir, 0, - &homedir, 0)) - goto failed; + if (credentials != NULL) + { + our_credentials = _dbus_credentials_copy (credentials); } else { - if (!_dbus_homedir_from_username (username, &homedir)) - goto failed; + our_credentials = _dbus_credentials_new_from_current_process (); } + + if (our_credentials == NULL) + goto failed; -#ifdef DBUS_BUILD_TESTS - { - const char *override; - - override = _dbus_getenv ("DBUS_TEST_HOMEDIR"); - if (override != NULL && *override != '\0') - { - _dbus_string_set_length (&homedir, 0); - if (!_dbus_string_append (&homedir, override)) - _dbus_assert_not_reached ("no memory"); - - _dbus_verbose ("Using fake homedir for testing: %s\n", - _dbus_string_get_const_data (&homedir)); - } - else - { - _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n"); - } - } -#endif + if (_dbus_credentials_are_anonymous (our_credentials)) + { + if (!_dbus_credentials_add_from_current_process (our_credentials)) + goto failed; + } - _dbus_assert (username != NULL); + if (!_dbus_append_keyring_directory_for_credentials (&ringdir, + our_credentials)) + goto failed; keyring = _dbus_keyring_new (); if (keyring == NULL) goto failed; + _dbus_assert (keyring->credentials == NULL); + keyring->credentials = our_credentials; + our_credentials = NULL; /* so we don't unref it again later */ + /* should have been validated already, but paranoia check here */ if (!_dbus_keyring_validate_context (context)) { @@ -748,20 +775,12 @@ _dbus_keyring_new_homedir (const DBusString *username, goto failed; } - if (!_dbus_string_copy (username, 0, - &keyring->username, 0)) - goto failed; - - if (!_dbus_string_copy (&homedir, 0, + /* Save keyring dir in the keyring object */ + if (!_dbus_string_copy (&ringdir, 0, &keyring->directory, 0)) - goto failed; - - _dbus_string_free (&homedir); - - if (!_dbus_concat_dir_and_file (&keyring->directory, - &dotdir)) - goto failed; + goto failed; + /* Create keyring->filename based on keyring dir and context */ if (!_dbus_string_copy (&keyring->directory, 0, &keyring->filename, 0)) goto failed; @@ -770,6 +789,7 @@ _dbus_keyring_new_homedir (const DBusString *username, context)) goto failed; + /* Create lockfile name */ if (!_dbus_string_copy (&keyring->filename, 0, &keyring->filename_lock, 0)) goto failed; @@ -777,6 +797,7 @@ _dbus_keyring_new_homedir (const DBusString *username, if (!_dbus_string_append (&keyring->filename_lock, ".lock")) goto failed; + /* Reload keyring */ dbus_error_init (&tmp_error); if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error)) { @@ -797,6 +818,8 @@ _dbus_keyring_new_homedir (const DBusString *username, tmp_error.message); dbus_error_free (&tmp_error); } + + _dbus_string_free (&ringdir); return keyring; @@ -804,11 +827,13 @@ _dbus_keyring_new_homedir (const DBusString *username, if (!error_set) dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, - "No memory to create keyring"); + NULL); + if (our_credentials) + _dbus_credentials_unref (our_credentials); if (keyring) _dbus_keyring_unref (keyring); - _dbus_string_free (&homedir); - return FALSE; + _dbus_string_free (&ringdir); + return NULL; } @@ -890,7 +915,7 @@ find_recent_key (DBusKeyring *keyring) int i; long tv_sec, tv_usec; - _dbus_get_current_time (&tv_sec, &tv_usec); + _dbus_get_real_time (&tv_sec, &tv_usec); i = 0; while (i < keyring->n_keys) @@ -952,19 +977,19 @@ _dbus_keyring_get_best_key (DBusKeyring *keyring, } /** - * Checks whether the keyring is for the given username. + * Checks whether the keyring is for the same user as the given credentials. * * @param keyring the keyring - * @param username the username to check + * @param credentials the credentials to check * * @returns #TRUE if the keyring belongs to the given user */ dbus_bool_t -_dbus_keyring_is_for_user (DBusKeyring *keyring, - const DBusString *username) +_dbus_keyring_is_for_credentials (DBusKeyring *keyring, + DBusCredentials *credentials) { - return _dbus_string_equal (&keyring->username, - username); + return _dbus_credentials_same_user (keyring->credentials, + credentials); } /** @@ -998,7 +1023,7 @@ _dbus_keyring_get_hex_key (DBusKeyring *keyring, /** @} */ /* end of exposed API */ -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS #include "dbus-test.h" #include @@ -1054,9 +1079,9 @@ _dbus_keyring_test (void) _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite"); dbus_error_init (&error); - ring1 = _dbus_keyring_new_homedir (NULL, &context, - &error); - _dbus_assert (ring1); + ring1 = _dbus_keyring_new_for_credentials (NULL, &context, + &error); + _dbus_assert (ring1 != NULL); _dbus_assert (error.name == NULL); id = _dbus_keyring_get_best_key (ring1, &error); @@ -1067,8 +1092,8 @@ _dbus_keyring_test (void) goto failure; } - ring2 = _dbus_keyring_new_homedir (NULL, &context, &error); - _dbus_assert (ring2); + ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error); + _dbus_assert (ring2 != NULL); _dbus_assert (error.name == NULL); if (ring1->n_keys != ring2->n_keys) @@ -1109,6 +1134,14 @@ _dbus_keyring_test (void) printf (" %d keys in test\n", ring1->n_keys); + /* Test ref/unref */ + _dbus_keyring_ref (ring1); + _dbus_keyring_ref (ring2); + _dbus_keyring_unref (ring1); + _dbus_keyring_unref (ring2); + + + /* really unref */ _dbus_keyring_unref (ring1); _dbus_keyring_unref (ring2); @@ -1123,5 +1156,5 @@ _dbus_keyring_test (void) return FALSE; } -#endif /* DBUS_BUILD_TESTS */ +#endif /* DBUS_ENABLE_EMBEDDED_TESTS */