D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus 00003 * 00004 * Copyright (C) 2003, 2004, 2005 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 #include <unistd.h> 00025 #define DBUS_USERDB_INCLUDES_PRIVATE 1 00026 #include "dbus-userdb.h" 00027 #include "dbus-test.h" 00028 #include "dbus-internals.h" 00029 #include "dbus-protocol.h" 00030 #include <string.h> 00031 00032 #if HAVE_SYSTEMD 00033 #include <systemd/sd-login.h> 00034 #endif 00035 00048 dbus_bool_t 00049 _dbus_is_console_user (dbus_uid_t uid, 00050 DBusError *error) 00051 { 00052 00053 DBusUserDatabase *db; 00054 const DBusUserInfo *info; 00055 dbus_bool_t result = FALSE; 00056 00057 #ifdef HAVE_SYSTEMD 00058 /* check if we have logind */ 00059 if (access ("/run/systemd/seats/", F_OK) >= 0) 00060 { 00061 int r; 00062 00063 /* Check whether this user is logged in on at least one physical 00064 seat */ 00065 r = sd_uid_get_seats (uid, 0, NULL); 00066 if (r < 0) 00067 { 00068 dbus_set_error (error, _dbus_error_from_errno (-r), 00069 "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s", 00070 uid, 00071 _dbus_strerror (-r)); 00072 return FALSE; 00073 } 00074 00075 return (r > 0); 00076 } 00077 #endif 00078 00079 #ifdef HAVE_CONSOLE_OWNER_FILE 00080 00081 DBusString f; 00082 DBusStat st; 00083 00084 if (!_dbus_string_init (&f)) 00085 { 00086 _DBUS_SET_OOM (error); 00087 return FALSE; 00088 } 00089 00090 if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE)) 00091 { 00092 _dbus_string_free(&f); 00093 _DBUS_SET_OOM (error); 00094 return FALSE; 00095 } 00096 00097 if (_dbus_stat(&f, &st, NULL) && (st.uid == uid)) 00098 { 00099 _dbus_string_free(&f); 00100 return TRUE; 00101 } 00102 00103 _dbus_string_free(&f); 00104 00105 #endif /* HAVE_CONSOLE_OWNER_FILE */ 00106 00107 if (!_dbus_user_database_lock_system ()) 00108 { 00109 _DBUS_SET_OOM (error); 00110 return FALSE; 00111 } 00112 00113 db = _dbus_user_database_get_system (); 00114 if (db == NULL) 00115 { 00116 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database."); 00117 _dbus_user_database_unlock_system (); 00118 return FALSE; 00119 } 00120 00121 /* TPTD: this should be cache-safe, we've locked the DB and 00122 _dbus_user_at_console doesn't pass it on. */ 00123 info = _dbus_user_database_lookup (db, uid, NULL, error); 00124 00125 if (info == NULL) 00126 { 00127 _dbus_user_database_unlock_system (); 00128 return FALSE; 00129 } 00130 00131 result = _dbus_user_at_console (info->username, error); 00132 00133 _dbus_user_database_unlock_system (); 00134 00135 return result; 00136 } 00137 00145 dbus_bool_t 00146 _dbus_get_user_id (const DBusString *username, 00147 dbus_uid_t *uid) 00148 { 00149 return _dbus_get_user_id_and_primary_group (username, uid, NULL); 00150 } 00151 00159 dbus_bool_t 00160 _dbus_get_group_id (const DBusString *groupname, 00161 dbus_gid_t *gid) 00162 { 00163 DBusUserDatabase *db; 00164 const DBusGroupInfo *info; 00165 00166 /* FIXME: this can't distinguish ENOMEM from other errors */ 00167 if (!_dbus_user_database_lock_system ()) 00168 return FALSE; 00169 00170 db = _dbus_user_database_get_system (); 00171 if (db == NULL) 00172 { 00173 _dbus_user_database_unlock_system (); 00174 return FALSE; 00175 } 00176 00177 if (!_dbus_user_database_get_groupname (db, groupname, 00178 &info, NULL)) 00179 { 00180 _dbus_user_database_unlock_system (); 00181 return FALSE; 00182 } 00183 00184 *gid = info->gid; 00185 00186 _dbus_user_database_unlock_system (); 00187 return TRUE; 00188 } 00189 00198 dbus_bool_t 00199 _dbus_get_user_id_and_primary_group (const DBusString *username, 00200 dbus_uid_t *uid_p, 00201 dbus_gid_t *gid_p) 00202 { 00203 DBusUserDatabase *db; 00204 const DBusUserInfo *info; 00205 00206 /* FIXME: this can't distinguish ENOMEM from other errors */ 00207 if (!_dbus_user_database_lock_system ()) 00208 return FALSE; 00209 00210 db = _dbus_user_database_get_system (); 00211 if (db == NULL) 00212 { 00213 _dbus_user_database_unlock_system (); 00214 return FALSE; 00215 } 00216 00217 if (!_dbus_user_database_get_username (db, username, 00218 &info, NULL)) 00219 { 00220 _dbus_user_database_unlock_system (); 00221 return FALSE; 00222 } 00223 00224 if (uid_p) 00225 *uid_p = info->uid; 00226 if (gid_p) 00227 *gid_p = info->primary_gid; 00228 00229 _dbus_user_database_unlock_system (); 00230 return TRUE; 00231 } 00232 00245 DBusGroupInfo* 00246 _dbus_user_database_lookup_group (DBusUserDatabase *db, 00247 dbus_gid_t gid, 00248 const DBusString *groupname, 00249 DBusError *error) 00250 { 00251 DBusGroupInfo *info; 00252 00253 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00254 00255 /* See if the group is really a number */ 00256 if (gid == DBUS_UID_UNSET) 00257 { 00258 unsigned long n; 00259 00260 if (_dbus_is_a_number (groupname, &n)) 00261 gid = n; 00262 } 00263 00264 if (gid != DBUS_GID_UNSET) 00265 info = _dbus_hash_table_lookup_uintptr (db->groups, gid); 00266 else 00267 info = _dbus_hash_table_lookup_string (db->groups_by_name, 00268 _dbus_string_get_const_data (groupname)); 00269 if (info) 00270 { 00271 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", 00272 info->gid); 00273 return info; 00274 } 00275 else 00276 { 00277 if (gid != DBUS_GID_UNSET) 00278 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", 00279 gid); 00280 else 00281 _dbus_verbose ("No cache for groupname \"%s\"\n", 00282 _dbus_string_get_const_data (groupname)); 00283 00284 info = dbus_new0 (DBusGroupInfo, 1); 00285 if (info == NULL) 00286 { 00287 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00288 return NULL; 00289 } 00290 00291 if (gid != DBUS_GID_UNSET) 00292 { 00293 if (!_dbus_group_info_fill_gid (info, gid, error)) 00294 { 00295 _DBUS_ASSERT_ERROR_IS_SET (error); 00296 _dbus_group_info_free_allocated (info); 00297 return NULL; 00298 } 00299 } 00300 else 00301 { 00302 if (!_dbus_group_info_fill (info, groupname, error)) 00303 { 00304 _DBUS_ASSERT_ERROR_IS_SET (error); 00305 _dbus_group_info_free_allocated (info); 00306 return NULL; 00307 } 00308 } 00309 00310 /* don't use these past here */ 00311 gid = DBUS_GID_UNSET; 00312 groupname = NULL; 00313 00314 if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info)) 00315 { 00316 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00317 _dbus_group_info_free_allocated (info); 00318 return NULL; 00319 } 00320 00321 00322 if (!_dbus_hash_table_insert_string (db->groups_by_name, 00323 info->groupname, 00324 info)) 00325 { 00326 _dbus_hash_table_remove_uintptr (db->groups, info->gid); 00327 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00328 return NULL; 00329 } 00330 00331 return info; 00332 } 00333 } 00334 00335 00346 dbus_bool_t 00347 _dbus_user_database_get_groupname (DBusUserDatabase *db, 00348 const DBusString *groupname, 00349 const DBusGroupInfo **info, 00350 DBusError *error) 00351 { 00352 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); 00353 return *info != NULL; 00354 } 00355 00366 dbus_bool_t 00367 _dbus_user_database_get_gid (DBusUserDatabase *db, 00368 dbus_gid_t gid, 00369 const DBusGroupInfo **info, 00370 DBusError *error) 00371 { 00372 *info = _dbus_user_database_lookup_group (db, gid, NULL, error); 00373 return *info != NULL; 00374 } 00375 00376 00387 dbus_bool_t 00388 _dbus_groups_from_uid (dbus_uid_t uid, 00389 dbus_gid_t **group_ids, 00390 int *n_group_ids) 00391 { 00392 DBusUserDatabase *db; 00393 const DBusUserInfo *info; 00394 *group_ids = NULL; 00395 *n_group_ids = 0; 00396 00397 /* FIXME: this can't distinguish ENOMEM from other errors */ 00398 if (!_dbus_user_database_lock_system ()) 00399 return FALSE; 00400 00401 db = _dbus_user_database_get_system (); 00402 if (db == NULL) 00403 { 00404 _dbus_user_database_unlock_system (); 00405 return FALSE; 00406 } 00407 00408 if (!_dbus_user_database_get_uid (db, uid, 00409 &info, NULL)) 00410 { 00411 _dbus_user_database_unlock_system (); 00412 return FALSE; 00413 } 00414 00415 _dbus_assert (info->uid == uid); 00416 00417 if (info->n_group_ids > 0) 00418 { 00419 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids); 00420 if (*group_ids == NULL) 00421 { 00422 _dbus_user_database_unlock_system (); 00423 return FALSE; 00424 } 00425 00426 *n_group_ids = info->n_group_ids; 00427 00428 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t)); 00429 } 00430 00431 _dbus_user_database_unlock_system (); 00432 return TRUE; 00433 } 00436 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00437 #include <stdio.h> 00438 00444 dbus_bool_t 00445 _dbus_userdb_test (const char *test_data_dir) 00446 { 00447 const DBusString *username; 00448 const DBusString *homedir; 00449 dbus_uid_t uid; 00450 unsigned long *group_ids; 00451 int n_group_ids, i; 00452 DBusError error; 00453 00454 if (!_dbus_username_from_current_process (&username)) 00455 _dbus_assert_not_reached ("didn't get username"); 00456 00457 if (!_dbus_homedir_from_current_process (&homedir)) 00458 _dbus_assert_not_reached ("didn't get homedir"); 00459 00460 if (!_dbus_get_user_id (username, &uid)) 00461 _dbus_assert_not_reached ("didn't get uid"); 00462 00463 if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids)) 00464 _dbus_assert_not_reached ("didn't get groups"); 00465 00466 printf (" Current user: %s homedir: %s gids:", 00467 _dbus_string_get_const_data (username), 00468 _dbus_string_get_const_data (homedir)); 00469 00470 for (i=0; i<n_group_ids; i++) 00471 printf(" %ld", group_ids[i]); 00472 00473 printf ("\n"); 00474 00475 dbus_error_init (&error); 00476 printf ("Is Console user: %i\n", 00477 _dbus_is_console_user (uid, &error)); 00478 printf ("Invocation was OK: %s\n", error.message ? error.message : "yes"); 00479 dbus_error_free (&error); 00480 printf ("Is Console user 4711: %i\n", 00481 _dbus_is_console_user (4711, &error)); 00482 printf ("Invocation was OK: %s\n", error.message ? error.message : "yes"); 00483 dbus_error_free (&error); 00484 00485 dbus_free (group_ids); 00486 00487 return TRUE; 00488 } 00489 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */