D-Bus 1.4.10
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-userdb.c User database abstraction 00003 * 00004 * Copyright (C) 2003, 2004 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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) /* hash table will pass 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) /* hash table will pass 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 /* See if the username is really a number */ 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 /* be sure we don't use these after here */ 00198 uid = DBUS_UID_UNSET; 00199 username = NULL; 00200 00201 /* insert into hash */ 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 /* This really should not happen. */ 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 /* DBUS_BUILD_TESTS */ 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 /* Tests in dbus-userdb-util.c */