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
00032 struct DBusUserDatabase
00033 {
00034 int refcount;
00036 DBusHashTable *users;
00037 DBusHashTable *groups;
00038 DBusHashTable *users_by_name;
00039 DBusHashTable *groups_by_name;
00040 };
00041
00042 static void
00043 free_user_info (void *data)
00044 {
00045 DBusUserInfo *info = data;
00046
00047 if (info == NULL)
00048 return;
00049
00050 _dbus_user_info_free (info);
00051 dbus_free (info);
00052 }
00053
00054 static void
00055 free_group_info (void *data)
00056 {
00057 DBusGroupInfo *info = data;
00058
00059 if (info == NULL)
00060 return;
00061
00062 _dbus_group_info_free (info);
00063 dbus_free (info);
00064 }
00065
00066 static DBusUserInfo*
00067 _dbus_user_database_lookup (DBusUserDatabase *db,
00068 dbus_uid_t uid,
00069 const DBusString *username,
00070 DBusError *error)
00071 {
00072 DBusUserInfo *info;
00073
00074 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00075 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00076
00077 if (uid != DBUS_UID_UNSET)
00078 info = _dbus_hash_table_lookup_ulong (db->users, uid);
00079 else
00080 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00081
00082 if (info)
00083 {
00084 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00085 uid);
00086 return info;
00087 }
00088 else
00089 {
00090 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00091 uid);
00092
00093 info = dbus_new0 (DBusUserInfo, 1);
00094 if (info == NULL)
00095 {
00096 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00097 return NULL;
00098 }
00099
00100 if (uid != DBUS_UID_UNSET)
00101 {
00102 if (!_dbus_user_info_fill_uid (info, uid, error))
00103 {
00104 _DBUS_ASSERT_ERROR_IS_SET (error);
00105 free_user_info (info);
00106 return NULL;
00107 }
00108 }
00109 else
00110 {
00111 if (!_dbus_user_info_fill (info, username, error))
00112 {
00113 _DBUS_ASSERT_ERROR_IS_SET (error);
00114 free_user_info (info);
00115 return NULL;
00116 }
00117 }
00118
00119
00120 uid = DBUS_UID_UNSET;
00121 username = NULL;
00122
00123
00124 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00125 {
00126 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00127 free_user_info (info);
00128 return NULL;
00129 }
00130
00131 if (!_dbus_hash_table_insert_string (db->users_by_name,
00132 info->username,
00133 info))
00134 {
00135 _dbus_hash_table_remove_ulong (db->users, info->uid);
00136 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00137 return NULL;
00138 }
00139
00140 return info;
00141 }
00142 }
00143
00144 static DBusGroupInfo*
00145 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00146 dbus_gid_t gid,
00147 const DBusString *groupname,
00148 DBusError *error)
00149 {
00150 DBusGroupInfo *info;
00151
00152 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00153
00154 if (gid != DBUS_GID_UNSET)
00155 info = _dbus_hash_table_lookup_ulong (db->groups, gid);
00156 else
00157 info = _dbus_hash_table_lookup_string (db->groups_by_name,
00158 _dbus_string_get_const_data (groupname));
00159 if (info)
00160 {
00161 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00162 gid);
00163 return info;
00164 }
00165 else
00166 {
00167 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00168 gid);
00169
00170 info = dbus_new0 (DBusGroupInfo, 1);
00171 if (info == NULL)
00172 {
00173 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00174 return NULL;
00175 }
00176
00177 if (!_dbus_group_info_fill_gid (info, gid, error))
00178 {
00179 _DBUS_ASSERT_ERROR_IS_SET (error);
00180 free_group_info (info);
00181 return NULL;
00182 }
00183
00184 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
00185 {
00186 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00187 free_group_info (info);
00188 return NULL;
00189 }
00190
00191
00192 if (!_dbus_hash_table_insert_string (db->groups_by_name,
00193 info->groupname,
00194 info))
00195 {
00196 _dbus_hash_table_remove_ulong (db->groups, info->gid);
00197 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00198 return NULL;
00199 }
00200
00201 return info;
00202 }
00203 }
00204
00205 _DBUS_DEFINE_GLOBAL_LOCK(system_users);
00206 static dbus_bool_t database_locked = FALSE;
00207 static DBusUserDatabase *system_db = NULL;
00208 static DBusString process_username;
00209 static DBusString process_homedir;
00210
00211 static void
00212 shutdown_system_db (void *data)
00213 {
00214 _dbus_user_database_unref (system_db);
00215 system_db = NULL;
00216 _dbus_string_free (&process_username);
00217 _dbus_string_free (&process_homedir);
00218 }
00219
00220 static dbus_bool_t
00221 init_system_db (void)
00222 {
00223 _dbus_assert (database_locked);
00224
00225 if (system_db == NULL)
00226 {
00227 DBusError error;
00228 const DBusUserInfo *info;
00229
00230 system_db = _dbus_user_database_new ();
00231 if (system_db == NULL)
00232 return FALSE;
00233
00234 dbus_error_init (&error);
00235
00236 if (!_dbus_user_database_get_uid (system_db,
00237 _dbus_getuid (),
00238 &info,
00239 &error))
00240 {
00241 _dbus_user_database_unref (system_db);
00242 system_db = NULL;
00243
00244 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00245 {
00246 dbus_error_free (&error);
00247 return FALSE;
00248 }
00249 else
00250 {
00251
00252 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00253 error.message);
00254 dbus_error_free (&error);
00255 return FALSE;
00256 }
00257 }
00258
00259 if (!_dbus_string_init (&process_username))
00260 {
00261 _dbus_user_database_unref (system_db);
00262 system_db = NULL;
00263 return FALSE;
00264 }
00265
00266 if (!_dbus_string_init (&process_homedir))
00267 {
00268 _dbus_string_free (&process_username);
00269 _dbus_user_database_unref (system_db);
00270 system_db = NULL;
00271 return FALSE;
00272 }
00273
00274 if (!_dbus_string_append (&process_username,
00275 info->username) ||
00276 !_dbus_string_append (&process_homedir,
00277 info->homedir) ||
00278 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00279 {
00280 _dbus_string_free (&process_username);
00281 _dbus_string_free (&process_homedir);
00282 _dbus_user_database_unref (system_db);
00283 system_db = NULL;
00284 return FALSE;
00285 }
00286 }
00287
00288 return TRUE;
00289 }
00290
00299 void
00300 _dbus_user_database_lock_system (void)
00301 {
00302 _DBUS_LOCK (system_users);
00303 database_locked = TRUE;
00304 }
00305
00309 void
00310 _dbus_user_database_unlock_system (void)
00311 {
00312 database_locked = FALSE;
00313 _DBUS_UNLOCK (system_users);
00314 }
00315
00322 DBusUserDatabase*
00323 _dbus_user_database_get_system (void)
00324 {
00325 _dbus_assert (database_locked);
00326
00327 init_system_db ();
00328
00329 return system_db;
00330 }
00331
00339 dbus_bool_t
00340 _dbus_username_from_current_process (const DBusString **username)
00341 {
00342 _dbus_user_database_lock_system ();
00343 if (!init_system_db ())
00344 {
00345 _dbus_user_database_unlock_system ();
00346 return FALSE;
00347 }
00348 *username = &process_username;
00349 _dbus_user_database_unlock_system ();
00350
00351 return TRUE;
00352 }
00353
00361 dbus_bool_t
00362 _dbus_homedir_from_current_process (const DBusString **homedir)
00363 {
00364 _dbus_user_database_lock_system ();
00365 if (!init_system_db ())
00366 {
00367 _dbus_user_database_unlock_system ();
00368 return FALSE;
00369 }
00370 *homedir = &process_homedir;
00371 _dbus_user_database_unlock_system ();
00372
00373 return TRUE;
00374 }
00375
00383 dbus_bool_t
00384 _dbus_get_user_id (const DBusString *username,
00385 dbus_uid_t *uid)
00386 {
00387 DBusCredentials creds;
00388
00389 if (!_dbus_credentials_from_username (username, &creds))
00390 return FALSE;
00391
00392 if (creds.uid == DBUS_UID_UNSET)
00393 return FALSE;
00394
00395 *uid = creds.uid;
00396
00397 return TRUE;
00398 }
00399
00407 dbus_bool_t
00408 _dbus_get_group_id (const DBusString *groupname,
00409 dbus_gid_t *gid)
00410 {
00411 DBusUserDatabase *db;
00412 const DBusGroupInfo *info;
00413 _dbus_user_database_lock_system ();
00414
00415 db = _dbus_user_database_get_system ();
00416 if (db == NULL)
00417 {
00418 _dbus_user_database_unlock_system ();
00419 return FALSE;
00420 }
00421
00422 if (!_dbus_user_database_get_groupname (db, groupname,
00423 &info, NULL))
00424 {
00425 _dbus_user_database_unlock_system ();
00426 return FALSE;
00427 }
00428
00429 *gid = info->gid;
00430
00431 _dbus_user_database_unlock_system ();
00432 return TRUE;
00433 }
00434
00442 dbus_bool_t
00443 _dbus_homedir_from_username (const DBusString *username,
00444 DBusString *homedir)
00445 {
00446 DBusUserDatabase *db;
00447 const DBusUserInfo *info;
00448 _dbus_user_database_lock_system ();
00449
00450 db = _dbus_user_database_get_system ();
00451 if (db == NULL)
00452 {
00453 _dbus_user_database_unlock_system ();
00454 return FALSE;
00455 }
00456
00457 if (!_dbus_user_database_get_username (db, username,
00458 &info, NULL))
00459 {
00460 _dbus_user_database_unlock_system ();
00461 return FALSE;
00462 }
00463
00464 if (!_dbus_string_append (homedir, info->homedir))
00465 {
00466 _dbus_user_database_unlock_system ();
00467 return FALSE;
00468 }
00469
00470 _dbus_user_database_unlock_system ();
00471 return TRUE;
00472 }
00473
00481 dbus_bool_t
00482 _dbus_uid_from_string (const DBusString *uid_str,
00483 dbus_uid_t *uid)
00484 {
00485 int end;
00486 long val;
00487
00488 if (_dbus_string_get_length (uid_str) == 0)
00489 {
00490 _dbus_verbose ("UID string was zero length\n");
00491 return FALSE;
00492 }
00493
00494 val = -1;
00495 end = 0;
00496 if (!_dbus_string_parse_int (uid_str, 0, &val,
00497 &end))
00498 {
00499 _dbus_verbose ("could not parse string as a UID\n");
00500 return FALSE;
00501 }
00502
00503 if (end != _dbus_string_get_length (uid_str))
00504 {
00505 _dbus_verbose ("string contained trailing stuff after UID\n");
00506 return FALSE;
00507 }
00508
00509 *uid = val;
00510
00511 return TRUE;
00512 }
00513
00521 dbus_bool_t
00522 _dbus_credentials_from_username (const DBusString *username,
00523 DBusCredentials *credentials)
00524 {
00525 DBusUserDatabase *db;
00526 const DBusUserInfo *info;
00527 _dbus_user_database_lock_system ();
00528
00529 db = _dbus_user_database_get_system ();
00530 if (db == NULL)
00531 {
00532 _dbus_user_database_unlock_system ();
00533 return FALSE;
00534 }
00535
00536 if (!_dbus_user_database_get_username (db, username,
00537 &info, NULL))
00538 {
00539 _dbus_user_database_unlock_system ();
00540 return FALSE;
00541 }
00542
00543 credentials->pid = DBUS_PID_UNSET;
00544 credentials->uid = info->uid;
00545 credentials->gid = info->primary_gid;
00546
00547 _dbus_user_database_unlock_system ();
00548 return TRUE;
00549 }
00550
00558 dbus_bool_t
00559 _dbus_credentials_from_uid (dbus_uid_t uid,
00560 DBusCredentials *credentials)
00561 {
00562 DBusUserDatabase *db;
00563 const DBusUserInfo *info;
00564 _dbus_user_database_lock_system ();
00565
00566 db = _dbus_user_database_get_system ();
00567 if (db == NULL)
00568 {
00569 _dbus_user_database_unlock_system ();
00570 return FALSE;
00571 }
00572
00573 if (!_dbus_user_database_get_uid (db, uid,
00574 &info, NULL))
00575 {
00576 _dbus_user_database_unlock_system ();
00577 return FALSE;
00578 }
00579
00580 _dbus_assert (info->uid == uid);
00581
00582 credentials->pid = DBUS_PID_UNSET;
00583 credentials->uid = info->uid;
00584 credentials->gid = info->primary_gid;
00585
00586 _dbus_user_database_unlock_system ();
00587 return TRUE;
00588 }
00589
00595 DBusUserDatabase*
00596 _dbus_user_database_new (void)
00597 {
00598 DBusUserDatabase *db;
00599
00600 db = dbus_new0 (DBusUserDatabase, 1);
00601 if (db == NULL)
00602 return NULL;
00603
00604 db->refcount = 1;
00605
00606 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00607 NULL, free_user_info);
00608
00609 if (db->users == NULL)
00610 goto failed;
00611
00612 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00613 NULL, free_group_info);
00614
00615 if (db->groups == NULL)
00616 goto failed;
00617
00618 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00619 NULL, NULL);
00620 if (db->users_by_name == NULL)
00621 goto failed;
00622
00623 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00624 NULL, NULL);
00625 if (db->groups_by_name == NULL)
00626 goto failed;
00627
00628 return db;
00629
00630 failed:
00631 _dbus_user_database_unref (db);
00632 return NULL;
00633 }
00634
00640 DBusUserDatabase *
00641 _dbus_user_database_ref (DBusUserDatabase *db)
00642 {
00643 _dbus_assert (db->refcount > 0);
00644
00645 db->refcount += 1;
00646
00647 return db;
00648 }
00649
00654 void
00655 _dbus_user_database_unref (DBusUserDatabase *db)
00656 {
00657 _dbus_assert (db->refcount > 0);
00658
00659 db->refcount -= 1;
00660 if (db->refcount == 0)
00661 {
00662 if (db->users)
00663 _dbus_hash_table_unref (db->users);
00664
00665 if (db->groups)
00666 _dbus_hash_table_unref (db->groups);
00667
00668 if (db->users_by_name)
00669 _dbus_hash_table_unref (db->users_by_name);
00670
00671 if (db->groups_by_name)
00672 _dbus_hash_table_unref (db->groups_by_name);
00673
00674 dbus_free (db);
00675 }
00676 }
00677
00691 dbus_bool_t
00692 _dbus_user_database_get_groups (DBusUserDatabase *db,
00693 dbus_uid_t uid,
00694 dbus_gid_t **group_ids,
00695 int *n_group_ids,
00696 DBusError *error)
00697 {
00698 DBusUserInfo *info;
00699
00700 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00701
00702 *group_ids = NULL;
00703 *n_group_ids = 0;
00704
00705 info = _dbus_user_database_lookup (db, uid, NULL, error);
00706 if (info == NULL)
00707 {
00708 _DBUS_ASSERT_ERROR_IS_SET (error);
00709 return FALSE;
00710 }
00711
00712 if (info->n_group_ids > 0)
00713 {
00714 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00715 if (*group_ids == NULL)
00716 {
00717 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00718 return FALSE;
00719 }
00720
00721 *n_group_ids = info->n_group_ids;
00722
00723 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00724 }
00725
00726 return TRUE;
00727 }
00728
00739 dbus_bool_t
00740 _dbus_user_database_get_uid (DBusUserDatabase *db,
00741 dbus_uid_t uid,
00742 const DBusUserInfo **info,
00743 DBusError *error)
00744 {
00745 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00746 return *info != NULL;
00747 }
00748
00759 dbus_bool_t
00760 _dbus_user_database_get_gid (DBusUserDatabase *db,
00761 dbus_gid_t gid,
00762 const DBusGroupInfo **info,
00763 DBusError *error)
00764 {
00765 *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00766 return *info != NULL;
00767 }
00768
00778 dbus_bool_t
00779 _dbus_user_database_get_username (DBusUserDatabase *db,
00780 const DBusString *username,
00781 const DBusUserInfo **info,
00782 DBusError *error)
00783 {
00784 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00785 return *info != NULL;
00786 }
00787
00798 dbus_bool_t
00799 _dbus_user_database_get_groupname (DBusUserDatabase *db,
00800 const DBusString *groupname,
00801 const DBusGroupInfo **info,
00802 DBusError *error)
00803 {
00804 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00805 return *info != NULL;
00806 }
00807
00810 #ifdef DBUS_BUILD_TESTS
00811 #include <stdio.h>
00812
00818 dbus_bool_t
00819 _dbus_userdb_test (const char *test_data_dir)
00820 {
00821 const DBusString *username;
00822 const DBusString *homedir;
00823
00824 if (!_dbus_username_from_current_process (&username))
00825 _dbus_assert_not_reached ("didn't get username");
00826
00827 if (!_dbus_homedir_from_current_process (&homedir))
00828 _dbus_assert_not_reached ("didn't get homedir");
00829
00830 printf (" Current user: %s homedir: %s\n",
00831 _dbus_string_get_const_data (username),
00832 _dbus_string_get_const_data (homedir));
00833
00834 return TRUE;
00835 }
00836 #endif