00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <config.h>
00024 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00025 #include "dbus-userdb.h"
00026 #include "dbus-hash.h"
00027 #include "dbus-test.h"
00028 #include "dbus-internals.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-credentials.h"
00031 #include <string.h>
00032
00044 void
00045 _dbus_user_info_free_allocated (DBusUserInfo *info)
00046 {
00047 if (info == NULL)
00048 return;
00049
00050 _dbus_user_info_free (info);
00051 dbus_free (info);
00052 }
00053
00060 void
00061 _dbus_group_info_free_allocated (DBusGroupInfo *info)
00062 {
00063 if (info == NULL)
00064 return;
00065
00066 _dbus_group_info_free (info);
00067 dbus_free (info);
00068 }
00069
00075 void
00076 _dbus_user_info_free (DBusUserInfo *info)
00077 {
00078 dbus_free (info->group_ids);
00079 dbus_free (info->username);
00080 dbus_free (info->homedir);
00081 }
00082
00088 void
00089 _dbus_group_info_free (DBusGroupInfo *info)
00090 {
00091 dbus_free (info->groupname);
00092 }
00093
00102 dbus_bool_t
00103 _dbus_is_a_number (const DBusString *str,
00104 unsigned long *num)
00105 {
00106 int end;
00107
00108 if (_dbus_string_parse_uint (str, 0, num, &end) &&
00109 end == _dbus_string_get_length (str))
00110 return TRUE;
00111 else
00112 return FALSE;
00113 }
00114
00127 DBusUserInfo*
00128 _dbus_user_database_lookup (DBusUserDatabase *db,
00129 dbus_uid_t uid,
00130 const DBusString *username,
00131 DBusError *error)
00132 {
00133 DBusUserInfo *info;
00134
00135 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00136 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00137
00138
00139 if (uid == DBUS_UID_UNSET)
00140 {
00141 unsigned long n;
00142
00143 if (_dbus_is_a_number (username, &n))
00144 uid = n;
00145 }
00146
00147 #ifdef DBUS_ENABLE_USERDB_CACHE
00148 if (uid != DBUS_UID_UNSET)
00149 info = _dbus_hash_table_lookup_uintptr (db->users, uid);
00150 else
00151 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00152
00153 if (info)
00154 {
00155 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00156 info->uid);
00157 return info;
00158 }
00159 else
00160 #else
00161 if (1)
00162 #endif
00163 {
00164 if (uid != DBUS_UID_UNSET)
00165 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00166 uid);
00167 else
00168 _dbus_verbose ("No cache for user \"%s\"\n",
00169 _dbus_string_get_const_data (username));
00170
00171 info = dbus_new0 (DBusUserInfo, 1);
00172 if (info == NULL)
00173 {
00174 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00175 return NULL;
00176 }
00177
00178 if (uid != DBUS_UID_UNSET)
00179 {
00180 if (!_dbus_user_info_fill_uid (info, uid, error))
00181 {
00182 _DBUS_ASSERT_ERROR_IS_SET (error);
00183 _dbus_user_info_free_allocated (info);
00184 return NULL;
00185 }
00186 }
00187 else
00188 {
00189 if (!_dbus_user_info_fill (info, username, error))
00190 {
00191 _DBUS_ASSERT_ERROR_IS_SET (error);
00192 _dbus_user_info_free_allocated (info);
00193 return NULL;
00194 }
00195 }
00196
00197
00198 uid = DBUS_UID_UNSET;
00199 username = NULL;
00200
00201
00202 if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info))
00203 {
00204 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00205 _dbus_user_info_free_allocated (info);
00206 return NULL;
00207 }
00208
00209 if (!_dbus_hash_table_insert_string (db->users_by_name,
00210 info->username,
00211 info))
00212 {
00213 _dbus_hash_table_remove_uintptr (db->users, info->uid);
00214 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00215 return NULL;
00216 }
00217
00218 return info;
00219 }
00220 }
00221
00222 static dbus_bool_t database_locked = FALSE;
00223 static DBusUserDatabase *system_db = NULL;
00224 static DBusString process_username;
00225 static DBusString process_homedir;
00226
00227 static void
00228 shutdown_system_db (void *data)
00229 {
00230 if (system_db != NULL)
00231 _dbus_user_database_unref (system_db);
00232 system_db = NULL;
00233 _dbus_string_free (&process_username);
00234 _dbus_string_free (&process_homedir);
00235 }
00236
00237 static dbus_bool_t
00238 init_system_db (void)
00239 {
00240 _dbus_assert (database_locked);
00241
00242 if (system_db == NULL)
00243 {
00244 DBusError error = DBUS_ERROR_INIT;
00245 const DBusUserInfo *info;
00246
00247 system_db = _dbus_user_database_new ();
00248 if (system_db == NULL)
00249 return FALSE;
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
00309 void
00310 _dbus_user_database_lock_system (void)
00311 {
00312 _DBUS_LOCK (system_users);
00313 database_locked = TRUE;
00314 }
00315
00319 void
00320 _dbus_user_database_unlock_system (void)
00321 {
00322 database_locked = FALSE;
00323 _DBUS_UNLOCK (system_users);
00324 }
00325
00332 DBusUserDatabase*
00333 _dbus_user_database_get_system (void)
00334 {
00335 _dbus_assert (database_locked);
00336
00337 init_system_db ();
00338
00339 return system_db;
00340 }
00341
00345 void
00346 _dbus_user_database_flush_system (void)
00347 {
00348 _dbus_user_database_lock_system ();
00349
00350 if (system_db != NULL)
00351 _dbus_user_database_flush (system_db);
00352
00353 _dbus_user_database_unlock_system ();
00354 }
00355
00363 dbus_bool_t
00364 _dbus_username_from_current_process (const DBusString **username)
00365 {
00366 _dbus_user_database_lock_system ();
00367 if (!init_system_db ())
00368 {
00369 _dbus_user_database_unlock_system ();
00370 return FALSE;
00371 }
00372 *username = &process_username;
00373 _dbus_user_database_unlock_system ();
00374
00375 return TRUE;
00376 }
00377
00385 dbus_bool_t
00386 _dbus_homedir_from_current_process (const DBusString **homedir)
00387 {
00388 _dbus_user_database_lock_system ();
00389 if (!init_system_db ())
00390 {
00391 _dbus_user_database_unlock_system ();
00392 return FALSE;
00393 }
00394 *homedir = &process_homedir;
00395 _dbus_user_database_unlock_system ();
00396
00397 return TRUE;
00398 }
00399
00407 dbus_bool_t
00408 _dbus_homedir_from_username (const DBusString *username,
00409 DBusString *homedir)
00410 {
00411 DBusUserDatabase *db;
00412 const DBusUserInfo *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_username (db, username,
00423 &info, NULL))
00424 {
00425 _dbus_user_database_unlock_system ();
00426 return FALSE;
00427 }
00428
00429 if (!_dbus_string_append (homedir, info->homedir))
00430 {
00431 _dbus_user_database_unlock_system ();
00432 return FALSE;
00433 }
00434
00435 _dbus_user_database_unlock_system ();
00436 return TRUE;
00437 }
00438
00446 dbus_bool_t
00447 _dbus_homedir_from_uid (dbus_uid_t uid,
00448 DBusString *homedir)
00449 {
00450 DBusUserDatabase *db;
00451 const DBusUserInfo *info;
00452 _dbus_user_database_lock_system ();
00453
00454 db = _dbus_user_database_get_system ();
00455 if (db == NULL)
00456 {
00457 _dbus_user_database_unlock_system ();
00458 return FALSE;
00459 }
00460
00461 if (!_dbus_user_database_get_uid (db, uid,
00462 &info, NULL))
00463 {
00464 _dbus_user_database_unlock_system ();
00465 return FALSE;
00466 }
00467
00468 if (!_dbus_string_append (homedir, info->homedir))
00469 {
00470 _dbus_user_database_unlock_system ();
00471 return FALSE;
00472 }
00473
00474 _dbus_user_database_unlock_system ();
00475 return TRUE;
00476 }
00477
00492 dbus_bool_t
00493 _dbus_credentials_add_from_user (DBusCredentials *credentials,
00494 const DBusString *username)
00495 {
00496 DBusUserDatabase *db;
00497 const DBusUserInfo *info;
00498
00499 _dbus_user_database_lock_system ();
00500
00501 db = _dbus_user_database_get_system ();
00502 if (db == NULL)
00503 {
00504 _dbus_user_database_unlock_system ();
00505 return FALSE;
00506 }
00507
00508 if (!_dbus_user_database_get_username (db, username,
00509 &info, NULL))
00510 {
00511 _dbus_user_database_unlock_system ();
00512 return FALSE;
00513 }
00514
00515 if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
00516 {
00517 _dbus_user_database_unlock_system ();
00518 return FALSE;
00519 }
00520
00521 _dbus_user_database_unlock_system ();
00522 return TRUE;
00523 }
00524
00530 DBusUserDatabase*
00531 _dbus_user_database_new (void)
00532 {
00533 DBusUserDatabase *db;
00534
00535 db = dbus_new0 (DBusUserDatabase, 1);
00536 if (db == NULL)
00537 return NULL;
00538
00539 db->refcount = 1;
00540
00541 db->users = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
00542 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00543
00544 if (db->users == NULL)
00545 goto failed;
00546
00547 db->groups = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
00548 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00549
00550 if (db->groups == NULL)
00551 goto failed;
00552
00553 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00554 NULL, NULL);
00555 if (db->users_by_name == NULL)
00556 goto failed;
00557
00558 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00559 NULL, NULL);
00560 if (db->groups_by_name == NULL)
00561 goto failed;
00562
00563 return db;
00564
00565 failed:
00566 _dbus_user_database_unref (db);
00567 return NULL;
00568 }
00569
00573 void
00574 _dbus_user_database_flush (DBusUserDatabase *db)
00575 {
00576 _dbus_hash_table_remove_all(db->users_by_name);
00577 _dbus_hash_table_remove_all(db->groups_by_name);
00578 _dbus_hash_table_remove_all(db->users);
00579 _dbus_hash_table_remove_all(db->groups);
00580 }
00581
00582 #ifdef DBUS_BUILD_TESTS
00583
00588 DBusUserDatabase *
00589 _dbus_user_database_ref (DBusUserDatabase *db)
00590 {
00591 _dbus_assert (db->refcount > 0);
00592
00593 db->refcount += 1;
00594
00595 return db;
00596 }
00597 #endif
00598
00603 void
00604 _dbus_user_database_unref (DBusUserDatabase *db)
00605 {
00606 _dbus_assert (db->refcount > 0);
00607
00608 db->refcount -= 1;
00609 if (db->refcount == 0)
00610 {
00611 if (db->users)
00612 _dbus_hash_table_unref (db->users);
00613
00614 if (db->groups)
00615 _dbus_hash_table_unref (db->groups);
00616
00617 if (db->users_by_name)
00618 _dbus_hash_table_unref (db->users_by_name);
00619
00620 if (db->groups_by_name)
00621 _dbus_hash_table_unref (db->groups_by_name);
00622
00623 dbus_free (db);
00624 }
00625 }
00626
00637 dbus_bool_t
00638 _dbus_user_database_get_uid (DBusUserDatabase *db,
00639 dbus_uid_t uid,
00640 const DBusUserInfo **info,
00641 DBusError *error)
00642 {
00643 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00644 return *info != NULL;
00645 }
00646
00656 dbus_bool_t
00657 _dbus_user_database_get_username (DBusUserDatabase *db,
00658 const DBusString *username,
00659 const DBusUserInfo **info,
00660 DBusError *error)
00661 {
00662 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00663 return *info != NULL;
00664 }
00665
00668