D-Bus 1.2.24
|
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 #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) /* hash table will pass 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) /* hash table will pass 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 /* See if the username is really a number */ 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 /* be sure we don't use these after here */ 00197 uid = DBUS_UID_UNSET; 00198 username = NULL; 00199 00200 /* insert into hash */ 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 if (system_db != NULL) 00230 _dbus_user_database_unref (system_db); 00231 system_db = NULL; 00232 _dbus_string_free (&process_username); 00233 _dbus_string_free (&process_homedir); 00234 } 00235 00236 static dbus_bool_t 00237 init_system_db (void) 00238 { 00239 _dbus_assert (database_locked); 00240 00241 if (system_db == NULL) 00242 { 00243 DBusError error = DBUS_ERROR_INIT; 00244 const DBusUserInfo *info; 00245 00246 system_db = _dbus_user_database_new (); 00247 if (system_db == NULL) 00248 return FALSE; 00249 00250 if (!_dbus_user_database_get_uid (system_db, 00251 _dbus_getuid (), 00252 &info, 00253 &error)) 00254 { 00255 _dbus_user_database_unref (system_db); 00256 system_db = NULL; 00257 00258 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 00259 { 00260 dbus_error_free (&error); 00261 return FALSE; 00262 } 00263 else 00264 { 00265 /* This really should not happen. */ 00266 _dbus_warn ("Could not get password database information for UID of current process: %s\n", 00267 error.message); 00268 dbus_error_free (&error); 00269 return FALSE; 00270 } 00271 } 00272 00273 if (!_dbus_string_init (&process_username)) 00274 { 00275 _dbus_user_database_unref (system_db); 00276 system_db = NULL; 00277 return FALSE; 00278 } 00279 00280 if (!_dbus_string_init (&process_homedir)) 00281 { 00282 _dbus_string_free (&process_username); 00283 _dbus_user_database_unref (system_db); 00284 system_db = NULL; 00285 return FALSE; 00286 } 00287 00288 if (!_dbus_string_append (&process_username, 00289 info->username) || 00290 !_dbus_string_append (&process_homedir, 00291 info->homedir) || 00292 !_dbus_register_shutdown_func (shutdown_system_db, NULL)) 00293 { 00294 _dbus_string_free (&process_username); 00295 _dbus_string_free (&process_homedir); 00296 _dbus_user_database_unref (system_db); 00297 system_db = NULL; 00298 return FALSE; 00299 } 00300 } 00301 00302 return TRUE; 00303 } 00304 00308 void 00309 _dbus_user_database_lock_system (void) 00310 { 00311 _DBUS_LOCK (system_users); 00312 database_locked = TRUE; 00313 } 00314 00318 void 00319 _dbus_user_database_unlock_system (void) 00320 { 00321 database_locked = FALSE; 00322 _DBUS_UNLOCK (system_users); 00323 } 00324 00331 DBusUserDatabase* 00332 _dbus_user_database_get_system (void) 00333 { 00334 _dbus_assert (database_locked); 00335 00336 init_system_db (); 00337 00338 return system_db; 00339 } 00340 00344 void 00345 _dbus_user_database_flush_system (void) 00346 { 00347 _dbus_user_database_lock_system (); 00348 00349 if (system_db != NULL) 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 /* DBUS_BUILD_TESTS */ 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 /* Tests in dbus-userdb-util.c */