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_USER_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;
00243 const DBusUserInfo *info;
00244
00245 system_db = _dbus_user_database_new ();
00246 if (system_db == NULL)
00247 return FALSE;
00248
00249 dbus_error_init (&error);
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 _dbus_user_database_flush (system_db);
00351
00352 _dbus_user_database_unlock_system ();
00353 }
00354
00362 dbus_bool_t
00363 _dbus_username_from_current_process (const DBusString **username)
00364 {
00365 _dbus_user_database_lock_system ();
00366 if (!init_system_db ())
00367 {
00368 _dbus_user_database_unlock_system ();
00369 return FALSE;
00370 }
00371 *username = &process_username;
00372 _dbus_user_database_unlock_system ();
00373
00374 return TRUE;
00375 }
00376
00384 dbus_bool_t
00385 _dbus_homedir_from_current_process (const DBusString **homedir)
00386 {
00387 _dbus_user_database_lock_system ();
00388 if (!init_system_db ())
00389 {
00390 _dbus_user_database_unlock_system ();
00391 return FALSE;
00392 }
00393 *homedir = &process_homedir;
00394 _dbus_user_database_unlock_system ();
00395
00396 return TRUE;
00397 }
00398
00406 dbus_bool_t
00407 _dbus_homedir_from_username (const DBusString *username,
00408 DBusString *homedir)
00409 {
00410 DBusUserDatabase *db;
00411 const DBusUserInfo *info;
00412 _dbus_user_database_lock_system ();
00413
00414 db = _dbus_user_database_get_system ();
00415 if (db == NULL)
00416 {
00417 _dbus_user_database_unlock_system ();
00418 return FALSE;
00419 }
00420
00421 if (!_dbus_user_database_get_username (db, username,
00422 &info, NULL))
00423 {
00424 _dbus_user_database_unlock_system ();
00425 return FALSE;
00426 }
00427
00428 if (!_dbus_string_append (homedir, info->homedir))
00429 {
00430 _dbus_user_database_unlock_system ();
00431 return FALSE;
00432 }
00433
00434 _dbus_user_database_unlock_system ();
00435 return TRUE;
00436 }
00437
00445 dbus_bool_t
00446 _dbus_homedir_from_uid (dbus_uid_t uid,
00447 DBusString *homedir)
00448 {
00449 DBusUserDatabase *db;
00450 const DBusUserInfo *info;
00451 _dbus_user_database_lock_system ();
00452
00453 db = _dbus_user_database_get_system ();
00454 if (db == NULL)
00455 {
00456 _dbus_user_database_unlock_system ();
00457 return FALSE;
00458 }
00459
00460 if (!_dbus_user_database_get_uid (db, uid,
00461 &info, NULL))
00462 {
00463 _dbus_user_database_unlock_system ();
00464 return FALSE;
00465 }
00466
00467 if (!_dbus_string_append (homedir, info->homedir))
00468 {
00469 _dbus_user_database_unlock_system ();
00470 return FALSE;
00471 }
00472
00473 _dbus_user_database_unlock_system ();
00474 return TRUE;
00475 }
00476
00491 dbus_bool_t
00492 _dbus_credentials_add_from_user (DBusCredentials *credentials,
00493 const DBusString *username)
00494 {
00495 DBusUserDatabase *db;
00496 const DBusUserInfo *info;
00497
00498 _dbus_user_database_lock_system ();
00499
00500 db = _dbus_user_database_get_system ();
00501 if (db == NULL)
00502 {
00503 _dbus_user_database_unlock_system ();
00504 return FALSE;
00505 }
00506
00507 if (!_dbus_user_database_get_username (db, username,
00508 &info, NULL))
00509 {
00510 _dbus_user_database_unlock_system ();
00511 return FALSE;
00512 }
00513
00514 if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
00515 {
00516 _dbus_user_database_unlock_system ();
00517 return FALSE;
00518 }
00519
00520 _dbus_user_database_unlock_system ();
00521 return TRUE;
00522 }
00523
00529 DBusUserDatabase*
00530 _dbus_user_database_new (void)
00531 {
00532 DBusUserDatabase *db;
00533
00534 db = dbus_new0 (DBusUserDatabase, 1);
00535 if (db == NULL)
00536 return NULL;
00537
00538 db->refcount = 1;
00539
00540 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00541 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00542
00543 if (db->users == NULL)
00544 goto failed;
00545
00546 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00547 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00548
00549 if (db->groups == NULL)
00550 goto failed;
00551
00552 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00553 NULL, NULL);
00554 if (db->users_by_name == NULL)
00555 goto failed;
00556
00557 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00558 NULL, NULL);
00559 if (db->groups_by_name == NULL)
00560 goto failed;
00561
00562 return db;
00563
00564 failed:
00565 _dbus_user_database_unref (db);
00566 return NULL;
00567 }
00568
00572 void
00573 _dbus_user_database_flush (DBusUserDatabase *db)
00574 {
00575 _dbus_hash_table_remove_all(db->users_by_name);
00576 _dbus_hash_table_remove_all(db->groups_by_name);
00577 _dbus_hash_table_remove_all(db->users);
00578 _dbus_hash_table_remove_all(db->groups);
00579 }
00580
00581 #ifdef DBUS_BUILD_TESTS
00582
00587 DBusUserDatabase *
00588 _dbus_user_database_ref (DBusUserDatabase *db)
00589 {
00590 _dbus_assert (db->refcount > 0);
00591
00592 db->refcount += 1;
00593
00594 return db;
00595 }
00596 #endif
00597
00602 void
00603 _dbus_user_database_unref (DBusUserDatabase *db)
00604 {
00605 _dbus_assert (db->refcount > 0);
00606
00607 db->refcount -= 1;
00608 if (db->refcount == 0)
00609 {
00610 if (db->users)
00611 _dbus_hash_table_unref (db->users);
00612
00613 if (db->groups)
00614 _dbus_hash_table_unref (db->groups);
00615
00616 if (db->users_by_name)
00617 _dbus_hash_table_unref (db->users_by_name);
00618
00619 if (db->groups_by_name)
00620 _dbus_hash_table_unref (db->groups_by_name);
00621
00622 dbus_free (db);
00623 }
00624 }
00625
00636 dbus_bool_t
00637 _dbus_user_database_get_uid (DBusUserDatabase *db,
00638 dbus_uid_t uid,
00639 const DBusUserInfo **info,
00640 DBusError *error)
00641 {
00642 *info = _dbus_user_database_lookup (db, uid, NULL, error);
00643 return *info != NULL;
00644 }
00645
00655 dbus_bool_t
00656 _dbus_user_database_get_username (DBusUserDatabase *db,
00657 const DBusString *username,
00658 const DBusUserInfo **info,
00659 DBusError *error)
00660 {
00661 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00662 return *info != NULL;
00663 }
00664
00667