D-Bus  1.6.12
dbus-userdb.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-userdb.c User database abstraction
3  *
4  * Copyright (C) 2003, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 #include <config.h>
24 #define DBUS_USERDB_INCLUDES_PRIVATE 1
25 #include "dbus-userdb.h"
26 #include "dbus-hash.h"
27 #include "dbus-test.h"
28 #include "dbus-internals.h"
29 #include "dbus-protocol.h"
30 #include "dbus-credentials.h"
31 #include <string.h>
32 
44 void
46 {
47  if (info == NULL) /* hash table will pass NULL */
48  return;
49 
50  _dbus_user_info_free (info);
51  dbus_free (info);
52 }
53 
60 void
62 {
63  if (info == NULL) /* hash table will pass NULL */
64  return;
65 
66  _dbus_group_info_free (info);
67  dbus_free (info);
68 }
69 
75 void
77 {
78  dbus_free (info->group_ids);
79  dbus_free (info->username);
80  dbus_free (info->homedir);
81 }
82 
88 void
90 {
91  dbus_free (info->groupname);
92 }
93 
104  unsigned long *num)
105 {
106  int end;
107 
108  if (_dbus_string_parse_uint (str, 0, num, &end) &&
109  end == _dbus_string_get_length (str))
110  return TRUE;
111  else
112  return FALSE;
113 }
114 
128 _dbus_user_database_lookup (DBusUserDatabase *db,
129  dbus_uid_t uid,
130  const DBusString *username,
131  DBusError *error)
132 {
133  DBusUserInfo *info;
134 
135  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
136  _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
137 
138  /* See if the username is really a number */
139  if (uid == DBUS_UID_UNSET)
140  {
141  unsigned long n;
142 
143  if (_dbus_is_a_number (username, &n))
144  uid = n;
145  }
146 
147 #ifdef DBUS_ENABLE_USERDB_CACHE
148  if (uid != DBUS_UID_UNSET)
149  info = _dbus_hash_table_lookup_uintptr (db->users, uid);
150  else
151  info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
152 
153  if (info)
154  {
155  _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
156  info->uid);
157  return info;
158  }
159  else
160 #else
161  if (1)
162 #endif
163  {
164  if (uid != DBUS_UID_UNSET)
165  _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
166  uid);
167  else
168  _dbus_verbose ("No cache for user \"%s\"\n",
169  _dbus_string_get_const_data (username));
170 
171  info = dbus_new0 (DBusUserInfo, 1);
172  if (info == NULL)
173  {
175  return NULL;
176  }
177 
178  if (uid != DBUS_UID_UNSET)
179  {
180  if (!_dbus_user_info_fill_uid (info, uid, error))
181  {
182  _DBUS_ASSERT_ERROR_IS_SET (error);
184  return NULL;
185  }
186  }
187  else
188  {
189  if (!_dbus_user_info_fill (info, username, error))
190  {
191  _DBUS_ASSERT_ERROR_IS_SET (error);
193  return NULL;
194  }
195  }
196 
197  /* be sure we don't use these after here */
198  uid = DBUS_UID_UNSET;
199  username = NULL;
200 
201  /* insert into hash */
202  if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info))
203  {
206  return NULL;
207  }
208 
209  if (!_dbus_hash_table_insert_string (db->users_by_name,
210  info->username,
211  info))
212  {
213  _dbus_hash_table_remove_uintptr (db->users, info->uid);
215  return NULL;
216  }
217 
218  return info;
219  }
220 }
221 
222 static dbus_bool_t database_locked = FALSE;
223 static DBusUserDatabase *system_db = NULL;
224 static DBusString process_username;
225 static DBusString process_homedir;
226 
227 static void
228 shutdown_system_db (void *data)
229 {
230  if (system_db != NULL)
231  _dbus_user_database_unref (system_db);
232  system_db = NULL;
233  _dbus_string_free (&process_username);
234  _dbus_string_free (&process_homedir);
235 }
236 
237 static dbus_bool_t
238 init_system_db (void)
239 {
240  _dbus_assert (database_locked);
241 
242  if (system_db == NULL)
243  {
244  DBusError error = DBUS_ERROR_INIT;
245  const DBusUserInfo *info;
246 
247  system_db = _dbus_user_database_new ();
248  if (system_db == NULL)
249  return FALSE;
250 
251  if (!_dbus_user_database_get_uid (system_db,
252  _dbus_getuid (),
253  &info,
254  &error))
255  {
256  _dbus_user_database_unref (system_db);
257  system_db = NULL;
258 
260  {
261  dbus_error_free (&error);
262  return FALSE;
263  }
264  else
265  {
266  /* This really should not happen. */
267  _dbus_warn ("Could not get password database information for UID of current process: %s\n",
268  error.message);
269  dbus_error_free (&error);
270  return FALSE;
271  }
272  }
273 
274  if (!_dbus_string_init (&process_username))
275  {
276  _dbus_user_database_unref (system_db);
277  system_db = NULL;
278  return FALSE;
279  }
280 
281  if (!_dbus_string_init (&process_homedir))
282  {
283  _dbus_string_free (&process_username);
284  _dbus_user_database_unref (system_db);
285  system_db = NULL;
286  return FALSE;
287  }
288 
289  if (!_dbus_string_append (&process_username,
290  info->username) ||
291  !_dbus_string_append (&process_homedir,
292  info->homedir) ||
293  !_dbus_register_shutdown_func (shutdown_system_db, NULL))
294  {
295  _dbus_string_free (&process_username);
296  _dbus_string_free (&process_homedir);
297  _dbus_user_database_unref (system_db);
298  system_db = NULL;
299  return FALSE;
300  }
301  }
302 
303  return TRUE;
304 }
305 
309 void
311 {
312  _DBUS_LOCK (system_users);
313  database_locked = TRUE;
314 }
315 
319 void
321 {
322  database_locked = FALSE;
323  _DBUS_UNLOCK (system_users);
324 }
325 
332 DBusUserDatabase*
334 {
335  _dbus_assert (database_locked);
336 
337  init_system_db ();
338 
339  return system_db;
340 }
341 
345 void
347 {
349 
350  if (system_db != NULL)
351  _dbus_user_database_flush (system_db);
352 
354 }
355 
365 {
367  if (!init_system_db ())
368  {
370  return FALSE;
371  }
372  *username = &process_username;
374 
375  return TRUE;
376 }
377 
387 {
389  if (!init_system_db ())
390  {
392  return FALSE;
393  }
394  *homedir = &process_homedir;
396 
397  return TRUE;
398 }
399 
409  DBusString *homedir)
410 {
411  DBusUserDatabase *db;
412  const DBusUserInfo *info;
414 
416  if (db == NULL)
417  {
419  return FALSE;
420  }
421 
422  if (!_dbus_user_database_get_username (db, username,
423  &info, NULL))
424  {
426  return FALSE;
427  }
428 
429  if (!_dbus_string_append (homedir, info->homedir))
430  {
432  return FALSE;
433  }
434 
436  return TRUE;
437 }
438 
448  DBusString *homedir)
449 {
450  DBusUserDatabase *db;
451  const DBusUserInfo *info;
453 
455  if (db == NULL)
456  {
458  return FALSE;
459  }
460 
461  if (!_dbus_user_database_get_uid (db, uid,
462  &info, NULL))
463  {
465  return FALSE;
466  }
467 
468  if (!_dbus_string_append (homedir, info->homedir))
469  {
471  return FALSE;
472  }
473 
475  return TRUE;
476 }
477 
494  const DBusString *username)
495 {
496  DBusUserDatabase *db;
497  const DBusUserInfo *info;
498 
500 
502  if (db == NULL)
503  {
505  return FALSE;
506  }
507 
508  if (!_dbus_user_database_get_username (db, username,
509  &info, NULL))
510  {
512  return FALSE;
513  }
514 
515  if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
516  {
518  return FALSE;
519  }
520 
522  return TRUE;
523 }
524 
530 DBusUserDatabase*
532 {
533  DBusUserDatabase *db;
534 
535  db = dbus_new0 (DBusUserDatabase, 1);
536  if (db == NULL)
537  return NULL;
538 
539  db->refcount = 1;
540 
543 
544  if (db->users == NULL)
545  goto failed;
546 
549 
550  if (db->groups == NULL)
551  goto failed;
552 
553  db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
554  NULL, NULL);
555  if (db->users_by_name == NULL)
556  goto failed;
557 
558  db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
559  NULL, NULL);
560  if (db->groups_by_name == NULL)
561  goto failed;
562 
563  return db;
564 
565  failed:
567  return NULL;
568 }
569 
573 void
574 _dbus_user_database_flush (DBusUserDatabase *db)
575 {
576  _dbus_hash_table_remove_all(db->users_by_name);
577  _dbus_hash_table_remove_all(db->groups_by_name);
578  _dbus_hash_table_remove_all(db->users);
579  _dbus_hash_table_remove_all(db->groups);
580 }
581 
582 #ifdef DBUS_BUILD_TESTS
583 
588 DBusUserDatabase *
589 _dbus_user_database_ref (DBusUserDatabase *db)
590 {
591  _dbus_assert (db->refcount > 0);
592 
593  db->refcount += 1;
594 
595  return db;
596 }
597 #endif /* DBUS_BUILD_TESTS */
598 
603 void
604 _dbus_user_database_unref (DBusUserDatabase *db)
605 {
606  _dbus_assert (db->refcount > 0);
607 
608  db->refcount -= 1;
609  if (db->refcount == 0)
610  {
611  if (db->users)
612  _dbus_hash_table_unref (db->users);
613 
614  if (db->groups)
615  _dbus_hash_table_unref (db->groups);
616 
617  if (db->users_by_name)
618  _dbus_hash_table_unref (db->users_by_name);
619 
620  if (db->groups_by_name)
621  _dbus_hash_table_unref (db->groups_by_name);
622 
623  dbus_free (db);
624  }
625 }
626 
638 _dbus_user_database_get_uid (DBusUserDatabase *db,
639  dbus_uid_t uid,
640  const DBusUserInfo **info,
641  DBusError *error)
642 {
643  *info = _dbus_user_database_lookup (db, uid, NULL, error);
644  return *info != NULL;
645 }
646 
657 _dbus_user_database_get_username (DBusUserDatabase *db,
658  const DBusString *username,
659  const DBusUserInfo **info,
660  DBusError *error)
661 {
662  *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
663  return *info != NULL;
664 }
665 
668 /* Tests in dbus-userdb-util.c */
dbus_bool_t dbus_error_has_name(const DBusError *error, const char *name)
Checks whether the error is set and has the given name.
Definition: dbus-errors.c:302
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
Definition: dbus-string.c:913
const char * message
public error message field
Definition: dbus-errors.h:51
char * username
Username.
#define NULL
A null pointer, defined appropriately for C or C++.
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory.
Definition: dbus-memory.h:64
void _dbus_user_database_lock_system(void)
Locks global system user database.
Definition: dbus-userdb.c:310
DBusUserInfo * _dbus_user_database_lookup(DBusUserDatabase *db, dbus_uid_t uid, const DBusString *username, DBusError *error)
Looks up a uid or username in the user database.
Definition: dbus-userdb.c:128
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:700
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack.
Definition: dbus-errors.h:62
void _dbus_user_database_flush_system(void)
Flushes the system global user database;.
Definition: dbus-userdb.c:346
void dbus_error_free(DBusError *error)
Frees an error that&#39;s been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
dbus_bool_t _dbus_homedir_from_username(const DBusString *username, DBusString *homedir)
Gets the home directory for the given user.
Definition: dbus-userdb.c:408
void _dbus_user_database_flush(DBusUserDatabase *db)
Flush all information out of the user database.
Definition: dbus-userdb.c:574
dbus_bool_t _dbus_user_database_get_uid(DBusUserDatabase *db, dbus_uid_t uid, const DBusUserInfo **info, DBusError *error)
Gets the user information for the given UID, returned user info should not be freed.
Definition: dbus-userdb.c:638
void _dbus_user_database_unlock_system(void)
Unlocks global system user database.
Definition: dbus-userdb.c:320
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
Hash keys are strings.
Definition: dbus-hash.h:69
void _dbus_hash_table_unref(DBusHashTable *table)
Decrements the reference count for a hash table, freeing the hash table if the count reaches zero...
Definition: dbus-hash.c:361
Hash keys are integer capable to hold a pointer.
Definition: dbus-hash.h:71
void _dbus_hash_table_remove_all(DBusHashTable *table)
Removed all entries from a hash table.
Definition: dbus-hash.c:418
char * groupname
Group name.
#define DBUS_UID_UNSET
an invalid UID used to represent an uninitialized dbus_uid_t field
Definition: dbus-sysdeps.h:107
void _dbus_user_info_free_allocated(DBusUserInfo *info)
Frees the given DBusUserInfo&#39;s members with _dbus_user_info_free() and also calls dbus_free() on the ...
Definition: dbus-userdb.c:45
dbus_bool_t _dbus_user_info_fill(DBusUserInfo *info, const DBusString *username, DBusError *error)
Gets user info for the given username.
DBusUserDatabase * _dbus_user_database_get_system(void)
Gets the system global user database; must be called with lock held (_dbus_user_database_lock_system(...
Definition: dbus-userdb.c:333
dbus_bool_t _dbus_homedir_from_uid(dbus_uid_t uid, DBusString *homedir)
Gets the home directory for the given user.
Definition: dbus-userdb.c:447
dbus_gid_t * group_ids
Groups IDs, including above primary group.
dbus_bool_t _dbus_is_a_number(const DBusString *str, unsigned long *num)
Checks if a given string is actually a number and converts it if it is.
Definition: dbus-userdb.c:103
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
void _dbus_group_info_free_allocated(DBusGroupInfo *info)
Frees the given DBusGroupInfo&#39;s members with _dbus_group_info_free() and also calls dbus_free() on th...
Definition: dbus-userdb.c:61
DBusHashTable * _dbus_hash_table_new(DBusHashType type, DBusFreeFunction key_free_function, DBusFreeFunction value_free_function)
Constructs a new hash table.
Definition: dbus-hash.c:285
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
dbus_uid_t uid
UID.
void _dbus_group_info_free(DBusGroupInfo *info)
Frees the members of info (but not info itself).
Definition: dbus-userdb.c:89
void * _dbus_hash_table_lookup_uintptr(DBusHashTable *table, uintptr_t key)
Looks up the value for a given integer in a hash table of type DBUS_HASH_UINTPTR. ...
Definition: dbus-hash.c:1099
void _dbus_user_info_free(DBusUserInfo *info)
Frees the members of info (but not info itself)
Definition: dbus-userdb.c:76
int _dbus_string_get_length(const DBusString *str)
Gets the length of a string (not including nul termination).
Definition: dbus-string.c:717
Object representing an exception.
Definition: dbus-errors.h:48
dbus_bool_t _dbus_hash_table_insert_string(DBusHashTable *table, char *key, void *value)
Creates a hash entry with the given key and value.
Definition: dbus-hash.c:1214
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
DBusUserDatabase * _dbus_user_database_new(void)
Creates a new user database object used to look up and cache user information.
Definition: dbus-userdb.c:531
#define _DBUS_UNLOCK(name)
Unlocks a global lock.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:242
#define TRUE
Expands to &quot;1&quot;.
dbus_bool_t _dbus_hash_table_insert_uintptr(DBusHashTable *table, uintptr_t key, void *value)
Creates a hash entry with the given key and value.
Definition: dbus-hash.c:1289
#define DBUS_UID_FORMAT
an appropriate printf format for dbus_uid_t
Definition: dbus-sysdeps.h:114
char * homedir
Home directory.
dbus_uid_t _dbus_getuid(void)
Gets our UID.
dbus_bool_t _dbus_homedir_from_current_process(const DBusString **homedir)
Gets homedir of user owning current process.
Definition: dbus-userdb.c:386
Information about a UNIX group.
dbus_bool_t _dbus_string_parse_uint(const DBusString *str, int start, unsigned long *value_return, int *end_return)
Parses an unsigned integer contained in a DBusString.
Definition: dbus-sysdeps.c:472
dbus_bool_t _dbus_user_info_fill_uid(DBusUserInfo *info, dbus_uid_t uid, DBusError *error)
Gets user info for the given user ID.
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
#define FALSE
Expands to &quot;0&quot;.
DBusCredentials * credentials
Credentials of other end read from the socket.
dbus_bool_t _dbus_hash_table_remove_uintptr(DBusHashTable *table, uintptr_t key)
Removes the hash entry for the given key.
Definition: dbus-hash.c:1179
dbus_bool_t _dbus_register_shutdown_func(DBusShutdownFunction function, void *data)
Register a cleanup function to be called exactly once the next time dbus_shutdown() is called...
Definition: dbus-memory.c:809
#define _DBUS_LOCK(name)
Locks a global lock.
dbus_bool_t _dbus_user_database_get_username(DBusUserDatabase *db, const DBusString *username, const DBusUserInfo **info, DBusError *error)
Gets the user information for the given username.
Definition: dbus-userdb.c:657
dbus_bool_t _dbus_credentials_add_unix_uid(DBusCredentials *credentials, dbus_uid_t uid)
Add a UNIX user ID to the credentials.
void _dbus_user_database_unref(DBusUserDatabase *db)
Decrements refcount of user database.
Definition: dbus-userdb.c:604
unsigned long dbus_uid_t
A user ID.
Definition: dbus-sysdeps.h:100
void * _dbus_hash_table_lookup_string(DBusHashTable *table, const char *key)
Looks up the value for a given string in a hash table of type DBUS_HASH_STRING.
Definition: dbus-hash.c:1049
const char * _dbus_string_get_const_data(const DBusString *str)
Gets the raw character buffer from a const string.
Definition: dbus-string.c:446
dbus_bool_t _dbus_username_from_current_process(const DBusString **username)
Gets username of user owning current process.
Definition: dbus-userdb.c:364
Information about a UNIX user.
dbus_bool_t _dbus_credentials_add_from_user(DBusCredentials *credentials, const DBusString *username)
Adds the credentials corresponding to the given username.