00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00024 #include "dbus-userdb.h"
00025 #include "dbus-hash.h"
00026 #include "dbus-test.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-protocol.h"
00029 #include "dbus-credentials.h"
00030 #include <string.h>
00031
00043 void
00044 _dbus_user_info_free_allocated (DBusUserInfo *info)
00045 {
00046 if (info == NULL)
00047 return;
00048
00049 _dbus_user_info_free (info);
00050 dbus_free (info);
00051 }
00052
00059 void
00060 _dbus_group_info_free_allocated (DBusGroupInfo *info)
00061 {
00062 if (info == NULL)
00063 return;
00064
00065 _dbus_group_info_free (info);
00066 dbus_free (info);
00067 }
00068
00074 void
00075 _dbus_user_info_free (DBusUserInfo *info)
00076 {
00077 dbus_free (info->group_ids);
00078 dbus_free (info->username);
00079 dbus_free (info->homedir);
00080 }
00081
00087 void
00088 _dbus_group_info_free (DBusGroupInfo *info)
00089 {
00090 dbus_free (info->groupname);
00091 }
00092
00101 dbus_bool_t
00102 _dbus_is_a_number (const DBusString *str,
00103 unsigned long *num)
00104 {
00105 int end;
00106
00107 if (_dbus_string_parse_uint (str, 0, num, &end) &&
00108 end == _dbus_string_get_length (str))
00109 return TRUE;
00110 else
00111 return FALSE;
00112 }
00113
00126 DBusUserInfo*
00127 _dbus_user_database_lookup (DBusUserDatabase *db,
00128 dbus_uid_t uid,
00129 const DBusString *username,
00130 DBusError *error)
00131 {
00132 DBusUserInfo *info;
00133
00134 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00135 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00136
00137
00138 if (uid == DBUS_UID_UNSET)
00139 {
00140 unsigned long n;
00141
00142 if (_dbus_is_a_number (username, &n))
00143 uid = n;
00144 }
00145
00146 #ifdef DBUS_ENABLE_USERDB_CACHE
00147 if (uid != DBUS_UID_UNSET)
00148 info = _dbus_hash_table_lookup_ulong (db->users, uid);
00149 else
00150 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00151
00152 if (info)
00153 {
00154 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00155 info->uid);
00156 return info;
00157 }
00158 else
00159 #else
00160 if (1)
00161 #endif
00162 {
00163 if (uid != DBUS_UID_UNSET)
00164 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00165 uid);
00166 else
00167 _dbus_verbose ("No cache for user \"%s\"\n",
00168 _dbus_string_get_const_data (username));
00169
00170 info = dbus_new0 (DBusUserInfo, 1);
00171 if (info == NULL)
00172 {
00173 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00174 return NULL;
00175 }
00176
00177 if (uid != DBUS_UID_UNSET)
00178 {
00179 if (!_dbus_user_info_fill_uid (info, uid, error))
00180 {
00181 _DBUS_ASSERT_ERROR_IS_SET (error);
00182 _dbus_user_info_free_allocated (info);
00183 return NULL;
00184 }
00185 }
00186 else
00187 {
00188 if (!_dbus_user_info_fill (info, username, error))
00189 {
00190 _DBUS_ASSERT_ERROR_IS_SET (error);
00191 _dbus_user_info_free_allocated (info);
00192 return NULL;
00193 }
00194 }
00195
00196
00197 uid = DBUS_UID_UNSET;
00198 username = NULL;
00199
00200
00201 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00202 {
00203 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00204 _dbus_user_info_free_allocated (info);
00205 return NULL;
00206 }
00207
00208 if (!_dbus_hash_table_insert_string (db->users_by_name,
00209 info->username,
00210 info))
00211 {
00212 _dbus_hash_table_remove_ulong (db->users, info->uid);
00213 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00214 return NULL;
00215 }
00216
00217 return info;
00218 }
00219 }
00220
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 = DBUS_ERROR_INIT;
00243 const DBusUserInfo *info;
00244
00245 system_db = _dbus_user_database_new ();
00246 if (system_db == NULL)
00247 return FALSE;
00248
00249 if (!_dbus_user_database_get_uid (system_db,
00250 _dbus_getuid (),
00251 &info,
00252 &error))
00253 {
00254 _dbus_user_database_unref (system_db);
00255 system_db = NULL;
00256
00257 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00258 {
00259 dbus_error_free (&error);
00260 return FALSE;
00261 }
00262 else
00263 {
00264
00265 _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00266 error.message);
00267 dbus_error_free (&error);
00268 return FALSE;
00269 }
00270 }
00271
00272 if (!_dbus_string_init (&process_username))
00273 {
00274 _dbus_user_database_unref (system_db);
00275 system_db = NULL;
00276 return FALSE;
00277 }
00278
00279 if (!_dbus_string_init (&process_homedir))
00280 {
00281 _dbus_string_free (&process_username);
00282 _dbus_user_database_unref (system_db);
00283 system_db = NULL;
00284 return FALSE;
00285 }
00286
00287 if (!_dbus_string_append (&process_username,
00288 info->username) ||
00289 !_dbus_string_append (&process_homedir,
00290 info->homedir) ||
00291 !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00292 {
00293 _dbus_string_free (&process_username);
00294 _dbus_string_free (&process_homedir);
00295 _dbus_user_database_unref (system_db);
00296 system_db = NULL;
00297 return FALSE;
00298 }
00299 }
00300
00301 return TRUE;
00302 }
00303
00307 void
00308 _dbus_user_database_lock_system (void)
00309 {
00310 _DBUS_LOCK (system_users);
00311 database_locked = TRUE;
00312 }
00313
00317 void
00318 _dbus_user_database_unlock_system (void)
00319 {
00320 database_locked = FALSE;
00321 _DBUS_UNLOCK (system_users);
00322 }
00323
00330 DBusUserDatabase*
00331 _dbus_user_database_get_system (void)
00332 {
00333 _dbus_assert (database_locked);
00334
00335 init_system_db ();
00336
00337 return system_db;
00338 }
00339
00343 void
00344 _dbus_user_database_flush_system (void)
00345 {
00346 _dbus_user_database_lock_system ();
00347
00348 _dbus_user_database_flush (system_db);
00349
00350 _dbus_user_database_unlock_system ();
00351 }
00352
00360 dbus_bool_t
00361 _dbus_username_from_current_process (const DBusString **username)
00362 {
00363 _dbus_user_database_lock_system ();
00364 if (!init_system_db ())
00365 {
00366 _dbus_user_database_unlock_system ();
00367 return FALSE;
00368 }
00369 *username = &process_username;
00370 _dbus_user_database_unlock_system ();
00371
00372 return TRUE;
00373 }
00374
00382 dbus_bool_t
00383 _dbus_homedir_from_current_process (const DBusString **homedir)
00384 {
00385 _dbus_user_database_lock_system ();
00386 if (!init_system_db ())
00387 {
00388 _dbus_user_database_unlock_system ();
00389 return FALSE;
00390 }
00391 *homedir = &process_homedir;
00392 _dbus_user_database_unlock_system ();
00393
00394 return TRUE;
00395 }
00396
00404 dbus_bool_t
00405 _dbus_homedir_from_username (const DBusString *username,
00406 DBusString *homedir)
00407 {
00408 DBusUserDatabase *db;
00409 const DBusUserInfo *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_username (db, username,
00420 &info, NULL))
00421 {
00422 _dbus_user_database_unlock_system ();
00423 return FALSE;
00424 }
00425
00426 if (!_dbus_string_append (homedir, info->homedir))
00427 {
00428 _dbus_user_database_unlock_system ();
00429 return FALSE;
00430 }
00431
00432 _dbus_user_database_unlock_system ();
00433 return TRUE;
00434 }
00435
00443 dbus_bool_t
00444 _dbus_homedir_from_uid (dbus_uid_t uid,
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_uid (db, uid,
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
00489 dbus_bool_t
00490 _dbus_credentials_add_from_user (DBusCredentials *credentials,
00491 const DBusString *username)
00492 {
00493 DBusUserDatabase *db;
00494 const DBusUserInfo *info;
00495
00496 _dbus_user_database_lock_system ();
00497
00498 db = _dbus_user_database_get_system ();
00499 if (db == NULL)
00500 {
00501 _dbus_user_database_unlock_system ();
00502 return FALSE;
00503 }
00504
00505 if (!_dbus_user_database_get_username (db, username,
00506 &info, NULL))
00507 {
00508 _dbus_user_database_unlock_system ();
00509 return FALSE;
00510 }
00511
00512 if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
00513 {
00514 _dbus_user_database_unlock_system ();
00515 return FALSE;
00516 }
00517
00518 _dbus_user_database_unlock_system ();
00519 return TRUE;
00520 }
00521
00527 DBusUserDatabase*
00528 _dbus_user_database_new (void)
00529 {
00530 DBusUserDatabase *db;
00531
00532 db = dbus_new0 (DBusUserDatabase, 1);
00533 if (db == NULL)
00534 return NULL;
00535
00536 db->refcount = 1;
00537
00538 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00539 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00540
00541 if (db->users == NULL)
00542 goto failed;
00543
00544 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00545 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00546
00547 if (db->groups == NULL)
00548 goto failed;
00549
00550 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00551 NULL, NULL);
00552 if (db->users_by_name == NULL)
00553 goto failed;
00554
00555 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00556 NULL, NULL);
00557 if (db->groups_by_name == NULL)
00558 goto failed;
00559
00560 return db;
00561
00562 failed:
00563 _dbus_user_database_unref (db);
00564 return NULL;
00565 }
00566
00570 void
00571 _dbus_user_database_flush (DBusUserDatabase *db)
00572 {
00573 _dbus_hash_table_remove_all(db->users_by_name);
00574 _dbus_hash_table_remove_all(db->groups_by_name);
00575 _dbus_hash_table_remove_all(db->users);
00576 _dbus_hash_table_remove_all(db->groups);
00577 }
00578
00579 #ifdef DBUS_BUILD_TESTS
00580
00585 DBusUserDatabase *
00586 _dbus_user_database_ref (DBusUserDatabase *db)
00587 {
00588 _dbus_assert (db->refcount > 0);
00589
00590 db->refcount += 1;
00591
00592 return db;
00593 }
00594 #endif
00595
00600 void
00601 _dbus_user_database_unref (DBusUserDatabase *db)
00602 {
00603 _dbus_assert (db->refcount > 0);
00604
00605 db->refcount -= 1;
00606 if (db->refcount == 0)
00607 {
00608 if (db->users)
00609 _dbus_hash_table_unref (db->users);
00610
00611 if (db->groups)
00612 _dbus_hash_table_unref (db->groups);
00613
00614 if (db->users_by_name)
00615 _dbus_hash_table_unref (db->users_by_name);
00616
00617 if (db->groups_by_name)
00618 _dbus_hash_table_unref (db->groups_by_name);
00619
00620 dbus_free (db);
00621 }
00622 }
00623
00634 dbus_bool_t
00635 _dbus_user_database_get_uid (DBusUserDatabase *db,
00636 dbus_uid_t uid,
00637 const DBusUserInfo **info,
00638 DBusError *error)
00639 {
00640 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00641 return *info != NULL;
00642 }
00643
00653 dbus_bool_t
00654 _dbus_user_database_get_username (DBusUserDatabase *db,
00655 const DBusString *username,
00656 const DBusUserInfo **info,
00657 DBusError *error)
00658 {
00659 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00660 return *info != NULL;
00661 }
00662
00665