00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00025 #include "dbus-userdb.h"
00026 #include "dbus-hash.h"
00027 #include "dbus-test.h"
00028 #include "dbus-internals.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-credentials.h"
00031 #include <string.h>
00032
00044 void
00045 _dbus_user_info_free_allocated (DBusUserInfo *info)
00046 {
00047 if (info == NULL)
00048 return;
00049
00050 _dbus_user_info_free (info);
00051 dbus_free (info);
00052 }
00053
00060 void
00061 _dbus_group_info_free_allocated (DBusGroupInfo *info)
00062 {
00063 if (info == NULL)
00064 return;
00065
00066 _dbus_group_info_free (info);
00067 dbus_free (info);
00068 }
00069
00075 void
00076 _dbus_user_info_free (DBusUserInfo *info)
00077 {
00078 dbus_free (info->group_ids);
00079 dbus_free (info->username);
00080 dbus_free (info->homedir);
00081 }
00082
00088 void
00089 _dbus_group_info_free (DBusGroupInfo *info)
00090 {
00091 dbus_free (info->groupname);
00092 }
00093
00102 dbus_bool_t
00103 _dbus_is_a_number (const DBusString *str,
00104 unsigned long *num)
00105 {
00106 int end;
00107
00108 if (_dbus_string_parse_uint (str, 0, num, &end) &&
00109 end == _dbus_string_get_length (str))
00110 return TRUE;
00111 else
00112 return FALSE;
00113 }
00114
00127 DBusUserInfo*
00128 _dbus_user_database_lookup (DBusUserDatabase *db,
00129 dbus_uid_t uid,
00130 const DBusString *username,
00131 DBusError *error)
00132 {
00133 DBusUserInfo *info;
00134
00135 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00136 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00137
00138
00139 if (uid == DBUS_UID_UNSET)
00140 {
00141 unsigned long n;
00142
00143 if (_dbus_is_a_number (username, &n))
00144 uid = n;
00145 }
00146
00147 if (uid != DBUS_UID_UNSET)
00148 info = _dbus_hash_table_lookup_uintptr (db->users, uid);
00149 else
00150 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00151
00152 if (info)
00153 {
00154 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00155 info->uid);
00156 return info;
00157 }
00158 else
00159 {
00160 if (uid != DBUS_UID_UNSET)
00161 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00162 uid);
00163 else
00164 _dbus_verbose ("No cache for user \"%s\"\n",
00165 _dbus_string_get_const_data (username));
00166
00167 info = dbus_new0 (DBusUserInfo, 1);
00168 if (info == NULL)
00169 {
00170 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00171 return NULL;
00172 }
00173
00174 if (uid != DBUS_UID_UNSET)
00175 {
00176 if (!_dbus_user_info_fill_uid (info, uid, error))
00177 {
00178 _DBUS_ASSERT_ERROR_IS_SET (error);
00179 _dbus_user_info_free_allocated (info);
00180 return NULL;
00181 }
00182 }
00183 else
00184 {
00185 if (!_dbus_user_info_fill (info, username, error))
00186 {
00187 _DBUS_ASSERT_ERROR_IS_SET (error);
00188 _dbus_user_info_free_allocated (info);
00189 return NULL;
00190 }
00191 }
00192
00193
00194 uid = DBUS_UID_UNSET;
00195 username = NULL;
00196
00197
00198 if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info))
00199 {
00200 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00201 _dbus_user_info_free_allocated (info);
00202 return NULL;
00203 }
00204
00205 if (!_dbus_hash_table_insert_string (db->users_by_name,
00206 info->username,
00207 info))
00208 {
00209 _dbus_hash_table_remove_uintptr (db->users, info->uid);
00210 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00211 return NULL;
00212 }
00213
00214 return info;
00215 }
00216 }
00217
00218 static dbus_bool_t database_locked = FALSE;
00219 static DBusUserDatabase *system_db = NULL;
00220 static DBusString process_username;
00221 static DBusString process_homedir;
00222
00223 static void
00224 shutdown_system_db (void *data)
00225 {
00226 if (system_db != NULL)
00227 _dbus_user_database_unref (system_db);
00228 system_db = NULL;
00229 _dbus_string_free (&process_username);
00230 _dbus_string_free (&process_homedir);
00231 }
00232
00233 static dbus_bool_t
00234 init_system_db (void)
00235 {
00236 _dbus_assert (database_locked);
00237
00238 if (system_db == NULL)
00239 {
00240 DBusError error = DBUS_ERROR_INIT;
00241 const DBusUserInfo *info;
00242
00243 system_db = _dbus_user_database_new ();
00244 if (system_db == NULL)
00245 return FALSE;
00246
00247 if (!_dbus_user_database_get_uid (system_db,
00248 _dbus_getuid (),
00249 &info,
00250 &error))
00251 {
00252 _dbus_user_database_unref (system_db);
00253 system_db = NULL;
00254
00255 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00256 {
00257 dbus_error_free (&error);
00258 return FALSE;
00259 }
00260 else
00261 {
00262
00263 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00264 error.message);
00265 dbus_error_free (&error);
00266 return FALSE;
00267 }
00268 }
00269
00270 if (!_dbus_string_init (&process_username))
00271 {
00272 _dbus_user_database_unref (system_db);
00273 system_db = NULL;
00274 return FALSE;
00275 }
00276
00277 if (!_dbus_string_init (&process_homedir))
00278 {
00279 _dbus_string_free (&process_username);
00280 _dbus_user_database_unref (system_db);
00281 system_db = NULL;
00282 return FALSE;
00283 }
00284
00285 if (!_dbus_string_append (&process_username,
00286 info->username) ||
00287 !_dbus_string_append (&process_homedir,
00288 info->homedir) ||
00289 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00290 {
00291 _dbus_string_free (&process_username);
00292 _dbus_string_free (&process_homedir);
00293 _dbus_user_database_unref (system_db);
00294 system_db = NULL;
00295 return FALSE;
00296 }
00297 }
00298
00299 return TRUE;
00300 }
00301
00305 dbus_bool_t
00306 _dbus_user_database_lock_system (void)
00307 {
00308 if (_DBUS_LOCK (system_users))
00309 {
00310 database_locked = TRUE;
00311 return TRUE;
00312 }
00313 else
00314 {
00315 return FALSE;
00316 }
00317 }
00318
00322 void
00323 _dbus_user_database_unlock_system (void)
00324 {
00325 database_locked = FALSE;
00326 _DBUS_UNLOCK (system_users);
00327 }
00328
00335 DBusUserDatabase*
00336 _dbus_user_database_get_system (void)
00337 {
00338 _dbus_assert (database_locked);
00339
00340 init_system_db ();
00341
00342 return system_db;
00343 }
00344
00348 void
00349 _dbus_user_database_flush_system (void)
00350 {
00351 if (!_dbus_user_database_lock_system ())
00352 {
00353
00354 return;
00355 }
00356
00357 if (system_db != NULL)
00358 _dbus_user_database_flush (system_db);
00359
00360 _dbus_user_database_unlock_system ();
00361 }
00362
00370 dbus_bool_t
00371 _dbus_username_from_current_process (const DBusString **username)
00372 {
00373 if (!_dbus_user_database_lock_system ())
00374 return FALSE;
00375
00376 if (!init_system_db ())
00377 {
00378 _dbus_user_database_unlock_system ();
00379 return FALSE;
00380 }
00381 *username = &process_username;
00382 _dbus_user_database_unlock_system ();
00383
00384 return TRUE;
00385 }
00386
00394 dbus_bool_t
00395 _dbus_homedir_from_current_process (const DBusString **homedir)
00396 {
00397 if (!_dbus_user_database_lock_system ())
00398 return FALSE;
00399
00400 if (!init_system_db ())
00401 {
00402 _dbus_user_database_unlock_system ();
00403 return FALSE;
00404 }
00405 *homedir = &process_homedir;
00406 _dbus_user_database_unlock_system ();
00407
00408 return TRUE;
00409 }
00410
00418 dbus_bool_t
00419 _dbus_homedir_from_username (const DBusString *username,
00420 DBusString *homedir)
00421 {
00422 DBusUserDatabase *db;
00423 const DBusUserInfo *info;
00424
00425
00426 if (!_dbus_user_database_lock_system ())
00427 return FALSE;
00428
00429 db = _dbus_user_database_get_system ();
00430 if (db == NULL)
00431 {
00432 _dbus_user_database_unlock_system ();
00433 return FALSE;
00434 }
00435
00436 if (!_dbus_user_database_get_username (db, username,
00437 &info, NULL))
00438 {
00439 _dbus_user_database_unlock_system ();
00440 return FALSE;
00441 }
00442
00443 if (!_dbus_string_append (homedir, info->homedir))
00444 {
00445 _dbus_user_database_unlock_system ();
00446 return FALSE;
00447 }
00448
00449 _dbus_user_database_unlock_system ();
00450 return TRUE;
00451 }
00452
00460 dbus_bool_t
00461 _dbus_homedir_from_uid (dbus_uid_t uid,
00462 DBusString *homedir)
00463 {
00464 DBusUserDatabase *db;
00465 const DBusUserInfo *info;
00466
00467
00468 if (!_dbus_user_database_lock_system ())
00469 return FALSE;
00470
00471 db = _dbus_user_database_get_system ();
00472 if (db == NULL)
00473 {
00474 _dbus_user_database_unlock_system ();
00475 return FALSE;
00476 }
00477
00478 if (!_dbus_user_database_get_uid (db, uid,
00479 &info, NULL))
00480 {
00481 _dbus_user_database_unlock_system ();
00482 return FALSE;
00483 }
00484
00485 if (!_dbus_string_append (homedir, info->homedir))
00486 {
00487 _dbus_user_database_unlock_system ();
00488 return FALSE;
00489 }
00490
00491 _dbus_user_database_unlock_system ();
00492 return TRUE;
00493 }
00494
00509 dbus_bool_t
00510 _dbus_credentials_add_from_user (DBusCredentials *credentials,
00511 const DBusString *username)
00512 {
00513 DBusUserDatabase *db;
00514 const DBusUserInfo *info;
00515
00516
00517 if (!_dbus_user_database_lock_system ())
00518 return FALSE;
00519
00520 db = _dbus_user_database_get_system ();
00521 if (db == NULL)
00522 {
00523 _dbus_user_database_unlock_system ();
00524 return FALSE;
00525 }
00526
00527 if (!_dbus_user_database_get_username (db, username,
00528 &info, NULL))
00529 {
00530 _dbus_user_database_unlock_system ();
00531 return FALSE;
00532 }
00533
00534 if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
00535 {
00536 _dbus_user_database_unlock_system ();
00537 return FALSE;
00538 }
00539
00540 _dbus_user_database_unlock_system ();
00541 return TRUE;
00542 }
00543
00549 DBusUserDatabase*
00550 _dbus_user_database_new (void)
00551 {
00552 DBusUserDatabase *db;
00553
00554 db = dbus_new0 (DBusUserDatabase, 1);
00555 if (db == NULL)
00556 return NULL;
00557
00558 db->refcount = 1;
00559
00560 db->users = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
00561 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00562
00563 if (db->users == NULL)
00564 goto failed;
00565
00566 db->groups = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
00567 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00568
00569 if (db->groups == NULL)
00570 goto failed;
00571
00572 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00573 NULL, NULL);
00574 if (db->users_by_name == NULL)
00575 goto failed;
00576
00577 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00578 NULL, NULL);
00579 if (db->groups_by_name == NULL)
00580 goto failed;
00581
00582 return db;
00583
00584 failed:
00585 _dbus_user_database_unref (db);
00586 return NULL;
00587 }
00588
00592 void
00593 _dbus_user_database_flush (DBusUserDatabase *db)
00594 {
00595 _dbus_hash_table_remove_all(db->users_by_name);
00596 _dbus_hash_table_remove_all(db->groups_by_name);
00597 _dbus_hash_table_remove_all(db->users);
00598 _dbus_hash_table_remove_all(db->groups);
00599 }
00600
00601 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00602
00607 DBusUserDatabase *
00608 _dbus_user_database_ref (DBusUserDatabase *db)
00609 {
00610 _dbus_assert (db->refcount > 0);
00611
00612 db->refcount += 1;
00613
00614 return db;
00615 }
00616 #endif
00617
00622 void
00623 _dbus_user_database_unref (DBusUserDatabase *db)
00624 {
00625 _dbus_assert (db->refcount > 0);
00626
00627 db->refcount -= 1;
00628 if (db->refcount == 0)
00629 {
00630 if (db->users)
00631 _dbus_hash_table_unref (db->users);
00632
00633 if (db->groups)
00634 _dbus_hash_table_unref (db->groups);
00635
00636 if (db->users_by_name)
00637 _dbus_hash_table_unref (db->users_by_name);
00638
00639 if (db->groups_by_name)
00640 _dbus_hash_table_unref (db->groups_by_name);
00641
00642 dbus_free (db);
00643 }
00644 }
00645
00656 dbus_bool_t
00657 _dbus_user_database_get_uid (DBusUserDatabase *db,
00658 dbus_uid_t uid,
00659 const DBusUserInfo **info,
00660 DBusError *error)
00661 {
00662 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00663 return *info != NULL;
00664 }
00665
00675 dbus_bool_t
00676 _dbus_user_database_get_username (DBusUserDatabase *db,
00677 const DBusString *username,
00678 const DBusUserInfo **info,
00679 DBusError *error)
00680 {
00681 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00682 return *info != NULL;
00683 }
00684
00687