D-Bus
1.10.12
|
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 if (uid != DBUS_UID_UNSET) 00148 info = _dbus_hash_table_lookup_uintptr (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 { 00160 if (uid != DBUS_UID_UNSET) 00161 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", 00162 uid); 00163 else 00164 _dbus_verbose ("No cache for user \"%s\"\n", 00165 _dbus_string_get_const_data (username)); 00166 00167 info = dbus_new0 (DBusUserInfo, 1); 00168 if (info == NULL) 00169 { 00170 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00171 return NULL; 00172 } 00173 00174 if (uid != DBUS_UID_UNSET) 00175 { 00176 if (!_dbus_user_info_fill_uid (info, uid, error)) 00177 { 00178 _DBUS_ASSERT_ERROR_IS_SET (error); 00179 _dbus_user_info_free_allocated (info); 00180 return NULL; 00181 } 00182 } 00183 else 00184 { 00185 if (!_dbus_user_info_fill (info, username, error)) 00186 { 00187 _DBUS_ASSERT_ERROR_IS_SET (error); 00188 _dbus_user_info_free_allocated (info); 00189 return NULL; 00190 } 00191 } 00192 00193 /* be sure we don't use these after here */ 00194 uid = DBUS_UID_UNSET; 00195 username = NULL; 00196 00197 /* insert into hash */ 00198 if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info)) 00199 { 00200 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00201 _dbus_user_info_free_allocated (info); 00202 return NULL; 00203 } 00204 00205 if (!_dbus_hash_table_insert_string (db->users_by_name, 00206 info->username, 00207 info)) 00208 { 00209 _dbus_hash_table_remove_uintptr (db->users, info->uid); 00210 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00211 return NULL; 00212 } 00213 00214 return info; 00215 } 00216 } 00217 00218 static dbus_bool_t database_locked = FALSE; 00219 static DBusUserDatabase *system_db = NULL; 00220 static DBusString process_username; 00221 static DBusString process_homedir; 00222 00223 static void 00224 shutdown_system_db (void *data) 00225 { 00226 if (system_db != NULL) 00227 _dbus_user_database_unref (system_db); 00228 system_db = NULL; 00229 _dbus_string_free (&process_username); 00230 _dbus_string_free (&process_homedir); 00231 } 00232 00233 static dbus_bool_t 00234 init_system_db (void) 00235 { 00236 _dbus_assert (database_locked); 00237 00238 if (system_db == NULL) 00239 { 00240 DBusError error = DBUS_ERROR_INIT; 00241 const DBusUserInfo *info; 00242 00243 system_db = _dbus_user_database_new (); 00244 if (system_db == NULL) 00245 return FALSE; 00246 00247 if (!_dbus_user_database_get_uid (system_db, 00248 _dbus_getuid (), 00249 &info, 00250 &error)) 00251 { 00252 _dbus_user_database_unref (system_db); 00253 system_db = NULL; 00254 00255 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 00256 { 00257 dbus_error_free (&error); 00258 return FALSE; 00259 } 00260 else 00261 { 00262 /* This really should not happen. */ 00263 _dbus_warn ("Could not get password database information for UID of current process: %s\n", 00264 error.message); 00265 dbus_error_free (&error); 00266 return FALSE; 00267 } 00268 } 00269 00270 if (!_dbus_string_init (&process_username)) 00271 { 00272 _dbus_user_database_unref (system_db); 00273 system_db = NULL; 00274 return FALSE; 00275 } 00276 00277 if (!_dbus_string_init (&process_homedir)) 00278 { 00279 _dbus_string_free (&process_username); 00280 _dbus_user_database_unref (system_db); 00281 system_db = NULL; 00282 return FALSE; 00283 } 00284 00285 if (!_dbus_string_append (&process_username, 00286 info->username) || 00287 !_dbus_string_append (&process_homedir, 00288 info->homedir) || 00289 !_dbus_register_shutdown_func (shutdown_system_db, NULL)) 00290 { 00291 _dbus_string_free (&process_username); 00292 _dbus_string_free (&process_homedir); 00293 _dbus_user_database_unref (system_db); 00294 system_db = NULL; 00295 return FALSE; 00296 } 00297 } 00298 00299 return TRUE; 00300 } 00301 00305 dbus_bool_t 00306 _dbus_user_database_lock_system (void) 00307 { 00308 if (_DBUS_LOCK (system_users)) 00309 { 00310 database_locked = TRUE; 00311 return TRUE; 00312 } 00313 else 00314 { 00315 return FALSE; 00316 } 00317 } 00318 00322 void 00323 _dbus_user_database_unlock_system (void) 00324 { 00325 database_locked = FALSE; 00326 _DBUS_UNLOCK (system_users); 00327 } 00328 00335 DBusUserDatabase* 00336 _dbus_user_database_get_system (void) 00337 { 00338 _dbus_assert (database_locked); 00339 00340 init_system_db (); 00341 00342 return system_db; 00343 } 00344 00348 void 00349 _dbus_user_database_flush_system (void) 00350 { 00351 if (!_dbus_user_database_lock_system ()) 00352 { 00353 /* nothing to flush */ 00354 return; 00355 } 00356 00357 if (system_db != NULL) 00358 _dbus_user_database_flush (system_db); 00359 00360 _dbus_user_database_unlock_system (); 00361 } 00362 00370 dbus_bool_t 00371 _dbus_username_from_current_process (const DBusString **username) 00372 { 00373 if (!_dbus_user_database_lock_system ()) 00374 return FALSE; 00375 00376 if (!init_system_db ()) 00377 { 00378 _dbus_user_database_unlock_system (); 00379 return FALSE; 00380 } 00381 *username = &process_username; 00382 _dbus_user_database_unlock_system (); 00383 00384 return TRUE; 00385 } 00386 00394 dbus_bool_t 00395 _dbus_homedir_from_current_process (const DBusString **homedir) 00396 { 00397 if (!_dbus_user_database_lock_system ()) 00398 return FALSE; 00399 00400 if (!init_system_db ()) 00401 { 00402 _dbus_user_database_unlock_system (); 00403 return FALSE; 00404 } 00405 *homedir = &process_homedir; 00406 _dbus_user_database_unlock_system (); 00407 00408 return TRUE; 00409 } 00410 00418 dbus_bool_t 00419 _dbus_homedir_from_username (const DBusString *username, 00420 DBusString *homedir) 00421 { 00422 DBusUserDatabase *db; 00423 const DBusUserInfo *info; 00424 00425 /* FIXME: this can't distinguish ENOMEM from other errors */ 00426 if (!_dbus_user_database_lock_system ()) 00427 return FALSE; 00428 00429 db = _dbus_user_database_get_system (); 00430 if (db == NULL) 00431 { 00432 _dbus_user_database_unlock_system (); 00433 return FALSE; 00434 } 00435 00436 if (!_dbus_user_database_get_username (db, username, 00437 &info, NULL)) 00438 { 00439 _dbus_user_database_unlock_system (); 00440 return FALSE; 00441 } 00442 00443 if (!_dbus_string_append (homedir, info->homedir)) 00444 { 00445 _dbus_user_database_unlock_system (); 00446 return FALSE; 00447 } 00448 00449 _dbus_user_database_unlock_system (); 00450 return TRUE; 00451 } 00452 00460 dbus_bool_t 00461 _dbus_homedir_from_uid (dbus_uid_t uid, 00462 DBusString *homedir) 00463 { 00464 DBusUserDatabase *db; 00465 const DBusUserInfo *info; 00466 00467 /* FIXME: this can't distinguish ENOMEM from other errors */ 00468 if (!_dbus_user_database_lock_system ()) 00469 return FALSE; 00470 00471 db = _dbus_user_database_get_system (); 00472 if (db == NULL) 00473 { 00474 _dbus_user_database_unlock_system (); 00475 return FALSE; 00476 } 00477 00478 if (!_dbus_user_database_get_uid (db, uid, 00479 &info, NULL)) 00480 { 00481 _dbus_user_database_unlock_system (); 00482 return FALSE; 00483 } 00484 00485 if (!_dbus_string_append (homedir, info->homedir)) 00486 { 00487 _dbus_user_database_unlock_system (); 00488 return FALSE; 00489 } 00490 00491 _dbus_user_database_unlock_system (); 00492 return TRUE; 00493 } 00494 00509 dbus_bool_t 00510 _dbus_credentials_add_from_user (DBusCredentials *credentials, 00511 const DBusString *username) 00512 { 00513 DBusUserDatabase *db; 00514 const DBusUserInfo *info; 00515 00516 /* FIXME: this can't distinguish ENOMEM from other errors */ 00517 if (!_dbus_user_database_lock_system ()) 00518 return FALSE; 00519 00520 db = _dbus_user_database_get_system (); 00521 if (db == NULL) 00522 { 00523 _dbus_user_database_unlock_system (); 00524 return FALSE; 00525 } 00526 00527 if (!_dbus_user_database_get_username (db, username, 00528 &info, NULL)) 00529 { 00530 _dbus_user_database_unlock_system (); 00531 return FALSE; 00532 } 00533 00534 if (!_dbus_credentials_add_unix_uid(credentials, info->uid)) 00535 { 00536 _dbus_user_database_unlock_system (); 00537 return FALSE; 00538 } 00539 00540 _dbus_user_database_unlock_system (); 00541 return TRUE; 00542 } 00543 00549 DBusUserDatabase* 00550 _dbus_user_database_new (void) 00551 { 00552 DBusUserDatabase *db; 00553 00554 db = dbus_new0 (DBusUserDatabase, 1); 00555 if (db == NULL) 00556 return NULL; 00557 00558 db->refcount = 1; 00559 00560 db->users = _dbus_hash_table_new (DBUS_HASH_UINTPTR, 00561 NULL, (DBusFreeFunction) _dbus_user_info_free_allocated); 00562 00563 if (db->users == NULL) 00564 goto failed; 00565 00566 db->groups = _dbus_hash_table_new (DBUS_HASH_UINTPTR, 00567 NULL, (DBusFreeFunction) _dbus_group_info_free_allocated); 00568 00569 if (db->groups == NULL) 00570 goto failed; 00571 00572 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, 00573 NULL, NULL); 00574 if (db->users_by_name == NULL) 00575 goto failed; 00576 00577 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, 00578 NULL, NULL); 00579 if (db->groups_by_name == NULL) 00580 goto failed; 00581 00582 return db; 00583 00584 failed: 00585 _dbus_user_database_unref (db); 00586 return NULL; 00587 } 00588 00592 void 00593 _dbus_user_database_flush (DBusUserDatabase *db) 00594 { 00595 _dbus_hash_table_remove_all(db->users_by_name); 00596 _dbus_hash_table_remove_all(db->groups_by_name); 00597 _dbus_hash_table_remove_all(db->users); 00598 _dbus_hash_table_remove_all(db->groups); 00599 } 00600 00601 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00602 00607 DBusUserDatabase * 00608 _dbus_user_database_ref (DBusUserDatabase *db) 00609 { 00610 _dbus_assert (db->refcount > 0); 00611 00612 db->refcount += 1; 00613 00614 return db; 00615 } 00616 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ 00617 00622 void 00623 _dbus_user_database_unref (DBusUserDatabase *db) 00624 { 00625 _dbus_assert (db->refcount > 0); 00626 00627 db->refcount -= 1; 00628 if (db->refcount == 0) 00629 { 00630 if (db->users) 00631 _dbus_hash_table_unref (db->users); 00632 00633 if (db->groups) 00634 _dbus_hash_table_unref (db->groups); 00635 00636 if (db->users_by_name) 00637 _dbus_hash_table_unref (db->users_by_name); 00638 00639 if (db->groups_by_name) 00640 _dbus_hash_table_unref (db->groups_by_name); 00641 00642 dbus_free (db); 00643 } 00644 } 00645 00656 dbus_bool_t 00657 _dbus_user_database_get_uid (DBusUserDatabase *db, 00658 dbus_uid_t uid, 00659 const DBusUserInfo **info, 00660 DBusError *error) 00661 { 00662 *info = _dbus_user_database_lookup (db, uid, NULL, error); 00663 return *info != NULL; 00664 } 00665 00675 dbus_bool_t 00676 _dbus_user_database_get_username (DBusUserDatabase *db, 00677 const DBusString *username, 00678 const DBusUserInfo **info, 00679 DBusError *error) 00680 { 00681 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error); 00682 return *info != NULL; 00683 } 00684 00687 /* Tests in dbus-userdb-util.c */