Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-userdb.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 * 00022 */ 00023 #include "dbus-userdb.h" 00024 #include "dbus-hash.h" 00025 #include "dbus-test.h" 00026 #include "dbus-internals.h" 00027 #include "dbus-protocol.h" 00028 #include <string.h> 00029 00033 struct DBusUserDatabase 00034 { 00035 int refcount; 00037 DBusHashTable *users; 00038 DBusHashTable *groups; 00039 DBusHashTable *users_by_name; 00040 DBusHashTable *groups_by_name; 00041 }; 00042 00043 static void 00044 free_user_info (void *data) 00045 { 00046 DBusUserInfo *info = data; 00047 00048 if (info == NULL) /* hash table will pass NULL */ 00049 return; 00050 00051 _dbus_user_info_free (info); 00052 dbus_free (info); 00053 } 00054 00055 static void 00056 free_group_info (void *data) 00057 { 00058 DBusGroupInfo *info = data; 00059 00060 if (info == NULL) /* hash table will pass NULL */ 00061 return; 00062 00063 _dbus_group_info_free (info); 00064 dbus_free (info); 00065 } 00066 00067 static DBusUserInfo* 00068 _dbus_user_database_lookup (DBusUserDatabase *db, 00069 dbus_uid_t uid, 00070 const DBusString *username, 00071 DBusError *error) 00072 { 00073 DBusUserInfo *info; 00074 00075 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00076 _dbus_assert (uid != DBUS_UID_UNSET || username != NULL); 00077 00078 if (uid != DBUS_UID_UNSET) 00079 info = _dbus_hash_table_lookup_ulong (db->users, uid); 00080 else 00081 info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username)); 00082 00083 if (info) 00084 { 00085 _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n", 00086 uid); 00087 return info; 00088 } 00089 else 00090 { 00091 _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", 00092 uid); 00093 00094 info = dbus_new0 (DBusUserInfo, 1); 00095 if (info == NULL) 00096 { 00097 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00098 return NULL; 00099 } 00100 00101 if (uid != DBUS_UID_UNSET) 00102 { 00103 if (!_dbus_user_info_fill_uid (info, uid, error)) 00104 { 00105 _DBUS_ASSERT_ERROR_IS_SET (error); 00106 free_user_info (info); 00107 return NULL; 00108 } 00109 } 00110 else 00111 { 00112 if (!_dbus_user_info_fill (info, username, error)) 00113 { 00114 _DBUS_ASSERT_ERROR_IS_SET (error); 00115 free_user_info (info); 00116 return NULL; 00117 } 00118 } 00119 00120 /* be sure we don't use these after here */ 00121 uid = DBUS_UID_UNSET; 00122 username = NULL; 00123 00124 /* insert into hash */ 00125 if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info)) 00126 { 00127 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00128 free_user_info (info); 00129 return NULL; 00130 } 00131 00132 if (!_dbus_hash_table_insert_string (db->users_by_name, 00133 info->username, 00134 info)) 00135 { 00136 _dbus_hash_table_remove_ulong (db->users, info->uid); 00137 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00138 return NULL; 00139 } 00140 00141 return info; 00142 } 00143 } 00144 00145 static DBusGroupInfo* 00146 _dbus_user_database_lookup_group (DBusUserDatabase *db, 00147 dbus_gid_t gid, 00148 const DBusString *groupname, 00149 DBusError *error) 00150 { 00151 DBusGroupInfo *info; 00152 00153 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00154 00155 if (gid != DBUS_GID_UNSET) 00156 info = _dbus_hash_table_lookup_ulong (db->groups, gid); 00157 else 00158 info = _dbus_hash_table_lookup_string (db->groups_by_name, 00159 _dbus_string_get_const_data (groupname)); 00160 if (info) 00161 { 00162 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", 00163 gid); 00164 return info; 00165 } 00166 else 00167 { 00168 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", 00169 gid); 00170 00171 info = dbus_new0 (DBusGroupInfo, 1); 00172 if (info == NULL) 00173 { 00174 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00175 return NULL; 00176 } 00177 00178 if (!_dbus_group_info_fill_gid (info, gid, error)) 00179 { 00180 _DBUS_ASSERT_ERROR_IS_SET (error); 00181 free_group_info (info); 00182 return NULL; 00183 } 00184 00185 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info)) 00186 { 00187 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00188 free_group_info (info); 00189 return NULL; 00190 } 00191 00192 00193 if (!_dbus_hash_table_insert_string (db->groups_by_name, 00194 info->groupname, 00195 info)) 00196 { 00197 _dbus_hash_table_remove_ulong (db->groups, info->gid); 00198 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00199 return NULL; 00200 } 00201 00202 return info; 00203 } 00204 } 00205 00206 _DBUS_DEFINE_GLOBAL_LOCK(system_users); 00207 static dbus_bool_t database_locked = FALSE; 00208 static DBusUserDatabase *system_db = NULL; 00209 static DBusString process_username; 00210 static DBusString process_homedir; 00211 00212 static void 00213 shutdown_system_db (void *data) 00214 { 00215 _dbus_user_database_unref (system_db); 00216 system_db = NULL; 00217 _dbus_string_free (&process_username); 00218 _dbus_string_free (&process_homedir); 00219 } 00220 00221 static dbus_bool_t 00222 init_system_db (void) 00223 { 00224 _dbus_assert (database_locked); 00225 00226 if (system_db == NULL) 00227 { 00228 DBusError error; 00229 const DBusUserInfo *info; 00230 00231 system_db = _dbus_user_database_new (); 00232 if (system_db == NULL) 00233 return FALSE; 00234 00235 dbus_error_init (&error); 00236 00237 if (!_dbus_user_database_get_uid (system_db, 00238 _dbus_getuid (), 00239 &info, 00240 &error)) 00241 { 00242 _dbus_user_database_unref (system_db); 00243 system_db = NULL; 00244 00245 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 00246 { 00247 dbus_error_free (&error); 00248 return FALSE; 00249 } 00250 else 00251 { 00252 /* This really should not happen. */ 00253 _dbus_warn ("Could not get password database information for UID of current process: %s\n", 00254 error.message); 00255 dbus_error_free (&error); 00256 return FALSE; 00257 } 00258 } 00259 00260 if (!_dbus_string_init (&process_username)) 00261 { 00262 _dbus_user_database_unref (system_db); 00263 system_db = NULL; 00264 return FALSE; 00265 } 00266 00267 if (!_dbus_string_init (&process_homedir)) 00268 { 00269 _dbus_string_free (&process_username); 00270 _dbus_user_database_unref (system_db); 00271 system_db = NULL; 00272 return FALSE; 00273 } 00274 00275 if (!_dbus_string_append (&process_username, 00276 info->username) || 00277 !_dbus_string_append (&process_homedir, 00278 info->homedir) || 00279 !_dbus_register_shutdown_func (shutdown_system_db, NULL)) 00280 { 00281 _dbus_string_free (&process_username); 00282 _dbus_string_free (&process_homedir); 00283 _dbus_user_database_unref (system_db); 00284 system_db = NULL; 00285 return FALSE; 00286 } 00287 } 00288 00289 return TRUE; 00290 } 00291 00300 void 00301 _dbus_user_database_lock_system (void) 00302 { 00303 _DBUS_LOCK (system_users); 00304 database_locked = TRUE; 00305 } 00306 00310 void 00311 _dbus_user_database_unlock_system (void) 00312 { 00313 database_locked = FALSE; 00314 _DBUS_UNLOCK (system_users); 00315 } 00316 00323 DBusUserDatabase* 00324 _dbus_user_database_get_system (void) 00325 { 00326 _dbus_assert (database_locked); 00327 00328 init_system_db (); 00329 00330 return system_db; 00331 } 00332 00340 dbus_bool_t 00341 _dbus_username_from_current_process (const DBusString **username) 00342 { 00343 _dbus_user_database_lock_system (); 00344 if (!init_system_db ()) 00345 { 00346 _dbus_user_database_unlock_system (); 00347 return FALSE; 00348 } 00349 *username = &process_username; 00350 _dbus_user_database_unlock_system (); 00351 00352 return TRUE; 00353 } 00354 00362 dbus_bool_t 00363 _dbus_homedir_from_current_process (const DBusString **homedir) 00364 { 00365 _dbus_user_database_lock_system (); 00366 if (!init_system_db ()) 00367 { 00368 _dbus_user_database_unlock_system (); 00369 return FALSE; 00370 } 00371 *homedir = &process_homedir; 00372 _dbus_user_database_unlock_system (); 00373 00374 return TRUE; 00375 } 00376 00384 dbus_bool_t 00385 _dbus_get_user_id (const DBusString *username, 00386 dbus_uid_t *uid) 00387 { 00388 DBusCredentials creds; 00389 00390 if (!_dbus_credentials_from_username (username, &creds)) 00391 return FALSE; 00392 00393 if (creds.uid == DBUS_UID_UNSET) 00394 return FALSE; 00395 00396 *uid = creds.uid; 00397 00398 return TRUE; 00399 } 00400 00408 dbus_bool_t 00409 _dbus_get_group_id (const DBusString *groupname, 00410 dbus_gid_t *gid) 00411 { 00412 DBusUserDatabase *db; 00413 const DBusGroupInfo *info; 00414 _dbus_user_database_lock_system (); 00415 00416 db = _dbus_user_database_get_system (); 00417 if (db == NULL) 00418 { 00419 _dbus_user_database_unlock_system (); 00420 return FALSE; 00421 } 00422 00423 if (!_dbus_user_database_get_groupname (db, groupname, 00424 &info, NULL)) 00425 { 00426 _dbus_user_database_unlock_system (); 00427 return FALSE; 00428 } 00429 00430 *gid = info->gid; 00431 00432 _dbus_user_database_unlock_system (); 00433 return TRUE; 00434 } 00435 00443 dbus_bool_t 00444 _dbus_homedir_from_username (const DBusString *username, 00445 DBusString *homedir) 00446 { 00447 DBusUserDatabase *db; 00448 const DBusUserInfo *info; 00449 _dbus_user_database_lock_system (); 00450 00451 db = _dbus_user_database_get_system (); 00452 if (db == NULL) 00453 { 00454 _dbus_user_database_unlock_system (); 00455 return FALSE; 00456 } 00457 00458 if (!_dbus_user_database_get_username (db, username, 00459 &info, NULL)) 00460 { 00461 _dbus_user_database_unlock_system (); 00462 return FALSE; 00463 } 00464 00465 if (!_dbus_string_append (homedir, info->homedir)) 00466 { 00467 _dbus_user_database_unlock_system (); 00468 return FALSE; 00469 } 00470 00471 _dbus_user_database_unlock_system (); 00472 return TRUE; 00473 } 00474 00482 dbus_bool_t 00483 _dbus_uid_from_string (const DBusString *uid_str, 00484 dbus_uid_t *uid) 00485 { 00486 int end; 00487 long val; 00488 00489 if (_dbus_string_get_length (uid_str) == 0) 00490 { 00491 _dbus_verbose ("UID string was zero length\n"); 00492 return FALSE; 00493 } 00494 00495 val = -1; 00496 end = 0; 00497 if (!_dbus_string_parse_int (uid_str, 0, &val, 00498 &end)) 00499 { 00500 _dbus_verbose ("could not parse string as a UID\n"); 00501 return FALSE; 00502 } 00503 00504 if (end != _dbus_string_get_length (uid_str)) 00505 { 00506 _dbus_verbose ("string contained trailing stuff after UID\n"); 00507 return FALSE; 00508 } 00509 00510 *uid = val; 00511 00512 return TRUE; 00513 } 00514 00522 dbus_bool_t 00523 _dbus_credentials_from_username (const DBusString *username, 00524 DBusCredentials *credentials) 00525 { 00526 DBusUserDatabase *db; 00527 const DBusUserInfo *info; 00528 _dbus_user_database_lock_system (); 00529 00530 db = _dbus_user_database_get_system (); 00531 if (db == NULL) 00532 { 00533 _dbus_user_database_unlock_system (); 00534 return FALSE; 00535 } 00536 00537 if (!_dbus_user_database_get_username (db, username, 00538 &info, NULL)) 00539 { 00540 _dbus_user_database_unlock_system (); 00541 return FALSE; 00542 } 00543 00544 credentials->pid = DBUS_PID_UNSET; 00545 credentials->uid = info->uid; 00546 credentials->gid = info->primary_gid; 00547 00548 _dbus_user_database_unlock_system (); 00549 return TRUE; 00550 } 00551 00559 dbus_bool_t 00560 _dbus_credentials_from_uid (dbus_uid_t uid, 00561 DBusCredentials *credentials) 00562 { 00563 DBusUserDatabase *db; 00564 const DBusUserInfo *info; 00565 _dbus_user_database_lock_system (); 00566 00567 db = _dbus_user_database_get_system (); 00568 if (db == NULL) 00569 { 00570 _dbus_user_database_unlock_system (); 00571 return FALSE; 00572 } 00573 00574 if (!_dbus_user_database_get_uid (db, uid, 00575 &info, NULL)) 00576 { 00577 _dbus_user_database_unlock_system (); 00578 return FALSE; 00579 } 00580 00581 _dbus_assert (info->uid == uid); 00582 00583 credentials->pid = DBUS_PID_UNSET; 00584 credentials->uid = info->uid; 00585 credentials->gid = info->primary_gid; 00586 00587 _dbus_user_database_unlock_system (); 00588 return TRUE; 00589 } 00590 00596 DBusUserDatabase* 00597 _dbus_user_database_new (void) 00598 { 00599 DBusUserDatabase *db; 00600 00601 db = dbus_new0 (DBusUserDatabase, 1); 00602 if (db == NULL) 00603 return NULL; 00604 00605 db->refcount = 1; 00606 00607 db->users = _dbus_hash_table_new (DBUS_HASH_ULONG, 00608 NULL, free_user_info); 00609 00610 if (db->users == NULL) 00611 goto failed; 00612 00613 db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG, 00614 NULL, free_group_info); 00615 00616 if (db->groups == NULL) 00617 goto failed; 00618 00619 db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, 00620 NULL, NULL); 00621 if (db->users_by_name == NULL) 00622 goto failed; 00623 00624 db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, 00625 NULL, NULL); 00626 if (db->groups_by_name == NULL) 00627 goto failed; 00628 00629 return db; 00630 00631 failed: 00632 _dbus_user_database_unref (db); 00633 return NULL; 00634 } 00635 00641 DBusUserDatabase * 00642 _dbus_user_database_ref (DBusUserDatabase *db) 00643 { 00644 _dbus_assert (db->refcount > 0); 00645 00646 db->refcount += 1; 00647 00648 return db; 00649 } 00650 00655 void 00656 _dbus_user_database_unref (DBusUserDatabase *db) 00657 { 00658 _dbus_assert (db->refcount > 0); 00659 00660 db->refcount -= 1; 00661 if (db->refcount == 0) 00662 { 00663 if (db->users) 00664 _dbus_hash_table_unref (db->users); 00665 00666 if (db->groups) 00667 _dbus_hash_table_unref (db->groups); 00668 00669 if (db->users_by_name) 00670 _dbus_hash_table_unref (db->users_by_name); 00671 00672 if (db->groups_by_name) 00673 _dbus_hash_table_unref (db->groups_by_name); 00674 00675 dbus_free (db); 00676 } 00677 } 00678 00692 dbus_bool_t 00693 _dbus_user_database_get_groups (DBusUserDatabase *db, 00694 dbus_uid_t uid, 00695 dbus_gid_t **group_ids, 00696 int *n_group_ids, 00697 DBusError *error) 00698 { 00699 DBusUserInfo *info; 00700 00701 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00702 00703 *group_ids = NULL; 00704 *n_group_ids = 0; 00705 00706 info = _dbus_user_database_lookup (db, uid, NULL, error); 00707 if (info == NULL) 00708 { 00709 _DBUS_ASSERT_ERROR_IS_SET (error); 00710 return FALSE; 00711 } 00712 00713 if (info->n_group_ids > 0) 00714 { 00715 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids); 00716 if (*group_ids == NULL) 00717 { 00718 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00719 return FALSE; 00720 } 00721 00722 *n_group_ids = info->n_group_ids; 00723 00724 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t)); 00725 } 00726 00727 return TRUE; 00728 } 00729 00740 dbus_bool_t 00741 _dbus_user_database_get_uid (DBusUserDatabase *db, 00742 dbus_uid_t uid, 00743 const DBusUserInfo **info, 00744 DBusError *error) 00745 { 00746 *info = _dbus_user_database_lookup (db, uid, NULL, error); 00747 return *info != NULL; 00748 } 00749 00760 dbus_bool_t 00761 _dbus_user_database_get_gid (DBusUserDatabase *db, 00762 dbus_gid_t gid, 00763 const DBusGroupInfo **info, 00764 DBusError *error) 00765 { 00766 *info = _dbus_user_database_lookup_group (db, gid, NULL, error); 00767 return *info != NULL; 00768 } 00769 00779 dbus_bool_t 00780 _dbus_user_database_get_username (DBusUserDatabase *db, 00781 const DBusString *username, 00782 const DBusUserInfo **info, 00783 DBusError *error) 00784 { 00785 *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error); 00786 return *info != NULL; 00787 } 00788 00799 dbus_bool_t 00800 _dbus_user_database_get_groupname (DBusUserDatabase *db, 00801 const DBusString *groupname, 00802 const DBusGroupInfo **info, 00803 DBusError *error) 00804 { 00805 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); 00806 return *info != NULL; 00807 } 00808 00811 #ifdef DBUS_BUILD_TESTS 00812 #include <stdio.h> 00813 00819 dbus_bool_t 00820 _dbus_userdb_test (const char *test_data_dir) 00821 { 00822 const DBusString *username; 00823 const DBusString *homedir; 00824 00825 if (!_dbus_username_from_current_process (&username)) 00826 _dbus_assert_not_reached ("didn't get username"); 00827 00828 if (!_dbus_homedir_from_current_process (&homedir)) 00829 _dbus_assert_not_reached ("didn't get homedir"); 00830 00831 printf (" Current user: %s homedir: %s\n", 00832 _dbus_string_get_const_data (username), 00833 _dbus_string_get_const_data (homedir)); 00834 00835 return TRUE; 00836 } 00837 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Oct 12 02:07:54 2004 for D-BUS by doxygen 1.3.7