From a26607ab68bf0878f23d2dbddec781b4b760d034 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 23 Mar 2003 07:41:54 +0000 Subject: 2003-03-23 Havoc Pennington * bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny policies code * dbus/dbus-hash.h: add ULONG hash keys * dbus/dbus-sysdeps.c (_dbus_get_groups): new (_dbus_get_group_id): new function --- dbus/dbus-connection.c | 10 ++- dbus/dbus-hash.c | 143 +++++++++++++++++++++++++++++++++++++- dbus/dbus-hash.h | 96 ++++++++++++++------------ dbus/dbus-sysdeps.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-sysdeps.h | 8 +++ dbus/dbus-transport.c | 8 ++- 6 files changed, 399 insertions(+), 49 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index db621405..ad8a1724 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -2214,6 +2214,8 @@ dbus_connection_handle_watch (DBusConnection *connection, * Gets the UNIX user ID of the connection if any. * Returns #TRUE if the uid is filled in. * Always returns #FALSE on non-UNIX platforms. + * Always returns #FALSE prior to authenticating the + * connection. * * @param connection the connection * @param uid return location for the user ID @@ -2226,8 +2228,12 @@ dbus_connection_get_unix_user (DBusConnection *connection, dbus_bool_t result; dbus_mutex_lock (connection->mutex); - result = _dbus_transport_get_unix_user (connection->transport, - uid); + + if (!_dbus_transport_get_is_authenticated (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_unix_user (connection->transport, + uid); dbus_mutex_unlock (connection->mutex); return result; diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index a53c5020..ff3f3b08 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -313,6 +313,7 @@ _dbus_hash_table_new (DBusHashType type, { case DBUS_HASH_INT: case DBUS_HASH_POINTER: + case DBUS_HASH_ULONG: table->find_function = find_direct_function; break; case DBUS_HASH_STRING: @@ -642,6 +643,25 @@ _dbus_hash_iter_get_int_key (DBusHashIter *iter) return _DBUS_POINTER_TO_INT (real->entry->key); } +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_ULONG. + * + * @param iter the hash table iterator. + */ +unsigned long +_dbus_hash_iter_get_ulong_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return (unsigned long) real->entry->key; +} + /** * Gets the key for the current entry. * Only works for hash tables of type #DBUS_HASH_STRING @@ -963,6 +983,7 @@ rebuild_table (DBusHashTable *table) idx = string_hash (entry->key) & table->mask; break; case DBUS_HASH_INT: + case DBUS_HASH_ULONG: case DBUS_HASH_POINTER: idx = RANDOM_INDEX (table, entry->key); break; @@ -1059,6 +1080,31 @@ _dbus_hash_table_lookup_pointer (DBusHashTable *table, return NULL; } +/** + * Looks up the value for a given integer in a hash table + * of type #DBUS_HASH_ULONG. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the integer to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_ulong (DBusHashTable *table, + unsigned long key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, FALSE, NULL); + + if (entry) + return entry->value; + else + return NULL; +} + /** * Removes the hash entry for the given key. If no hash entry * for the key exists, does nothing. @@ -1144,6 +1190,34 @@ _dbus_hash_table_remove_pointer (DBusHashTable *table, } +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_ulong (DBusHashTable *table, + unsigned long key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, FALSE, &bucket); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} + /** * Creates a hash entry with the given key and value. * The key and value are not copied; they are stored @@ -1267,6 +1341,48 @@ _dbus_hash_table_insert_pointer (DBusHashTable *table, return TRUE; } + +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_ulong (DBusHashTable *table, + unsigned long key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, TRUE, NULL); + + if (entry == NULL) + return FALSE; /* no memory */ + + if (table->free_key_function && entry->key != (void*) key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = (void*) key; + entry->value = value; + + return TRUE; +} + /** * Gets the number of hash entries in a hash table. * @@ -1316,6 +1432,7 @@ _dbus_hash_test (void) int i; DBusHashTable *table1; DBusHashTable *table2; + DBusHashTable *table3; DBusHashIter iter; #define N_HASH_KEYS 5000 char **keys; @@ -1352,6 +1469,11 @@ _dbus_hash_test (void) if (table2 == NULL) goto out; + table3 = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, dbus_free); + if (table3 == NULL) + goto out; + /* Insert and remove a bunch of stuff, counting the table in between * to be sure it's not broken and that iteration works */ @@ -1379,9 +1501,18 @@ _dbus_hash_test (void) if (!_dbus_hash_table_insert_int (table2, i, value)) goto out; + + value = _dbus_strdup (keys[i]); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_ulong (table3, + i, value)) + goto out; _dbus_assert (count_entries (table1) == i + 1); _dbus_assert (count_entries (table2) == i + 1); + _dbus_assert (count_entries (table3) == i + 1); value = _dbus_hash_table_lookup_string (table1, keys[i]); _dbus_assert (value != NULL); @@ -1390,6 +1521,10 @@ _dbus_hash_test (void) value = _dbus_hash_table_lookup_int (table2, i); _dbus_assert (value != NULL); _dbus_assert (strcmp (value, keys[i]) == 0); + + value = _dbus_hash_table_lookup_ulong (table3, i); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, keys[i]) == 0); ++i; } @@ -1402,19 +1537,25 @@ _dbus_hash_test (void) _dbus_hash_table_remove_int (table2, i); + _dbus_hash_table_remove_ulong (table3, i); + _dbus_assert (count_entries (table1) == i); _dbus_assert (count_entries (table2) == i); + _dbus_assert (count_entries (table3) == i); --i; } _dbus_hash_table_ref (table1); _dbus_hash_table_ref (table2); + _dbus_hash_table_ref (table3); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); + _dbus_hash_table_unref (table3); _dbus_hash_table_unref (table1); _dbus_hash_table_unref (table2); - + _dbus_hash_table_unref (table3); + table3 = NULL; /* Insert a bunch of stuff then check * that iteration works correctly (finds the right diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h index dc60679b..b9efcebb 100644 --- a/dbus/dbus-hash.h +++ b/dbus/dbus-hash.h @@ -52,53 +52,61 @@ typedef struct DBusHashIter DBusHashIter; */ typedef enum { - DBUS_HASH_STRING, /**< Hash keys are strings. */ - DBUS_HASH_INT, /**< Hash keys are integers. */ - DBUS_HASH_POINTER /**< Hash keys are pointers. */ + DBUS_HASH_STRING, /**< Hash keys are strings. */ + DBUS_HASH_INT, /**< Hash keys are integers. */ + DBUS_HASH_POINTER, /**< Hash keys are pointers. */ + DBUS_HASH_ULONG /**< Hash keys are unsigned long. */ } DBusHashType; -DBusHashTable* _dbus_hash_table_new (DBusHashType type, - DBusFreeFunction key_free_function, - DBusFreeFunction value_free_function); -void _dbus_hash_table_ref (DBusHashTable *table); -void _dbus_hash_table_unref (DBusHashTable *table); +DBusHashTable* _dbus_hash_table_new (DBusHashType type, + DBusFreeFunction key_free_function, + DBusFreeFunction value_free_function); +void _dbus_hash_table_ref (DBusHashTable *table); +void _dbus_hash_table_unref (DBusHashTable *table); +void _dbus_hash_iter_init (DBusHashTable *table, + DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); +void _dbus_hash_iter_remove_entry (DBusHashIter *iter); +void* _dbus_hash_iter_get_value (DBusHashIter *iter); +void _dbus_hash_iter_set_value (DBusHashIter *iter, + void *value); +int _dbus_hash_iter_get_int_key (DBusHashIter *iter); +const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); +unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashIter *iter); +void* _dbus_hash_table_lookup_string (DBusHashTable *table, + const char *key); +void* _dbus_hash_table_lookup_int (DBusHashTable *table, + int key); +void* _dbus_hash_table_lookup_pointer (DBusHashTable *table, + void *key); +void* _dbus_hash_table_lookup_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, + const char *key); +dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, + int key); +dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table, + void *key); +dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, + char *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, + int key, + void *value); +dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table, + void *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table, + unsigned long key, + void *value); +int _dbus_hash_table_get_n_entries (DBusHashTable *table); -void _dbus_hash_iter_init (DBusHashTable *table, - DBusHashIter *iter); -dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); - -void _dbus_hash_iter_remove_entry (DBusHashIter *iter); -void* _dbus_hash_iter_get_value (DBusHashIter *iter); -void _dbus_hash_iter_set_value (DBusHashIter *iter, - void *value); -int _dbus_hash_iter_get_int_key (DBusHashIter *iter); -const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); -dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, - void *key, - dbus_bool_t create_if_not_found, - DBusHashIter *iter); -void* _dbus_hash_table_lookup_string (DBusHashTable *table, - const char *key); -void* _dbus_hash_table_lookup_int (DBusHashTable *table, - int key); -void* _dbus_hash_table_lookup_pointer (DBusHashTable *table, - void *key); -dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, - const char *key); -dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, - int key); -dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table, - void *key); -dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, - char *key, - void *value); -dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, - int key, - void *value); -dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table, - void *key, - void *value); -int _dbus_hash_table_get_n_entries (DBusHashTable *table); DBUS_END_DECLS; diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index cd4a82a5..200fbddd 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef HAVE_WRITEV #include @@ -1217,6 +1218,20 @@ _dbus_credentials_from_username (const DBusString *username, return get_user_info (username, -1, credentials, NULL, NULL); } +/** + * Gets the credentials corresponding to the given user ID. + * + * @param user_id the user ID + * @param credentials credentials to fill in + * @returns #TRUE if the username existed and we got some credentials + */ +dbus_bool_t +_dbus_credentials_from_user_id (unsigned long user_id, + DBusCredentials *credentials) +{ + return get_user_info (NULL, user_id, credentials, NULL, NULL); +} + static DBusMutex *user_info_lock = NULL; /** * Initializes the global mutex for the process's user information. @@ -1398,6 +1413,174 @@ _dbus_credentials_match (const DBusCredentials *expected_credentials, return FALSE; } +/** + * Gets group ID from group name. + * + * @param group_name name of the group + * @param gid location to store group ID + * @returns #TRUE if group was known + */ +dbus_bool_t +_dbus_get_group_id (const DBusString *group_name, + unsigned long *gid) +{ + const char *group_c_str; + + _dbus_string_get_const_data (group_name, &group_c_str); + + /* For now assuming that the getgrnam() and getgrgid() flavors + * always correspond to the pwnam flavors, if not we have + * to add more configure checks. + */ + +#if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R) + { + struct group *g; + int result; + char buf[1024]; + struct group g_str; + + g = NULL; +#ifdef HAVE_POSIX_GETPWNAME_R + + result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), + &g); +#else + p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf)); + result = 0; +#endif /* !HAVE_POSIX_GETPWNAME_R */ + if (result == 0 && g == &g_str) + { + *gid = g->gr_gid; + return TRUE; + } + else + { + _dbus_verbose ("Group %s unknown\n", group_c_str); + return FALSE; + } + } +#else /* ! HAVE_GETPWNAM_R */ + { + /* I guess we're screwed on thread safety here */ + struct group *g; + + g = getgrnam (group_c_str); + + if (g != NULL) + { + *gid = g->gr_gid; + return TRUE; + } + else + { + _dbus_verbose ("Group %s unknown\n", group_c_str); + return FALSE; + } + } +#endif /* ! HAVE_GETPWNAM_R */ +} + +/** + * Gets all groups for a particular user. Returns #FALSE + * if no memory, or user isn't known, but always initializes + * group_ids to a NULL array. + * + * @todo failing to distinguish "out of memory" from + * "unknown user" is kind of bogus and would probably + * result in a failure in a comprehensive test suite. + * + * @param uid the user ID + * @param group_ids return location for array of group IDs + * @param n_group_ids return location for length of returned array + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_get_groups (unsigned long uid, + unsigned long **group_ids, + int *n_group_ids) +{ + DBusCredentials creds; + DBusString username; + const char *username_c; + dbus_bool_t retval; + + *group_ids = NULL; + *n_group_ids = 0; + + retval = FALSE; + + if (!_dbus_string_init (&username, _DBUS_INT_MAX)) + return FALSE; + + if (!get_user_info (NULL, uid, &creds, + NULL, &username) || + creds.gid < 0) + goto out; + + _dbus_string_get_const_data (&username, &username_c); + +#ifdef HAVE_GETGROUPLIST + { + gid_t *buf; + int buf_count; + int i; + + buf_count = 17; + buf = dbus_new (gid_t, buf_count); + if (buf == NULL) + goto out; + + if (getgrouplist (username_c, + creds.gid, + buf, &buf_count) < 0) + { + gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0])); + if (new == NULL) + { + dbus_free (buf); + goto out; + } + + buf = new; + + getgrouplist (username_c, creds.gid, buf, &buf_count); + } + + *group_ids = dbus_new (unsigned long, buf_count); + if (*group_ids == NULL) + { + dbus_free (buf); + goto out; + } + + for (i = 0; i < buf_count; ++i) + (*group_ids)[i] = buf[i]; + + *n_group_ids = buf_count; + + dbus_free (buf); + } +#else /* HAVE_GETGROUPLIST */ + { + /* We just get the one group ID */ + *group_ids = dbus_new (unsigned long, 1); + if (*group_ids == NULL) + goto out; + + *n_group_ids = 1; + + (*group_ids)[0] = creds.gid; + } +#endif /* HAVE_GETGROUPLIST */ + + retval = TRUE; + + out: + _dbus_string_free (&username); + return retval; +} + /** * Appends the uid of the current process to the given string. * diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 0c24d0c5..672d23a8 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -96,6 +96,8 @@ dbus_bool_t _dbus_send_credentials_unix_socket (int server_fd, dbus_bool_t _dbus_credentials_from_username (const DBusString *username, DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_from_user_id (unsigned long user_id, + DBusCredentials *credentials); dbus_bool_t _dbus_credentials_from_uid_string (const DBusString *uid_str, DBusCredentials *credentials); void _dbus_credentials_from_current_process (DBusCredentials *credentials); @@ -110,6 +112,12 @@ dbus_bool_t _dbus_user_info_from_current_process (const DBusString **userna const DBusString **homedir, const DBusCredentials **credentials); +dbus_bool_t _dbus_get_group_id (const DBusString *group_name, + unsigned long *gid); +dbus_bool_t _dbus_get_groups (unsigned long uid, + unsigned long **group_ids, + int *n_group_ids); + typedef int dbus_atomic_t; dbus_atomic_t _dbus_atomic_inc (dbus_atomic_t *atomic); diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index b6ab8c0a..b6ad8f9a 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -353,10 +353,12 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) return TRUE; else { + dbus_bool_t maybe_authenticated; + if (transport->disconnected) return FALSE; - transport->authenticated = + maybe_authenticated = (!(transport->send_credentials_pending || transport->receive_credentials_pending)) && _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_AUTHENTICATED; @@ -369,7 +371,7 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) * Or they may give certain identities extra privileges. */ - if (transport->authenticated && transport->is_server) + if (maybe_authenticated && transport->is_server) { DBusCredentials auth_identity; @@ -413,6 +415,8 @@ _dbus_transport_get_is_authenticated (DBusTransport *transport) } } } + + transport->authenticated = maybe_authenticated; return transport->authenticated; } -- cgit