00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dbus-userdb.h"
00024 #include "dbus-hash.h"
00025 #include "dbus-test.h"
00026 #include "dbus-internals.h"
00027 #include <string.h>
00028
00029 struct DBusUserDatabase
00030 {
00031 int refcount;
00032
00033 DBusHashTable *users;
00034 DBusHashTable *groups;
00035 DBusHashTable *users_by_name;
00036 DBusHashTable *groups_by_name;
00037 };
00038
00039 static void
00040 free_user_info (void *data)
00041 {
00042 DBusUserInfo *info = data;
00043
00044 if (info == NULL)
00045 return;
00046
00047 _dbus_user_info_free (info);
00048 dbus_free (info);
00049 }
00050
00051 static void
00052 free_group_info (void *data)
00053 {
00054 DBusGroupInfo *info = data;
00055
00056 if (info == NULL)
00057 return;
00058
00059 _dbus_group_info_free (info);
00060 dbus_free (info);
00061 }
00062
00063 static DBusUserInfo*
00064 _dbus_user_database_lookup (DBusUserDatabase *db,
00065 dbus_uid_t uid,
00066 const DBusString *username,
00067 DBusError *error)
00068 {
00069 DBusUserInfo *info;
00070
00071 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00072 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00073
00074 if (uid != DBUS_UID_UNSET)
00075 info = _dbus_hash_table_lookup_ulong (db->users, uid);
00076 else
00077 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00078
00079 if (info)
00080 {
00081 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00082 uid);
00083 return info;
00084 }
00085 else
00086 {
00087 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00088 uid);
00089
00090 info = dbus_new0 (DBusUserInfo, 1);
00091 if (info == NULL)
00092 {
00093 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00094 return NULL;
00095 }
00096
00097 if (uid != DBUS_UID_UNSET)
00098 {
00099 if (!_dbus_user_info_fill_uid (info, uid, error))
00100 {
00101 _DBUS_ASSERT_ERROR_IS_SET (error);
00102 free_user_info (info);
00103 return NULL;
00104 }
00105 }
00106 else
00107 {
00108 if (!_dbus_user_info_fill (info, username, error))
00109 {
00110 _DBUS_ASSERT_ERROR_IS_SET (error);
00111 free_user_info (info);
00112 return NULL;
00113 }
00114 }
00115
00116
00117 uid = DBUS_UID_UNSET;
00118 username = NULL;
00119
00120
00121 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00122 {
00123 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00124 free_user_info (info);
00125 return NULL;
00126 }
00127
00128 if (!_dbus_hash_table_insert_string (db->users_by_name,
00129 info->username,
00130 info))
00131 {
00132 _dbus_hash_table_remove_ulong (db->users, info->uid);
00133 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00134 return NULL;
00135 }
00136
00137 return info;
00138 }
00139 }
00140
00141 static DBusGroupInfo*
00142 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00143 dbus_gid_t gid,
00144 const DBusString *groupname,
00145 DBusError *error)
00146 {
00147 DBusGroupInfo *info;
00148
00149 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00150
00151 if (gid != DBUS_GID_UNSET)
00152 info = _dbus_hash_table_lookup_ulong (db->groups, gid);
00153 else
00154 info = _dbus_hash_table_lookup_string (db->groups_by_name,
00155 _dbus_string_get_const_data (groupname));
00156 if (info)
00157 {
00158 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00159 gid);
00160 return info;
00161 }
00162 else
00163 {
00164 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00165 gid);
00166
00167 info = dbus_new0 (DBusGroupInfo, 1);
00168 if (info == NULL)
00169 {
00170 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00171 return NULL;
00172 }
00173
00174 if (!_dbus_group_info_fill_gid (info, gid, error))
00175 {
00176 _DBUS_ASSERT_ERROR_IS_SET (error);
00177 free_group_info (info);
00178 return NULL;
00179 }
00180
00181 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
00182 {
00183 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00184 free_group_info (info);
00185 return NULL;
00186 }
00187
00188
00189 if (!_dbus_hash_table_insert_string (db->groups_by_name,
00190 info->groupname,
00191 info))
00192 {
00193 _dbus_hash_table_remove_ulong (db->groups, info->gid);
00194 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00195 return NULL;
00196 }
00197
00198 return info;
00199 }
00200 }
00201
00202 _DBUS_DEFINE_GLOBAL_LOCK(system_users);
00203 static dbus_bool_t database_locked = FALSE;
00204 static DBusUserDatabase *system_db = NULL;
00205 static DBusString process_username;
00206 static DBusString process_homedir;
00207
00208 static void
00209 shutdown_system_db (void *data)
00210 {
00211 _dbus_user_database_unref (system_db);
00212 system_db = NULL;
00213 _dbus_string_free (&process_username);
00214 _dbus_string_free (&process_homedir);
00215 }
00216
00217 static dbus_bool_t
00218 init_system_db (void)
00219 {
00220 _dbus_assert (database_locked);
00221
00222 if (system_db == NULL)
00223 {
00224 DBusError error;
00225 const DBusUserInfo *info;
00226
00227 system_db = _dbus_user_database_new ();
00228 if (system_db == NULL)
00229 return FALSE;
00230
00231 dbus_error_init (&error);
00232
00233 if (!_dbus_user_database_get_uid (system_db,
00234 _dbus_getuid (),
00235 &info,
00236 &error))
00237 {
00238 _dbus_user_database_unref (system_db);
00239 system_db = NULL;
00240
00241 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00242 {
00243 dbus_error_free (&error);
00244 return FALSE;
00245 }
00246 else
00247 {
00248
00249 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00250 error.message);
00251 dbus_error_free (&error);
00252 return FALSE;
00253 }
00254 }
00255
00256 if (!_dbus_string_init (&process_username))
00257 {
00258 _dbus_user_database_unref (system_db);
00259 system_db = NULL;
00260 return FALSE;
00261 }
00262
00263 if (!_dbus_string_init (&process_homedir))
00264 {
00265 _dbus_string_free (&process_username);
00266 _dbus_user_database_unref (system_db);
00267 system_db = NULL;
00268 return FALSE;
00269 }
00270
00271 if (!_dbus_string_append (&process_username,
00272 info->username) ||
00273 !_dbus_string_append (&process_homedir,
00274 info->homedir) ||
00275 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00276 {
00277 _dbus_string_free (&process_username);
00278 _dbus_string_free (&process_homedir);
00279 _dbus_user_database_unref (system_db);
00280 system_db = NULL;
00281 return FALSE;
00282 }
00283 }
00284
00285 return TRUE;
00286 }
00287
00296 void
00297 _dbus_user_database_lock_system (void)
00298 {
00299 _DBUS_LOCK (system_users);
00300 database_locked = TRUE;
00301 }
00302
00306 void
00307 _dbus_user_database_unlock_system (void)
00308 {
00309 database_locked = FALSE;
00310 _DBUS_UNLOCK (system_users);
00311 }
00312
00319 DBusUserDatabase*
00320 _dbus_user_database_get_system (void)
00321 {
00322 _dbus_assert (database_locked);
00323
00324 init_system_db ();
00325
00326 return system_db;
00327 }
00328
00336 dbus_bool_t
00337 _dbus_username_from_current_process (const DBusString **username)
00338 {
00339 _dbus_user_database_lock_system ();
00340 if (!init_system_db ())
00341 {
00342 _dbus_user_database_unlock_system ();
00343 return FALSE;
00344 }
00345 *username = &process_username;
00346 _dbus_user_database_unlock_system ();
00347
00348 return TRUE;
00349 }
00350
00358 dbus_bool_t
00359 _dbus_homedir_from_current_process (const DBusString **homedir)
00360 {
00361 _dbus_user_database_lock_system ();
00362 if (!init_system_db ())
00363 {
00364 _dbus_user_database_unlock_system ();
00365 return FALSE;
00366 }
00367 *homedir = &process_homedir;
00368 _dbus_user_database_unlock_system ();
00369
00370 return TRUE;
00371 }
00372
00380 dbus_bool_t
00381 _dbus_get_user_id (const DBusString *username,
00382 dbus_uid_t *uid)
00383 {
00384 DBusCredentials creds;
00385
00386 if (!_dbus_credentials_from_username (username, &creds))
00387 return FALSE;
00388
00389 if (creds.uid == DBUS_UID_UNSET)
00390 return FALSE;
00391
00392 *uid = creds.uid;
00393
00394 return TRUE;
00395 }
00396
00404 dbus_bool_t
00405 _dbus_get_group_id (const DBusString *groupname,
00406 dbus_gid_t *gid)
00407 {
00408 DBusUserDatabase *db;
00409 const DBusGroupInfo *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_groupname (db, groupname,
00420 &info, NULL))
00421 {
00422 _dbus_user_database_unlock_system ();
00423 return FALSE;
00424 }
00425
00426 *gid = info->gid;
00427
00428 _dbus_user_database_unlock_system ();
00429 return TRUE;
00430 }
00431
00439 dbus_bool_t
00440 _dbus_homedir_from_username (const DBusString *username,
00441 DBusString *homedir)
00442 {
00443 DBusUserDatabase *db;
00444 const DBusUserInfo *info;
00445 _dbus_user_database_lock_system ();
00446
00447 db = _dbus_user_database_get_system ();
00448 if (db == NULL)
00449 {
00450 _dbus_user_database_unlock_system ();
00451 return FALSE;
00452 }
00453
00454 if (!_dbus_user_database_get_username (db, username,
00455 &info, NULL))
00456 {
00457 _dbus_user_database_unlock_system ();
00458 return FALSE;
00459 }
00460
00461 if (!_dbus_string_append (homedir, info->homedir))
00462 {
00463 _dbus_user_database_unlock_system ();
00464 return FALSE;
00465 }
00466
00467 _dbus_user_database_unlock_system ();
00468 return TRUE;
00469 }
00470
00478 dbus_bool_t
00479 _dbus_uid_from_string (const DBusString *uid_str,
00480 dbus_uid_t *uid)
00481 {
00482 int end;
00483 long val;
00484
00485 if (_dbus_string_get_length (uid_str) == 0)
00486 {
00487 _dbus_verbose ("UID string was zero length\n");
00488 return FALSE;
00489 }
00490
00491 val = -1;
00492 end = 0;
00493 if (!_dbus_string_parse_int (uid_str, 0, &val,
00494 &end))
00495 {
00496 _dbus_verbose ("could not parse string as a UID\n");
00497 return FALSE;
00498 }
00499
00500 if (end != _dbus_string_get_length (uid_str))
00501 {
00502 _dbus_verbose ("string contained trailing stuff after UID\n");
00503 return FALSE;
00504 }
00505
00506 *uid = val;
00507
00508 return TRUE;
00509 }
00510
00518 dbus_bool_t
00519 _dbus_credentials_from_username (const DBusString *username,
00520 DBusCredentials *credentials)
00521 {
00522 DBusUserDatabase *db;
00523 const DBusUserInfo *info;
00524 _dbus_user_database_lock_system ();
00525
00526 db = _dbus_user_database_get_system ();
00527 if (db == NULL)
00528 {
00529 _dbus_user_database_unlock_system ();
00530 return FALSE;
00531 }
00532
00533 if (!_dbus_user_database_get_username (db, username,
00534 &info, NULL))
00535 {
00536 _dbus_user_database_unlock_system ();
00537 return FALSE;
00538 }
00539
00540 credentials->pid = DBUS_PID_UNSET;
00541 credentials->uid = info->uid;
00542 credentials->gid = info->primary_gid;
00543
00544 _dbus_user_database_unlock_system ();
00545 return TRUE;
00546 }
00547
00555 dbus_bool_t
00556 _dbus_credentials_from_uid (dbus_uid_t uid,
00557 DBusCredentials *credentials)
00558 {
00559 DBusUserDatabase *db;
00560 const DBusUserInfo *info;
00561 _dbus_user_database_lock_system ();
00562
00563 db = _dbus_user_database_get_system ();
00564 if (db == NULL)
00565 {
00566 _dbus_user_database_unlock_system ();
00567 return FALSE;
00568 }
00569
00570 if (!_dbus_user_database_get_uid (db, uid,
00571 &info, NULL))
00572 {
00573 _dbus_user_database_unlock_system ();
00574 return FALSE;
00575 }
00576
00577 _dbus_assert (info->uid == uid);
00578
00579 credentials->pid = DBUS_PID_UNSET;
00580 credentials->uid = info->uid;
00581 credentials->gid = info->primary_gid;
00582
00583 _dbus_user_database_unlock_system ();
00584 return TRUE;
00585 }
00586
00592 DBusUserDatabase*
00593 _dbus_user_database_new (void)
00594 {
00595 DBusUserDatabase *db;
00596
00597 db = dbus_new0 (DBusUserDatabase, 1);
00598 if (db == NULL)
00599 return NULL;
00600
00601 db->refcount = 1;
00602
00603 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00604 NULL, free_user_info);
00605
00606 if (db->users == NULL)
00607 goto failed;
00608
00609 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00610 NULL, free_group_info);
00611
00612 if (db->groups == NULL)
00613 goto failed;
00614
00615 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00616 NULL, NULL);
00617 if (db->users_by_name == NULL)
00618 goto failed;
00619
00620 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00621 NULL, NULL);
00622 if (db->groups_by_name == NULL)
00623 goto failed;
00624
00625 return db;
00626
00627 failed:
00628 _dbus_user_database_unref (db);
00629 return NULL;
00630 }
00631
00636 void
00637 _dbus_user_database_ref (DBusUserDatabase *db)
00638 {
00639 _dbus_assert (db->refcount > 0);
00640
00641 db->refcount += 1;
00642 }
00643
00648 void
00649 _dbus_user_database_unref (DBusUserDatabase *db)
00650 {
00651 _dbus_assert (db->refcount > 0);
00652
00653 db->refcount -= 1;
00654 if (db->refcount == 0)
00655 {
00656 if (db->users)
00657 _dbus_hash_table_unref (db->users);
00658
00659 if (db->groups)
00660 _dbus_hash_table_unref (db->groups);
00661
00662 if (db->users_by_name)
00663 _dbus_hash_table_unref (db->users_by_name);
00664
00665 if (db->groups_by_name)
00666 _dbus_hash_table_unref (db->groups_by_name);
00667
00668 dbus_free (db);
00669 }
00670 }
00671
00685 dbus_bool_t
00686 _dbus_user_database_get_groups (DBusUserDatabase *db,
00687 dbus_uid_t uid,
00688 dbus_gid_t **group_ids,
00689 int *n_group_ids,
00690 DBusError *error)
00691 {
00692 DBusUserInfo *info;
00693
00694 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00695
00696 *group_ids = NULL;
00697 *n_group_ids = 0;
00698
00699 info = _dbus_user_database_lookup (db, uid, NULL, error);
00700 if (info == NULL)
00701 {
00702 _DBUS_ASSERT_ERROR_IS_SET (error);
00703 return FALSE;
00704 }
00705
00706 if (info->n_group_ids > 0)
00707 {
00708 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00709 if (*group_ids == NULL)
00710 {
00711 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00712 return FALSE;
00713 }
00714
00715 *n_group_ids = info->n_group_ids;
00716
00717 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00718 }
00719
00720 return TRUE;
00721 }
00722
00733 dbus_bool_t
00734 _dbus_user_database_get_uid (DBusUserDatabase *db,
00735 dbus_uid_t uid,
00736 const DBusUserInfo **info,
00737 DBusError *error)
00738 {
00739 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00740 return *info != NULL;
00741 }
00742
00753 dbus_bool_t
00754 _dbus_user_database_get_gid (DBusUserDatabase *db,
00755 dbus_gid_t gid,
00756 const DBusGroupInfo **info,
00757 DBusError *error)
00758 {
00759 *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00760 return *info != NULL;
00761 }
00762
00772 dbus_bool_t
00773 _dbus_user_database_get_username (DBusUserDatabase *db,
00774 const DBusString *username,
00775 const DBusUserInfo **info,
00776 DBusError *error)
00777 {
00778 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00779 return *info != NULL;
00780 }
00781
00792 dbus_bool_t
00793 _dbus_user_database_get_groupname (DBusUserDatabase *db,
00794 const DBusString *groupname,
00795 const DBusGroupInfo **info,
00796 DBusError *error)
00797 {
00798 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00799 return *info != NULL;
00800 }
00801
00804 #ifdef DBUS_BUILD_TESTS
00805 #include <stdio.h>
00806
00812 dbus_bool_t
00813 _dbus_userdb_test (const char *test_data_dir)
00814 {
00815 const DBusString *username;
00816 const DBusString *homedir;
00817
00818 if (!_dbus_username_from_current_process (&username))
00819 _dbus_assert_not_reached ("didn't get username");
00820
00821 if (!_dbus_homedir_from_current_process (&homedir))
00822 _dbus_assert_not_reached ("didn't get homedir");
00823
00824 printf (" Current user: %s homedir: %s\n",
00825 _dbus_string_get_const_data (username),
00826 _dbus_string_get_const_data (homedir));
00827
00828 return TRUE;
00829 }
00830 #endif