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