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 if (!_dbus_group_info_fill_gid (info, gid, error))
00180 {
00181 _DBUS_ASSERT_ERROR_IS_SET (error);
00182 free_group_info (info);
00183 return NULL;
00184 }
00185
00186 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
00187 {
00188 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00189 free_group_info (info);
00190 return NULL;
00191 }
00192
00193
00194 if (!_dbus_hash_table_insert_string (db->groups_by_name,
00195 info->groupname,
00196 info))
00197 {
00198 _dbus_hash_table_remove_ulong (db->groups, info->gid);
00199 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00200 return NULL;
00201 }
00202
00203 return info;
00204 }
00205 }
00206
00207 _DBUS_DEFINE_GLOBAL_LOCK(system_users);
00208 static dbus_bool_t database_locked = FALSE;
00209 static DBusUserDatabase *system_db = NULL;
00210 static DBusString process_username;
00211 static DBusString process_homedir;
00212
00213 static void
00214 shutdown_system_db (void *data)
00215 {
00216 _dbus_user_database_unref (system_db);
00217 system_db = NULL;
00218 _dbus_string_free (&process_username);
00219 _dbus_string_free (&process_homedir);
00220 }
00221
00222 static dbus_bool_t
00223 init_system_db (void)
00224 {
00225 _dbus_assert (database_locked);
00226
00227 if (system_db == NULL)
00228 {
00229 DBusError error;
00230 const DBusUserInfo *info;
00231
00232 system_db = _dbus_user_database_new ();
00233 if (system_db == NULL)
00234 return FALSE;
00235
00236 dbus_error_init (&error);
00237
00238 if (!_dbus_user_database_get_uid (system_db,
00239 _dbus_getuid (),
00240 &info,
00241 &error))
00242 {
00243 _dbus_user_database_unref (system_db);
00244 system_db = NULL;
00245
00246 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00247 {
00248 dbus_error_free (&error);
00249 return FALSE;
00250 }
00251 else
00252 {
00253
00254 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00255 error.message);
00256 dbus_error_free (&error);
00257 return FALSE;
00258 }
00259 }
00260
00261 if (!_dbus_string_init (&process_username))
00262 {
00263 _dbus_user_database_unref (system_db);
00264 system_db = NULL;
00265 return FALSE;
00266 }
00267
00268 if (!_dbus_string_init (&process_homedir))
00269 {
00270 _dbus_string_free (&process_username);
00271 _dbus_user_database_unref (system_db);
00272 system_db = NULL;
00273 return FALSE;
00274 }
00275
00276 if (!_dbus_string_append (&process_username,
00277 info->username) ||
00278 !_dbus_string_append (&process_homedir,
00279 info->homedir) ||
00280 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00281 {
00282 _dbus_string_free (&process_username);
00283 _dbus_string_free (&process_homedir);
00284 _dbus_user_database_unref (system_db);
00285 system_db = NULL;
00286 return FALSE;
00287 }
00288 }
00289
00290 return TRUE;
00291 }
00292
00301 void
00302 _dbus_user_database_lock_system (void)
00303 {
00304 _DBUS_LOCK (system_users);
00305 database_locked = TRUE;
00306 }
00307
00311 void
00312 _dbus_user_database_unlock_system (void)
00313 {
00314 database_locked = FALSE;
00315 _DBUS_UNLOCK (system_users);
00316 }
00317
00324 DBusUserDatabase*
00325 _dbus_user_database_get_system (void)
00326 {
00327 _dbus_assert (database_locked);
00328
00329 init_system_db ();
00330
00331 return system_db;
00332 }
00333
00341 dbus_bool_t
00342 _dbus_username_from_current_process (const DBusString **username)
00343 {
00344 _dbus_user_database_lock_system ();
00345 if (!init_system_db ())
00346 {
00347 _dbus_user_database_unlock_system ();
00348 return FALSE;
00349 }
00350 *username = &process_username;
00351 _dbus_user_database_unlock_system ();
00352
00353 return TRUE;
00354 }
00355
00363 dbus_bool_t
00364 _dbus_homedir_from_current_process (const DBusString **homedir)
00365 {
00366 _dbus_user_database_lock_system ();
00367 if (!init_system_db ())
00368 {
00369 _dbus_user_database_unlock_system ();
00370 return FALSE;
00371 }
00372 *homedir = &process_homedir;
00373 _dbus_user_database_unlock_system ();
00374
00375 return TRUE;
00376 }
00377
00385 dbus_bool_t
00386 _dbus_get_user_id (const DBusString *username,
00387 dbus_uid_t *uid)
00388 {
00389 DBusCredentials creds;
00390
00391 if (!_dbus_credentials_from_username (username, &creds))
00392 return FALSE;
00393
00394 if (creds.uid == DBUS_UID_UNSET)
00395 return FALSE;
00396
00397 *uid = creds.uid;
00398
00399 return TRUE;
00400 }
00401
00409 dbus_bool_t
00410 _dbus_is_console_user (dbus_uid_t uid,
00411 DBusError *error)
00412 {
00413
00414 DBusUserDatabase *db;
00415 const DBusUserInfo *info;
00416 dbus_bool_t result = FALSE;
00417
00418 _dbus_user_database_lock_system ();
00419
00420 db = _dbus_user_database_get_system ();
00421 if (db == NULL)
00422 {
00423 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
00424 _dbus_user_database_unlock_system ();
00425 return FALSE;
00426 }
00427
00428 info = _dbus_user_database_lookup (db, uid, NULL, error);
00429
00430 if (info == NULL)
00431 {
00432 _dbus_user_database_unlock_system ();
00433 return FALSE;
00434 }
00435
00436 result = _dbus_user_at_console (info->username, error);
00437
00438 _dbus_user_database_unlock_system ();
00439
00440 return result;
00441 }
00442
00450 dbus_bool_t
00451 _dbus_get_group_id (const DBusString *groupname,
00452 dbus_gid_t *gid)
00453 {
00454 DBusUserDatabase *db;
00455 const DBusGroupInfo *info;
00456 _dbus_user_database_lock_system ();
00457
00458 db = _dbus_user_database_get_system ();
00459 if (db == NULL)
00460 {
00461 _dbus_user_database_unlock_system ();
00462 return FALSE;
00463 }
00464
00465 if (!_dbus_user_database_get_groupname (db, groupname,
00466 &info, NULL))
00467 {
00468 _dbus_user_database_unlock_system ();
00469 return FALSE;
00470 }
00471
00472 *gid = info->gid;
00473
00474 _dbus_user_database_unlock_system ();
00475 return TRUE;
00476 }
00477
00485 dbus_bool_t
00486 _dbus_homedir_from_username (const DBusString *username,
00487 DBusString *homedir)
00488 {
00489 DBusUserDatabase *db;
00490 const DBusUserInfo *info;
00491 _dbus_user_database_lock_system ();
00492
00493 db = _dbus_user_database_get_system ();
00494 if (db == NULL)
00495 {
00496 _dbus_user_database_unlock_system ();
00497 return FALSE;
00498 }
00499
00500 if (!_dbus_user_database_get_username (db, username,
00501 &info, NULL))
00502 {
00503 _dbus_user_database_unlock_system ();
00504 return FALSE;
00505 }
00506
00507 if (!_dbus_string_append (homedir, info->homedir))
00508 {
00509 _dbus_user_database_unlock_system ();
00510 return FALSE;
00511 }
00512
00513 _dbus_user_database_unlock_system ();
00514 return TRUE;
00515 }
00516
00524 dbus_bool_t
00525 _dbus_uid_from_string (const DBusString *uid_str,
00526 dbus_uid_t *uid)
00527 {
00528 int end;
00529 long val;
00530
00531 if (_dbus_string_get_length (uid_str) == 0)
00532 {
00533 _dbus_verbose ("UID string was zero length\n");
00534 return FALSE;
00535 }
00536
00537 val = -1;
00538 end = 0;
00539 if (!_dbus_string_parse_int (uid_str, 0, &val,
00540 &end))
00541 {
00542 _dbus_verbose ("could not parse string as a UID\n");
00543 return FALSE;
00544 }
00545
00546 if (end != _dbus_string_get_length (uid_str))
00547 {
00548 _dbus_verbose ("string contained trailing stuff after UID\n");
00549 return FALSE;
00550 }
00551
00552 *uid = val;
00553
00554 return TRUE;
00555 }
00556
00564 dbus_bool_t
00565 _dbus_credentials_from_username (const DBusString *username,
00566 DBusCredentials *credentials)
00567 {
00568 DBusUserDatabase *db;
00569 const DBusUserInfo *info;
00570 _dbus_user_database_lock_system ();
00571
00572 db = _dbus_user_database_get_system ();
00573 if (db == NULL)
00574 {
00575 _dbus_user_database_unlock_system ();
00576 return FALSE;
00577 }
00578
00579 if (!_dbus_user_database_get_username (db, username,
00580 &info, NULL))
00581 {
00582 _dbus_user_database_unlock_system ();
00583 return FALSE;
00584 }
00585
00586 credentials->pid = DBUS_PID_UNSET;
00587 credentials->uid = info->uid;
00588 credentials->gid = info->primary_gid;
00589
00590 _dbus_user_database_unlock_system ();
00591 return TRUE;
00592 }
00593
00601 dbus_bool_t
00602 _dbus_credentials_from_uid (dbus_uid_t uid,
00603 DBusCredentials *credentials)
00604 {
00605 DBusUserDatabase *db;
00606 const DBusUserInfo *info;
00607 _dbus_user_database_lock_system ();
00608
00609 db = _dbus_user_database_get_system ();
00610 if (db == NULL)
00611 {
00612 _dbus_user_database_unlock_system ();
00613 return FALSE;
00614 }
00615
00616 if (!_dbus_user_database_get_uid (db, uid,
00617 &info, NULL))
00618 {
00619 _dbus_user_database_unlock_system ();
00620 return FALSE;
00621 }
00622
00623 _dbus_assert (info->uid == uid);
00624
00625 credentials->pid = DBUS_PID_UNSET;
00626 credentials->uid = info->uid;
00627 credentials->gid = info->primary_gid;
00628
00629 _dbus_user_database_unlock_system ();
00630 return TRUE;
00631 }
00632
00638 DBusUserDatabase*
00639 _dbus_user_database_new (void)
00640 {
00641 DBusUserDatabase *db;
00642
00643 db = dbus_new0 (DBusUserDatabase, 1);
00644 if (db == NULL)
00645 return NULL;
00646
00647 db->refcount = 1;
00648
00649 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00650 NULL, free_user_info);
00651
00652 if (db->users == NULL)
00653 goto failed;
00654
00655 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00656 NULL, free_group_info);
00657
00658 if (db->groups == NULL)
00659 goto failed;
00660
00661 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00662 NULL, NULL);
00663 if (db->users_by_name == NULL)
00664 goto failed;
00665
00666 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00667 NULL, NULL);
00668 if (db->groups_by_name == NULL)
00669 goto failed;
00670
00671 return db;
00672
00673 failed:
00674 _dbus_user_database_unref (db);
00675 return NULL;
00676 }
00677
00683 DBusUserDatabase *
00684 _dbus_user_database_ref (DBusUserDatabase *db)
00685 {
00686 _dbus_assert (db->refcount > 0);
00687
00688 db->refcount += 1;
00689
00690 return db;
00691 }
00692
00697 void
00698 _dbus_user_database_unref (DBusUserDatabase *db)
00699 {
00700 _dbus_assert (db->refcount > 0);
00701
00702 db->refcount -= 1;
00703 if (db->refcount == 0)
00704 {
00705 if (db->users)
00706 _dbus_hash_table_unref (db->users);
00707
00708 if (db->groups)
00709 _dbus_hash_table_unref (db->groups);
00710
00711 if (db->users_by_name)
00712 _dbus_hash_table_unref (db->users_by_name);
00713
00714 if (db->groups_by_name)
00715 _dbus_hash_table_unref (db->groups_by_name);
00716
00717 dbus_free (db);
00718 }
00719 }
00720
00734 dbus_bool_t
00735 _dbus_user_database_get_groups (DBusUserDatabase *db,
00736 dbus_uid_t uid,
00737 dbus_gid_t **group_ids,
00738 int *n_group_ids,
00739 DBusError *error)
00740 {
00741 DBusUserInfo *info;
00742
00743 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00744
00745 *group_ids = NULL;
00746 *n_group_ids = 0;
00747
00748 info = _dbus_user_database_lookup (db, uid, NULL, error);
00749 if (info == NULL)
00750 {
00751 _DBUS_ASSERT_ERROR_IS_SET (error);
00752 return FALSE;
00753 }
00754
00755 if (info->n_group_ids > 0)
00756 {
00757 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00758 if (*group_ids == NULL)
00759 {
00760 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00761 return FALSE;
00762 }
00763
00764 *n_group_ids = info->n_group_ids;
00765
00766 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00767 }
00768
00769 return TRUE;
00770 }
00771
00782 dbus_bool_t
00783 _dbus_user_database_get_uid (DBusUserDatabase *db,
00784 dbus_uid_t uid,
00785 const DBusUserInfo **info,
00786 DBusError *error)
00787 {
00788 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00789 return *info != NULL;
00790 }
00791
00802 dbus_bool_t
00803 _dbus_user_database_get_gid (DBusUserDatabase *db,
00804 dbus_gid_t gid,
00805 const DBusGroupInfo **info,
00806 DBusError *error)
00807 {
00808 *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00809 return *info != NULL;
00810 }
00811
00821 dbus_bool_t
00822 _dbus_user_database_get_username (DBusUserDatabase *db,
00823 const DBusString *username,
00824 const DBusUserInfo **info,
00825 DBusError *error)
00826 {
00827 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00828 return *info != NULL;
00829 }
00830
00841 dbus_bool_t
00842 _dbus_user_database_get_groupname (DBusUserDatabase *db,
00843 const DBusString *groupname,
00844 const DBusGroupInfo **info,
00845 DBusError *error)
00846 {
00847 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00848 return *info != NULL;
00849 }
00850
00853 #ifdef DBUS_BUILD_TESTS
00854 #include <stdio.h>
00855
00861 dbus_bool_t
00862 _dbus_userdb_test (const char *test_data_dir)
00863 {
00864 const DBusString *username;
00865 const DBusString *homedir;
00866
00867 if (!_dbus_username_from_current_process (&username))
00868 _dbus_assert_not_reached ("didn't get username");
00869
00870 if (!_dbus_homedir_from_current_process (&homedir))
00871 _dbus_assert_not_reached ("didn't get homedir");
00872
00873 printf (" Current user: %s homedir: %s\n",
00874 _dbus_string_get_const_data (username),
00875 _dbus_string_get_const_data (homedir));
00876
00877 return TRUE;
00878 }
00879 #endif