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 "dbus-protocol.h"
00028 #include <string.h>
00029
00033 struct DBusUserDatabase
00034 {
00035 int refcount;
00037 DBusHashTable *users;
00038 DBusHashTable *groups;
00039 DBusHashTable *users_by_name;
00040 DBusHashTable *groups_by_name;
00042 };
00043
00044 static void
00045 free_user_info (void *data)
00046 {
00047 DBusUserInfo *info = data;
00048
00049 if (info == NULL)
00050 return;
00051
00052 _dbus_user_info_free (info);
00053 dbus_free (info);
00054 }
00055
00056 static void
00057 free_group_info (void *data)
00058 {
00059 DBusGroupInfo *info = data;
00060
00061 if (info == NULL)
00062 return;
00063
00064 _dbus_group_info_free (info);
00065 dbus_free (info);
00066 }
00067
00068 static DBusUserInfo*
00069 _dbus_user_database_lookup (DBusUserDatabase *db,
00070 dbus_uid_t uid,
00071 const DBusString *username,
00072 DBusError *error)
00073 {
00074 DBusUserInfo *info;
00075
00076 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00077 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00078
00079 if (uid != DBUS_UID_UNSET)
00080 info = _dbus_hash_table_lookup_ulong (db->users, uid);
00081 else
00082 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00083
00084 if (info)
00085 {
00086 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00087 uid);
00088 return info;
00089 }
00090 else
00091 {
00092 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00093 uid);
00094
00095 info = dbus_new0 (DBusUserInfo, 1);
00096 if (info == NULL)
00097 {
00098 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00099 return NULL;
00100 }
00101
00102 if (uid != DBUS_UID_UNSET)
00103 {
00104 if (!_dbus_user_info_fill_uid (info, uid, error))
00105 {
00106 _DBUS_ASSERT_ERROR_IS_SET (error);
00107 free_user_info (info);
00108 return NULL;
00109 }
00110 }
00111 else
00112 {
00113 if (!_dbus_user_info_fill (info, username, error))
00114 {
00115 _DBUS_ASSERT_ERROR_IS_SET (error);
00116 free_user_info (info);
00117 return NULL;
00118 }
00119 }
00120
00121
00122 uid = DBUS_UID_UNSET;
00123 username = NULL;
00124
00125
00126 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00127 {
00128 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00129 free_user_info (info);
00130 return NULL;
00131 }
00132
00133 if (!_dbus_hash_table_insert_string (db->users_by_name,
00134 info->username,
00135 info))
00136 {
00137 _dbus_hash_table_remove_ulong (db->users, info->uid);
00138 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00139 return NULL;
00140 }
00141
00142 return info;
00143 }
00144 }
00145
00146 static DBusGroupInfo*
00147 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00148 dbus_gid_t gid,
00149 const DBusString *groupname,
00150 DBusError *error)
00151 {
00152 DBusGroupInfo *info;
00153
00154 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00155
00156 if (gid != DBUS_GID_UNSET)
00157 info = _dbus_hash_table_lookup_ulong (db->groups, gid);
00158 else
00159 info = _dbus_hash_table_lookup_string (db->groups_by_name,
00160 _dbus_string_get_const_data (groupname));
00161 if (info)
00162 {
00163 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00164 gid);
00165 return info;
00166 }
00167 else
00168 {
00169 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00170 gid);
00171
00172 info = dbus_new0 (DBusGroupInfo, 1);
00173 if (info == NULL)
00174 {
00175 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00176 return NULL;
00177 }
00178
00179
00180 if (gid != DBUS_GID_UNSET)
00181 {
00182 if (!_dbus_group_info_fill_gid (info, gid, error))
00183 {
00184 _DBUS_ASSERT_ERROR_IS_SET (error);
00185 free_group_info (info);
00186 return NULL;
00187 }
00188 }
00189 else
00190 {
00191 if (!_dbus_group_info_fill (info, groupname, error))
00192 {
00193 _DBUS_ASSERT_ERROR_IS_SET (error);
00194 free_group_info (info);
00195 return NULL;
00196 }
00197 }
00198
00199 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
00200 {
00201 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00202 free_group_info (info);
00203 return NULL;
00204 }
00205
00206
00207 if (!_dbus_hash_table_insert_string (db->groups_by_name,
00208 info->groupname,
00209 info))
00210 {
00211 _dbus_hash_table_remove_ulong (db->groups, info->gid);
00212 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00213 return NULL;
00214 }
00215
00216 return info;
00217 }
00218 }
00219
00220 _DBUS_DEFINE_GLOBAL_LOCK(system_users);
00221 static dbus_bool_t database_locked = FALSE;
00222 static DBusUserDatabase *system_db = NULL;
00223 static DBusString process_username;
00224 static DBusString process_homedir;
00225
00226 static void
00227 shutdown_system_db (void *data)
00228 {
00229 _dbus_user_database_unref (system_db);
00230 system_db = NULL;
00231 _dbus_string_free (&process_username);
00232 _dbus_string_free (&process_homedir);
00233 }
00234
00235 static dbus_bool_t
00236 init_system_db (void)
00237 {
00238 _dbus_assert (database_locked);
00239
00240 if (system_db == NULL)
00241 {
00242 DBusError error;
00243 const DBusUserInfo *info;
00244
00245 system_db = _dbus_user_database_new ();
00246 if (system_db == NULL)
00247 return FALSE;
00248
00249 dbus_error_init (&error);
00250
00251 if (!_dbus_user_database_get_uid (system_db,
00252 _dbus_getuid (),
00253 &info,
00254 &error))
00255 {
00256 _dbus_user_database_unref (system_db);
00257 system_db = NULL;
00258
00259 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00260 {
00261 dbus_error_free (&error);
00262 return FALSE;
00263 }
00264 else
00265 {
00266
00267 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00268 error.message);
00269 dbus_error_free (&error);
00270 return FALSE;
00271 }
00272 }
00273
00274 if (!_dbus_string_init (&process_username))
00275 {
00276 _dbus_user_database_unref (system_db);
00277 system_db = NULL;
00278 return FALSE;
00279 }
00280
00281 if (!_dbus_string_init (&process_homedir))
00282 {
00283 _dbus_string_free (&process_username);
00284 _dbus_user_database_unref (system_db);
00285 system_db = NULL;
00286 return FALSE;
00287 }
00288
00289 if (!_dbus_string_append (&process_username,
00290 info->username) ||
00291 !_dbus_string_append (&process_homedir,
00292 info->homedir) ||
00293 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00294 {
00295 _dbus_string_free (&process_username);
00296 _dbus_string_free (&process_homedir);
00297 _dbus_user_database_unref (system_db);
00298 system_db = NULL;
00299 return FALSE;
00300 }
00301 }
00302
00303 return TRUE;
00304 }
00305
00314 void
00315 _dbus_user_database_lock_system (void)
00316 {
00317 _DBUS_LOCK (system_users);
00318 database_locked = TRUE;
00319 }
00320
00324 void
00325 _dbus_user_database_unlock_system (void)
00326 {
00327 database_locked = FALSE;
00328 _DBUS_UNLOCK (system_users);
00329 }
00330
00337 DBusUserDatabase*
00338 _dbus_user_database_get_system (void)
00339 {
00340 _dbus_assert (database_locked);
00341
00342 init_system_db ();
00343
00344 return system_db;
00345 }
00346
00354 dbus_bool_t
00355 _dbus_username_from_current_process (const DBusString **username)
00356 {
00357 _dbus_user_database_lock_system ();
00358 if (!init_system_db ())
00359 {
00360 _dbus_user_database_unlock_system ();
00361 return FALSE;
00362 }
00363 *username = &process_username;
00364 _dbus_user_database_unlock_system ();
00365
00366 return TRUE;
00367 }
00368
00376 dbus_bool_t
00377 _dbus_homedir_from_current_process (const DBusString **homedir)
00378 {
00379 _dbus_user_database_lock_system ();
00380 if (!init_system_db ())
00381 {
00382 _dbus_user_database_unlock_system ();
00383 return FALSE;
00384 }
00385 *homedir = &process_homedir;
00386 _dbus_user_database_unlock_system ();
00387
00388 return TRUE;
00389 }
00390
00398 dbus_bool_t
00399 _dbus_get_user_id (const DBusString *username,
00400 dbus_uid_t *uid)
00401 {
00402 DBusCredentials creds;
00403
00404 if (!_dbus_credentials_from_username (username, &creds))
00405 return FALSE;
00406
00407 if (creds.uid == DBUS_UID_UNSET)
00408 return FALSE;
00409
00410 *uid = creds.uid;
00411
00412 return TRUE;
00413 }
00414
00422 dbus_bool_t
00423 _dbus_is_console_user (dbus_uid_t uid,
00424 DBusError *error)
00425 {
00426
00427 DBusUserDatabase *db;
00428 const DBusUserInfo *info;
00429 dbus_bool_t result = FALSE;
00430
00431 _dbus_user_database_lock_system ();
00432
00433 db = _dbus_user_database_get_system ();
00434 if (db == NULL)
00435 {
00436 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
00437 _dbus_user_database_unlock_system ();
00438 return FALSE;
00439 }
00440
00441 info = _dbus_user_database_lookup (db, uid, NULL, error);
00442
00443 if (info == NULL)
00444 {
00445 _dbus_user_database_unlock_system ();
00446 return FALSE;
00447 }
00448
00449 result = _dbus_user_at_console (info->username, error);
00450
00451 _dbus_user_database_unlock_system ();
00452
00453 return result;
00454 }
00455
00463 dbus_bool_t
00464 _dbus_get_group_id (const DBusString *groupname,
00465 dbus_gid_t *gid)
00466 {
00467 DBusUserDatabase *db;
00468 const DBusGroupInfo *info;
00469 _dbus_user_database_lock_system ();
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_groupname (db, groupname,
00479 &info, NULL))
00480 {
00481 _dbus_user_database_unlock_system ();
00482 return FALSE;
00483 }
00484
00485 *gid = info->gid;
00486
00487 _dbus_user_database_unlock_system ();
00488 return TRUE;
00489 }
00490
00498 dbus_bool_t
00499 _dbus_homedir_from_username (const DBusString *username,
00500 DBusString *homedir)
00501 {
00502 DBusUserDatabase *db;
00503 const DBusUserInfo *info;
00504 _dbus_user_database_lock_system ();
00505
00506 db = _dbus_user_database_get_system ();
00507 if (db == NULL)
00508 {
00509 _dbus_user_database_unlock_system ();
00510 return FALSE;
00511 }
00512
00513 if (!_dbus_user_database_get_username (db, username,
00514 &info, NULL))
00515 {
00516 _dbus_user_database_unlock_system ();
00517 return FALSE;
00518 }
00519
00520 if (!_dbus_string_append (homedir, info->homedir))
00521 {
00522 _dbus_user_database_unlock_system ();
00523 return FALSE;
00524 }
00525
00526 _dbus_user_database_unlock_system ();
00527 return TRUE;
00528 }
00529
00537 dbus_bool_t
00538 _dbus_uid_from_string (const DBusString *uid_str,
00539 dbus_uid_t *uid)
00540 {
00541 int end;
00542 long val;
00543
00544 if (_dbus_string_get_length (uid_str) == 0)
00545 {
00546 _dbus_verbose ("UID string was zero length\n");
00547 return FALSE;
00548 }
00549
00550 val = -1;
00551 end = 0;
00552 if (!_dbus_string_parse_int (uid_str, 0, &val,
00553 &end))
00554 {
00555 _dbus_verbose ("could not parse string as a UID\n");
00556 return FALSE;
00557 }
00558
00559 if (end != _dbus_string_get_length (uid_str))
00560 {
00561 _dbus_verbose ("string contained trailing stuff after UID\n");
00562 return FALSE;
00563 }
00564
00565 *uid = val;
00566
00567 return TRUE;
00568 }
00569
00577 dbus_bool_t
00578 _dbus_credentials_from_username (const DBusString *username,
00579 DBusCredentials *credentials)
00580 {
00581 DBusUserDatabase *db;
00582 const DBusUserInfo *info;
00583 _dbus_user_database_lock_system ();
00584
00585 db = _dbus_user_database_get_system ();
00586 if (db == NULL)
00587 {
00588 _dbus_user_database_unlock_system ();
00589 return FALSE;
00590 }
00591
00592 if (!_dbus_user_database_get_username (db, username,
00593 &info, NULL))
00594 {
00595 _dbus_user_database_unlock_system ();
00596 return FALSE;
00597 }
00598
00599 credentials->pid = DBUS_PID_UNSET;
00600 credentials->uid = info->uid;
00601 credentials->gid = info->primary_gid;
00602
00603 _dbus_user_database_unlock_system ();
00604 return TRUE;
00605 }
00606
00614 dbus_bool_t
00615 _dbus_credentials_from_uid (dbus_uid_t uid,
00616 DBusCredentials *credentials)
00617 {
00618 DBusUserDatabase *db;
00619 const DBusUserInfo *info;
00620 _dbus_user_database_lock_system ();
00621
00622 db = _dbus_user_database_get_system ();
00623 if (db == NULL)
00624 {
00625 _dbus_user_database_unlock_system ();
00626 return FALSE;
00627 }
00628
00629 if (!_dbus_user_database_get_uid (db, uid,
00630 &info, NULL))
00631 {
00632 _dbus_user_database_unlock_system ();
00633 return FALSE;
00634 }
00635
00636 _dbus_assert (info->uid == uid);
00637
00638 credentials->pid = DBUS_PID_UNSET;
00639 credentials->uid = info->uid;
00640 credentials->gid = info->primary_gid;
00641
00642 _dbus_user_database_unlock_system ();
00643 return TRUE;
00644 }
00645
00651 DBusUserDatabase*
00652 _dbus_user_database_new (void)
00653 {
00654 DBusUserDatabase *db;
00655
00656 db = dbus_new0 (DBusUserDatabase, 1);
00657 if (db == NULL)
00658 return NULL;
00659
00660 db->refcount = 1;
00661
00662 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00663 NULL, free_user_info);
00664
00665 if (db->users == NULL)
00666 goto failed;
00667
00668 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00669 NULL, free_group_info);
00670
00671 if (db->groups == NULL)
00672 goto failed;
00673
00674 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00675 NULL, NULL);
00676 if (db->users_by_name == NULL)
00677 goto failed;
00678
00679 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00680 NULL, NULL);
00681 if (db->groups_by_name == NULL)
00682 goto failed;
00683
00684 return db;
00685
00686 failed:
00687 _dbus_user_database_unref (db);
00688 return NULL;
00689 }
00690
00696 DBusUserDatabase *
00697 _dbus_user_database_ref (DBusUserDatabase *db)
00698 {
00699 _dbus_assert (db->refcount > 0);
00700
00701 db->refcount += 1;
00702
00703 return db;
00704 }
00705
00710 void
00711 _dbus_user_database_unref (DBusUserDatabase *db)
00712 {
00713 _dbus_assert (db->refcount > 0);
00714
00715 db->refcount -= 1;
00716 if (db->refcount == 0)
00717 {
00718 if (db->users)
00719 _dbus_hash_table_unref (db->users);
00720
00721 if (db->groups)
00722 _dbus_hash_table_unref (db->groups);
00723
00724 if (db->users_by_name)
00725 _dbus_hash_table_unref (db->users_by_name);
00726
00727 if (db->groups_by_name)
00728 _dbus_hash_table_unref (db->groups_by_name);
00729
00730 dbus_free (db);
00731 }
00732 }
00733
00747 dbus_bool_t
00748 _dbus_user_database_get_groups (DBusUserDatabase *db,
00749 dbus_uid_t uid,
00750 dbus_gid_t **group_ids,
00751 int *n_group_ids,
00752 DBusError *error)
00753 {
00754 DBusUserInfo *info;
00755
00756 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00757
00758 *group_ids = NULL;
00759 *n_group_ids = 0;
00760
00761 info = _dbus_user_database_lookup (db, uid, NULL, error);
00762 if (info == NULL)
00763 {
00764 _DBUS_ASSERT_ERROR_IS_SET (error);
00765 return FALSE;
00766 }
00767
00768 if (info->n_group_ids > 0)
00769 {
00770 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00771 if (*group_ids == NULL)
00772 {
00773 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00774 return FALSE;
00775 }
00776
00777 *n_group_ids = info->n_group_ids;
00778
00779 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00780 }
00781
00782 return TRUE;
00783 }
00784
00795 dbus_bool_t
00796 _dbus_user_database_get_uid (DBusUserDatabase *db,
00797 dbus_uid_t uid,
00798 const DBusUserInfo **info,
00799 DBusError *error)
00800 {
00801 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00802 return *info != NULL;
00803 }
00804
00815 dbus_bool_t
00816 _dbus_user_database_get_gid (DBusUserDatabase *db,
00817 dbus_gid_t gid,
00818 const DBusGroupInfo **info,
00819 DBusError *error)
00820 {
00821 *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00822 return *info != NULL;
00823 }
00824
00834 dbus_bool_t
00835 _dbus_user_database_get_username (DBusUserDatabase *db,
00836 const DBusString *username,
00837 const DBusUserInfo **info,
00838 DBusError *error)
00839 {
00840 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00841 return *info != NULL;
00842 }
00843
00854 dbus_bool_t
00855 _dbus_user_database_get_groupname (DBusUserDatabase *db,
00856 const DBusString *groupname,
00857 const DBusGroupInfo **info,
00858 DBusError *error)
00859 {
00860 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00861 return *info != NULL;
00862 }
00863
00866 #ifdef DBUS_BUILD_TESTS
00867 #include <stdio.h>
00868
00874 dbus_bool_t
00875 _dbus_userdb_test (const char *test_data_dir)
00876 {
00877 const DBusString *username;
00878 const DBusString *homedir;
00879
00880 if (!_dbus_username_from_current_process (&username))
00881 _dbus_assert_not_reached ("didn't get username");
00882
00883 if (!_dbus_homedir_from_current_process (&homedir))
00884 _dbus_assert_not_reached ("didn't get homedir");
00885
00886 printf (" Current user: %s homedir: %s\n",
00887 _dbus_string_get_const_data (username),
00888 _dbus_string_get_const_data (homedir));
00889
00890 return TRUE;
00891 }
00892 #endif