00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00024 #include "dbus-userdb.h"
00025 #include "dbus-hash.h"
00026 #include "dbus-test.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-protocol.h"
00029 #include <string.h>
00030
00042 void
00043 _dbus_user_info_free_allocated (DBusUserInfo *info)
00044 {
00045 if (info == NULL)
00046 return;
00047
00048 _dbus_user_info_free (info);
00049 dbus_free (info);
00050 }
00051
00058 void
00059 _dbus_group_info_free_allocated (DBusGroupInfo *info)
00060 {
00061 if (info == NULL)
00062 return;
00063
00064 _dbus_group_info_free (info);
00065 dbus_free (info);
00066 }
00067
00076 dbus_bool_t
00077 _dbus_is_a_number (const DBusString *str,
00078 unsigned long *num)
00079 {
00080 int end;
00081
00082 if (_dbus_string_parse_int (str, 0, num, &end) &&
00083 end == _dbus_string_get_length (str))
00084 return TRUE;
00085 else
00086 return FALSE;
00087 }
00088
00101 DBusUserInfo*
00102 _dbus_user_database_lookup (DBusUserDatabase *db,
00103 dbus_uid_t uid,
00104 const DBusString *username,
00105 DBusError *error)
00106 {
00107 DBusUserInfo *info;
00108
00109 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00110 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00111
00112
00113 if (uid == DBUS_UID_UNSET)
00114 {
00115 unsigned long n;
00116
00117 if (_dbus_is_a_number (username, &n))
00118 uid = n;
00119 }
00120
00121 if (uid != DBUS_UID_UNSET)
00122 info = _dbus_hash_table_lookup_ulong (db->users, uid);
00123 else
00124 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00125
00126 if (info)
00127 {
00128 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00129 info->uid);
00130 return info;
00131 }
00132 else
00133 {
00134 if (uid != DBUS_UID_UNSET)
00135 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00136 uid);
00137 else
00138 _dbus_verbose ("No cache for user \"%s\"\n",
00139 _dbus_string_get_const_data (username));
00140
00141 info = dbus_new0 (DBusUserInfo, 1);
00142 if (info == NULL)
00143 {
00144 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00145 return NULL;
00146 }
00147
00148 if (uid != DBUS_UID_UNSET)
00149 {
00150 if (!_dbus_user_info_fill_uid (info, uid, error))
00151 {
00152 _DBUS_ASSERT_ERROR_IS_SET (error);
00153 _dbus_user_info_free_allocated (info);
00154 return NULL;
00155 }
00156 }
00157 else
00158 {
00159 if (!_dbus_user_info_fill (info, username, error))
00160 {
00161 _DBUS_ASSERT_ERROR_IS_SET (error);
00162 _dbus_user_info_free_allocated (info);
00163 return NULL;
00164 }
00165 }
00166
00167
00168 uid = DBUS_UID_UNSET;
00169 username = NULL;
00170
00171
00172 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00173 {
00174 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00175 _dbus_user_info_free_allocated (info);
00176 return NULL;
00177 }
00178
00179 if (!_dbus_hash_table_insert_string (db->users_by_name,
00180 info->username,
00181 info))
00182 {
00183 _dbus_hash_table_remove_ulong (db->users, info->uid);
00184 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00185 return NULL;
00186 }
00187
00188 return info;
00189 }
00190 }
00191
00192 _DBUS_DEFINE_GLOBAL_LOCK(system_users);
00193 static dbus_bool_t database_locked = FALSE;
00194 static DBusUserDatabase *system_db = NULL;
00195 static DBusString process_username;
00196 static DBusString process_homedir;
00197
00198 static void
00199 shutdown_system_db (void *data)
00200 {
00201 _dbus_user_database_unref (system_db);
00202 system_db = NULL;
00203 _dbus_string_free (&process_username);
00204 _dbus_string_free (&process_homedir);
00205 }
00206
00207 static dbus_bool_t
00208 init_system_db (void)
00209 {
00210 _dbus_assert (database_locked);
00211
00212 if (system_db == NULL)
00213 {
00214 DBusError error;
00215 const DBusUserInfo *info;
00216
00217 system_db = _dbus_user_database_new ();
00218 if (system_db == NULL)
00219 return FALSE;
00220
00221 dbus_error_init (&error);
00222
00223 if (!_dbus_user_database_get_uid (system_db,
00224 _dbus_getuid (),
00225 &info,
00226 &error))
00227 {
00228 _dbus_user_database_unref (system_db);
00229 system_db = NULL;
00230
00231 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00232 {
00233 dbus_error_free (&error);
00234 return FALSE;
00235 }
00236 else
00237 {
00238
00239 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00240 error.message);
00241 dbus_error_free (&error);
00242 return FALSE;
00243 }
00244 }
00245
00246 if (!_dbus_string_init (&process_username))
00247 {
00248 _dbus_user_database_unref (system_db);
00249 system_db = NULL;
00250 return FALSE;
00251 }
00252
00253 if (!_dbus_string_init (&process_homedir))
00254 {
00255 _dbus_string_free (&process_username);
00256 _dbus_user_database_unref (system_db);
00257 system_db = NULL;
00258 return FALSE;
00259 }
00260
00261 if (!_dbus_string_append (&process_username,
00262 info->username) ||
00263 !_dbus_string_append (&process_homedir,
00264 info->homedir) ||
00265 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00266 {
00267 _dbus_string_free (&process_username);
00268 _dbus_string_free (&process_homedir);
00269 _dbus_user_database_unref (system_db);
00270 system_db = NULL;
00271 return FALSE;
00272 }
00273 }
00274
00275 return TRUE;
00276 }
00277
00281 void
00282 _dbus_user_database_lock_system (void)
00283 {
00284 _DBUS_LOCK (system_users);
00285 database_locked = TRUE;
00286 }
00287
00291 void
00292 _dbus_user_database_unlock_system (void)
00293 {
00294 database_locked = FALSE;
00295 _DBUS_UNLOCK (system_users);
00296 }
00297
00304 DBusUserDatabase*
00305 _dbus_user_database_get_system (void)
00306 {
00307 _dbus_assert (database_locked);
00308
00309 init_system_db ();
00310
00311 return system_db;
00312 }
00313
00321 dbus_bool_t
00322 _dbus_username_from_current_process (const DBusString **username)
00323 {
00324 _dbus_user_database_lock_system ();
00325 if (!init_system_db ())
00326 {
00327 _dbus_user_database_unlock_system ();
00328 return FALSE;
00329 }
00330 *username = &process_username;
00331 _dbus_user_database_unlock_system ();
00332
00333 return TRUE;
00334 }
00335
00343 dbus_bool_t
00344 _dbus_homedir_from_current_process (const DBusString **homedir)
00345 {
00346 _dbus_user_database_lock_system ();
00347 if (!init_system_db ())
00348 {
00349 _dbus_user_database_unlock_system ();
00350 return FALSE;
00351 }
00352 *homedir = &process_homedir;
00353 _dbus_user_database_unlock_system ();
00354
00355 return TRUE;
00356 }
00357
00365 dbus_bool_t
00366 _dbus_homedir_from_username (const DBusString *username,
00367 DBusString *homedir)
00368 {
00369 DBusUserDatabase *db;
00370 const DBusUserInfo *info;
00371 _dbus_user_database_lock_system ();
00372
00373 db = _dbus_user_database_get_system ();
00374 if (db == NULL)
00375 {
00376 _dbus_user_database_unlock_system ();
00377 return FALSE;
00378 }
00379
00380 if (!_dbus_user_database_get_username (db, username,
00381 &info, NULL))
00382 {
00383 _dbus_user_database_unlock_system ();
00384 return FALSE;
00385 }
00386
00387 if (!_dbus_string_append (homedir, info->homedir))
00388 {
00389 _dbus_user_database_unlock_system ();
00390 return FALSE;
00391 }
00392
00393 _dbus_user_database_unlock_system ();
00394 return TRUE;
00395 }
00396
00404 dbus_bool_t
00405 _dbus_credentials_from_username (const DBusString *username,
00406 DBusCredentials *credentials)
00407 {
00408 DBusUserDatabase *db;
00409 const DBusUserInfo *info;
00410 _dbus_user_database_lock_system ();
00411
00412 db = _dbus_user_database_get_system ();
00413 if (db == NULL)
00414 {
00415 _dbus_user_database_unlock_system ();
00416 return FALSE;
00417 }
00418
00419 if (!_dbus_user_database_get_username (db, username,
00420 &info, NULL))
00421 {
00422 _dbus_user_database_unlock_system ();
00423 return FALSE;
00424 }
00425
00426 credentials->pid = DBUS_PID_UNSET;
00427 credentials->uid = info->uid;
00428 credentials->gid = info->primary_gid;
00429
00430 _dbus_user_database_unlock_system ();
00431 return TRUE;
00432 }
00433
00439 DBusUserDatabase*
00440 _dbus_user_database_new (void)
00441 {
00442 DBusUserDatabase *db;
00443
00444 db = dbus_new0 (DBusUserDatabase, 1);
00445 if (db == NULL)
00446 return NULL;
00447
00448 db->refcount = 1;
00449
00450 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00451 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00452
00453 if (db->users == NULL)
00454 goto failed;
00455
00456 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00457 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00458
00459 if (db->groups == NULL)
00460 goto failed;
00461
00462 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00463 NULL, NULL);
00464 if (db->users_by_name == NULL)
00465 goto failed;
00466
00467 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00468 NULL, NULL);
00469 if (db->groups_by_name == NULL)
00470 goto failed;
00471
00472 return db;
00473
00474 failed:
00475 _dbus_user_database_unref (db);
00476 return NULL;
00477 }
00478
00482 void
00483 _dbus_user_database_flush (DBusUserDatabase *db)
00484 {
00485 _dbus_hash_table_remove_all(db->users_by_name);
00486 _dbus_hash_table_remove_all(db->groups_by_name);
00487 _dbus_hash_table_remove_all(db->users);
00488 _dbus_hash_table_remove_all(db->groups);
00489 }
00490
00491 #ifdef DBUS_BUILD_TESTS
00492
00497 DBusUserDatabase *
00498 _dbus_user_database_ref (DBusUserDatabase *db)
00499 {
00500 _dbus_assert (db->refcount > 0);
00501
00502 db->refcount += 1;
00503
00504 return db;
00505 }
00506 #endif
00507
00512 void
00513 _dbus_user_database_unref (DBusUserDatabase *db)
00514 {
00515 _dbus_assert (db->refcount > 0);
00516
00517 db->refcount -= 1;
00518 if (db->refcount == 0)
00519 {
00520 if (db->users)
00521 _dbus_hash_table_unref (db->users);
00522
00523 if (db->groups)
00524 _dbus_hash_table_unref (db->groups);
00525
00526 if (db->users_by_name)
00527 _dbus_hash_table_unref (db->users_by_name);
00528
00529 if (db->groups_by_name)
00530 _dbus_hash_table_unref (db->groups_by_name);
00531
00532 dbus_free (db);
00533 }
00534 }
00535
00546 dbus_bool_t
00547 _dbus_user_database_get_uid (DBusUserDatabase *db,
00548 dbus_uid_t uid,
00549 const DBusUserInfo **info,
00550 DBusError *error)
00551 {
00552 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00553 return *info != NULL;
00554 }
00555
00565 dbus_bool_t
00566 _dbus_user_database_get_username (DBusUserDatabase *db,
00567 const DBusString *username,
00568 const DBusUserInfo **info,
00569 DBusError *error)
00570 {
00571 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00572 return *info != NULL;
00573 }
00574
00577