1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus 3 * 4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 #define DBUS_USERDB_INCLUDES_PRIVATE 1 24 #include "dbus-userdb.h" 25 #include "dbus-test.h" 26 #include "dbus-internals.h" 27 #include "dbus-protocol.h" 28 #include <string.h> 29 30 /** 31 * @addtogroup DBusInternalsUtils 32 * @{ 33 */ 34 35 /** 36 * Checks to see if the UID sent in is the console user 37 * 38 * @param uid UID of person to check 39 * @param error return location for errors 40 * @returns #TRUE if the UID is the same as the console user and there are no errors 41 */ 42 dbus_bool_t 43 _dbus_is_console_user (dbus_uid_t uid, 44 DBusError *error) 45 { 46 47 DBusUserDatabase *db; 48 const DBusUserInfo *info; 49 dbus_bool_t result = FALSE; 50 51 #ifdef HAVE_CONSOLE_OWNER_FILE 52 53 DBusString f; 54 DBusStat st; 55 56 if (!_dbus_string_init (&f)) 57 { 58 _DBUS_SET_OOM (error); 59 return FALSE; 60 } 61 62 if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE)) 63 { 64 _dbus_string_free(&f); 65 _DBUS_SET_OOM (error); 66 return FALSE; 67 } 68 69 if (_dbus_stat(&f, &st, NULL) && (st.uid == uid)) 70 { 71 _dbus_string_free(&f); 72 return TRUE; 73 } 74 75 _dbus_string_free(&f); 76 77 #endif /* HAVE_CONSOLE_OWNER_FILE */ 78 79 _dbus_user_database_lock_system (); 80 81 db = _dbus_user_database_get_system (); 82 if (db == NULL) 83 { 84 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database."); 85 _dbus_user_database_unlock_system (); 86 return FALSE; 87 } 88 89 info = _dbus_user_database_lookup (db, uid, NULL, error); 90 91 if (info == NULL) 92 { 93 _dbus_user_database_unlock_system (); 94 return FALSE; 95 } 96 97 result = _dbus_user_at_console (info->username, error); 98 99 _dbus_user_database_unlock_system (); 100 101 return result; 102 } 103 104 105 /** 106 * Gets the credentials corresponding to the given UID. 107 * 108 * @param uid the UID 109 * @param credentials credentials to fill in 110 * @returns #TRUE if the UID existed and we got some credentials 111 */ 112 dbus_bool_t 113 _dbus_credentials_from_uid (dbus_uid_t uid, 114 DBusCredentials *credentials) 115 { 116 DBusUserDatabase *db; 117 const DBusUserInfo *info; 118 _dbus_user_database_lock_system (); 119 120 db = _dbus_user_database_get_system (); 121 if (db == NULL) 122 { 123 _dbus_user_database_unlock_system (); 124 return FALSE; 125 } 126 127 if (!_dbus_user_database_get_uid (db, uid, 128 &info, NULL)) 129 { 130 _dbus_user_database_unlock_system (); 131 return FALSE; 132 } 133 134 _dbus_assert (info->uid == uid); 135 136 credentials->pid = DBUS_PID_UNSET; 137 credentials->uid = info->uid; 138 credentials->gid = info->primary_gid; 139 140 _dbus_user_database_unlock_system (); 141 return TRUE; 142 } 143 144 145 /** 146 * Gets user ID given username 147 * 148 * @param username the username 149 * @param uid return location for UID 150 * @returns #TRUE if username existed and we got the UID 151 */ 152 dbus_bool_t 153 _dbus_get_user_id (const DBusString *username, 154 dbus_uid_t *uid) 155 { 156 DBusCredentials creds; 157 158 if (!_dbus_credentials_from_username (username, &creds)) 159 return FALSE; 160 161 if (creds.uid == DBUS_UID_UNSET) 162 return FALSE; 163 164 *uid = creds.uid; 165 166 return TRUE; 167 } 168 169 /** 170 * Gets group ID given groupname 171 * 172 * @param groupname the groupname 173 * @param gid return location for GID 174 * @returns #TRUE if group name existed and we got the GID 175 */ 176 dbus_bool_t 177 _dbus_get_group_id (const DBusString *groupname, 178 dbus_gid_t *gid) 179 { 180 DBusUserDatabase *db; 181 const DBusGroupInfo *info; 182 _dbus_user_database_lock_system (); 183 184 db = _dbus_user_database_get_system (); 185 if (db == NULL) 186 { 187 _dbus_user_database_unlock_system (); 188 return FALSE; 189 } 190 191 if (!_dbus_user_database_get_groupname (db, groupname, 192 &info, NULL)) 193 { 194 _dbus_user_database_unlock_system (); 195 return FALSE; 196 } 197 198 *gid = info->gid; 199 200 _dbus_user_database_unlock_system (); 201 return TRUE; 202 } 203 204 /** 205 * Looks up a gid or group name in the user database. Only one of 206 * name or GID can be provided. There are wrapper functions for this 207 * that are better to use, this one does no locking or anything on the 208 * database and otherwise sort of sucks. 209 * 210 * @param db the database 211 * @param gid the group ID or #DBUS_GID_UNSET 212 * @param groupname group name or #NULL 213 * @param error error to fill in 214 * @returns the entry in the database 215 */ 216 DBusGroupInfo* 217 _dbus_user_database_lookup_group (DBusUserDatabase *db, 218 dbus_gid_t gid, 219 const DBusString *groupname, 220 DBusError *error) 221 { 222 DBusGroupInfo *info; 223 224 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 225 226 /* See if the group is really a number */ 227 if (gid == DBUS_UID_UNSET) 228 { 229 unsigned long n; 230 231 if (_dbus_is_a_number (groupname, &n)) 232 gid = n; 233 } 234 235 236 if (gid != DBUS_GID_UNSET) 237 info = _dbus_hash_table_lookup_ulong (db->groups, gid); 238 else 239 info = _dbus_hash_table_lookup_string (db->groups_by_name, 240 _dbus_string_get_const_data (groupname)); 241 if (info) 242 { 243 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", 244 info->gid); 245 return info; 246 } 247 else 248 { 249 if (gid != DBUS_GID_UNSET) 250 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", 251 gid); 252 else 253 _dbus_verbose ("No cache for groupname \"%s\"\n", 254 _dbus_string_get_const_data (groupname)); 255 256 info = dbus_new0 (DBusGroupInfo, 1); 257 if (info == NULL) 258 { 259 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 260 return NULL; 261 } 262 263 if (gid != DBUS_GID_UNSET) 264 { 265 if (!_dbus_group_info_fill_gid (info, gid, error)) 266 { 267 _DBUS_ASSERT_ERROR_IS_SET (error); 268 _dbus_group_info_free_allocated (info); 269 return NULL; 270 } 271 } 272 else 273 { 274 if (!_dbus_group_info_fill (info, groupname, error)) 275 { 276 _DBUS_ASSERT_ERROR_IS_SET (error); 277 _dbus_group_info_free_allocated (info); 278 return NULL; 279 } 280 } 281 282 /* don't use these past here */ 283 gid = DBUS_GID_UNSET; 284 groupname = NULL; 285 286 if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info)) 287 { 288 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 289 _dbus_group_info_free_allocated (info); 290 return NULL; 291 } 292 293 294 if (!_dbus_hash_table_insert_string (db->groups_by_name, 295 info->groupname, 296 info)) 297 { 298 _dbus_hash_table_remove_ulong (db->groups, info->gid); 299 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 300 return NULL; 301 } 302 303 return info; 304 } 305 } 306 307 308 /** 309 * Gets the user information for the given group name, 310 * returned group info should not be freed. 311 * 312 * @param db user database 313 * @param groupname the group name 314 * @param info return location for const ref to group info 315 * @param error error location 316 * @returns #FALSE if error is set 317 */ 318 dbus_bool_t 319 _dbus_user_database_get_groupname (DBusUserDatabase *db, 320 const DBusString *groupname, 321 const DBusGroupInfo **info, 322 DBusError *error) 323 { 324 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); 325 return *info != NULL; 326 } 327 328 /** 329 * Gets the user information for the given GID, 330 * returned group info should not be freed. 331 * 332 * @param db user database 333 * @param gid the group ID 334 * @param info return location for const ref to group info 335 * @param error error location 336 * @returns #FALSE if error is set 337 */ 338 dbus_bool_t 339 _dbus_user_database_get_gid (DBusUserDatabase *db, 340 dbus_gid_t gid, 341 const DBusGroupInfo **info, 342 DBusError *error) 343 { 344 *info = _dbus_user_database_lookup_group (db, gid, NULL, error); 345 return *info != NULL; 346 } 347 348 349 /** 350 * Gets all groups for a particular user. Returns #FALSE 351 * if no memory, or user isn't known, but always initializes 352 * group_ids to a NULL array. Sets error to the reason 353 * for returning #FALSE. 354 * 355 * @param db the user database object 356 * @param uid the user ID 357 * @param group_ids return location for array of group IDs 358 * @param n_group_ids return location for length of returned array 359 * @param error return location for error 360 * @returns #TRUE on success 361 */ 362 dbus_bool_t 363 _dbus_user_database_get_groups (DBusUserDatabase *db, 364 dbus_uid_t uid, 365 dbus_gid_t **group_ids, 366 int *n_group_ids, 367 DBusError *error) 368 { 369 DBusUserInfo *info; 370 371 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 372 373 *group_ids = NULL; 374 *n_group_ids = 0; 375 376 info = _dbus_user_database_lookup (db, uid, NULL, error); 377 if (info == NULL) 378 { 379 _DBUS_ASSERT_ERROR_IS_SET (error); 380 return FALSE; 381 } 382 383 if (info->n_group_ids > 0) 384 { 385 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids); 386 if (*group_ids == NULL) 387 { 388 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 389 return FALSE; 390 } 391 392 *n_group_ids = info->n_group_ids; 393 394 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t)); 395 } 396 397 return TRUE; 398 } 399 400 /** @} */ 401 402 #ifdef DBUS_BUILD_TESTS 403 #include <stdio.h> 404 405 /** 406 * Unit test for dbus-userdb.c. 407 * 408 * @returns #TRUE on success. 409 */ 410 dbus_bool_t 411 _dbus_userdb_test (const char *test_data_dir) 412 { 413 const DBusString *username; 414 const DBusString *homedir; 415 416 if (!_dbus_username_from_current_process (&username)) 417 _dbus_assert_not_reached ("didn't get username"); 418 419 if (!_dbus_homedir_from_current_process (&homedir)) 420 _dbus_assert_not_reached ("didn't get homedir"); 421 422 printf (" Current user: %s homedir: %s\n", 423 _dbus_string_get_const_data (username), 424 _dbus_string_get_const_data (homedir)); 425 426 return TRUE; 427 } 428 #endif /* DBUS_BUILD_TESTS */ 429