D-Bus  1.10.24
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  if (uid != DBUS_UID_UNSET)
148  info = _dbus_hash_table_lookup_uintptr (db->users, uid);
149  else
150  info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
151 
152  if (info)
153  {
154  _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
155  info->uid);
156  return info;
157  }
158  else
159  {
160  if (uid != DBUS_UID_UNSET)
161  _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
162  uid);
163  else
164  _dbus_verbose ("No cache for user \"%s\"\n",
165  _dbus_string_get_const_data (username));
166 
167  info = dbus_new0 (DBusUserInfo, 1);
168  if (info == NULL)
169  {
171  return NULL;
172  }
173 
174  if (uid != DBUS_UID_UNSET)
175  {
176  if (!_dbus_user_info_fill_uid (info, uid, error))
177  {
178  _DBUS_ASSERT_ERROR_IS_SET (error);
180  return NULL;
181  }
182  }
183  else
184  {
185  if (!_dbus_user_info_fill (info, username, error))
186  {
187  _DBUS_ASSERT_ERROR_IS_SET (error);
189  return NULL;
190  }
191  }
192 
193  /* be sure we don't use these after here */
194  uid = DBUS_UID_UNSET;
195  username = NULL;
196 
197  /* insert into hash */
198  if (!_dbus_hash_table_insert_uintptr (db->users, info->uid, info))
199  {
202  return NULL;
203  }
204 
205  if (!_dbus_hash_table_insert_string (db->users_by_name,
206  info->username,
207  info))
208  {
209  _dbus_hash_table_remove_uintptr (db->users, info->uid);
211  return NULL;
212  }
213 
214  return info;
215  }
216 }
217 
218 static dbus_bool_t database_locked = FALSE;
219 static DBusUserDatabase *system_db = NULL;
220 static DBusString process_username;
221 static DBusString process_homedir;
222 
223 static void
224 shutdown_system_db (void *data)
225 {
226  if (system_db != NULL)
227  _dbus_user_database_unref (system_db);
228  system_db = NULL;
229  _dbus_string_free (&process_username);
230  _dbus_string_free (&process_homedir);
231 }
232 
233 static dbus_bool_t
234 init_system_db (void)
235 {
236  _dbus_assert (database_locked);
237 
238  if (system_db == NULL)
239  {
240  DBusError error = DBUS_ERROR_INIT;
241  const DBusUserInfo *info;
242 
243  system_db = _dbus_user_database_new ();
244  if (system_db == NULL)
245  return FALSE;
246 
247  if (!_dbus_user_database_get_uid (system_db,
248  _dbus_getuid (),
249  &info,
250  &error))
251  {
252  _dbus_user_database_unref (system_db);
253  system_db = NULL;
254 
256  {
257  dbus_error_free (&error);
258  return FALSE;
259  }
260  else
261  {
262  /* This really should not happen. */
263  _dbus_warn ("Could not get password database information for UID of current process: %s\n",
264  error.message);
265  dbus_error_free (&error);
266  return FALSE;
267  }
268  }
269 
270  if (!_dbus_string_init (&process_username))
271  {
272  _dbus_user_database_unref (system_db);
273  system_db = NULL;
274  return FALSE;
275  }
276 
277  if (!_dbus_string_init (&process_homedir))
278  {
279  _dbus_string_free (&process_username);
280  _dbus_user_database_unref (system_db);
281  system_db = NULL;
282  return FALSE;
283  }
284 
285  if (!_dbus_string_append (&process_username,
286  info->username) ||
287  !_dbus_string_append (&process_homedir,
288  info->homedir) ||
289  !_dbus_register_shutdown_func (shutdown_system_db, NULL))
290  {
291  _dbus_string_free (&process_username);
292  _dbus_string_free (&process_homedir);
293  _dbus_user_database_unref (system_db);
294  system_db = NULL;
295  return FALSE;
296  }
297  }
298 
299  return TRUE;
300 }
301 
307 {
308  if (_DBUS_LOCK (system_users))
309  {
310  database_locked = TRUE;
311  return TRUE;
312  }
313  else
314  {
315  return FALSE;
316  }
317 }
318 
322 void
324 {
325  database_locked = FALSE;
326  _DBUS_UNLOCK (system_users);
327 }
328 
335 DBusUserDatabase*
337 {
338  _dbus_assert (database_locked);
339 
340  init_system_db ();
341 
342  return system_db;
343 }
344 
348 void
350 {
352  {
353  /* nothing to flush */
354  return;
355  }
356 
357  if (system_db != NULL)
358  _dbus_user_database_flush (system_db);
359 
361 }
362 
372 {
374  return FALSE;
375 
376  if (!init_system_db ())
377  {
379  return FALSE;
380  }
381  *username = &process_username;
383 
384  return TRUE;
385 }
386 
396 {
398  return FALSE;
399 
400  if (!init_system_db ())
401  {
403  return FALSE;
404  }
405  *homedir = &process_homedir;
407 
408  return TRUE;
409 }
410 
420  DBusString *homedir)
421 {
422  DBusUserDatabase *db;
423  const DBusUserInfo *info;
424 
425  /* FIXME: this can't distinguish ENOMEM from other errors */
427  return FALSE;
428 
430  if (db == NULL)
431  {
433  return FALSE;
434  }
435 
436  if (!_dbus_user_database_get_username (db, username,
437  &info, NULL))
438  {
440  return FALSE;
441  }
442 
443  if (!_dbus_string_append (homedir, info->homedir))
444  {
446  return FALSE;
447  }
448 
450  return TRUE;
451 }
452 
462  DBusString *homedir)
463 {
464  DBusUserDatabase *db;
465  const DBusUserInfo *info;
466 
467  /* FIXME: this can't distinguish ENOMEM from other errors */
469  return FALSE;
470 
472  if (db == NULL)
473  {
475  return FALSE;
476  }
477 
478  if (!_dbus_user_database_get_uid (db, uid,
479  &info, NULL))
480  {
482  return FALSE;
483  }
484 
485  if (!_dbus_string_append (homedir, info->homedir))
486  {
488  return FALSE;
489  }
490 
492  return TRUE;
493 }
494 
511  const DBusString *username)
512 {
513  DBusUserDatabase *db;
514  const DBusUserInfo *info;
515 
516  /* FIXME: this can't distinguish ENOMEM from other errors */
518  return FALSE;
519 
521  if (db == NULL)
522  {
524  return FALSE;
525  }
526 
527  if (!_dbus_user_database_get_username (db, username,
528  &info, NULL))
529  {
531  return FALSE;
532  }
533 
534  if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
535  {
537  return FALSE;
538  }
539 
541  return TRUE;
542 }
543 
549 DBusUserDatabase*
551 {
552  DBusUserDatabase *db;
553 
554  db = dbus_new0 (DBusUserDatabase, 1);
555  if (db == NULL)
556  return NULL;
557 
558  db->refcount = 1;
559 
562 
563  if (db->users == NULL)
564  goto failed;
565 
568 
569  if (db->groups == NULL)
570  goto failed;
571 
572  db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
573  NULL, NULL);
574  if (db->users_by_name == NULL)
575  goto failed;
576 
577  db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
578  NULL, NULL);
579  if (db->groups_by_name == NULL)
580  goto failed;
581 
582  return db;
583 
584  failed:
586  return NULL;
587 }
588 
592 void
593 _dbus_user_database_flush (DBusUserDatabase *db)
594 {
595  _dbus_hash_table_remove_all(db->users_by_name);
596  _dbus_hash_table_remove_all(db->groups_by_name);
597  _dbus_hash_table_remove_all(db->users);
598  _dbus_hash_table_remove_all(db->groups);
599 }
600 
601 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
602 
607 DBusUserDatabase *
608 _dbus_user_database_ref (DBusUserDatabase *db)
609 {
610  _dbus_assert (db->refcount > 0);
611 
612  db->refcount += 1;
613 
614  return db;
615 }
616 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
617 
622 void
623 _dbus_user_database_unref (DBusUserDatabase *db)
624 {
625  _dbus_assert (db->refcount > 0);
626 
627  db->refcount -= 1;
628  if (db->refcount == 0)
629  {
630  if (db->users)
631  _dbus_hash_table_unref (db->users);
632 
633  if (db->groups)
634  _dbus_hash_table_unref (db->groups);
635 
636  if (db->users_by_name)
637  _dbus_hash_table_unref (db->users_by_name);
638 
639  if (db->groups_by_name)
640  _dbus_hash_table_unref (db->groups_by_name);
641 
642  dbus_free (db);
643  }
644 }
645 
657 _dbus_user_database_get_uid (DBusUserDatabase *db,
658  dbus_uid_t uid,
659  const DBusUserInfo **info,
660  DBusError *error)
661 {
662  *info = _dbus_user_database_lookup (db, uid, NULL, error);
663  return *info != NULL;
664 }
665 
676 _dbus_user_database_get_username (DBusUserDatabase *db,
677  const DBusString *username,
678  const DBusUserInfo **info,
679  DBusError *error)
680 {
681  *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
682  return *info != NULL;
683 }
684 
687 /* 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:935
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
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
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:701
dbus_bool_t _dbus_user_database_lock_system(void)
Locks global system user database.
Definition: dbus-userdb.c:306
#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:349
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:419
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
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
void _dbus_user_database_flush(DBusUserDatabase *db)
Flush all information out of the user database.
Definition: dbus-userdb.c:593
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:657
void _dbus_user_database_unlock_system(void)
Unlocks global system user database.
Definition: dbus-userdb.c:323
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
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:114
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:336
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:461
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
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_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
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_user_info_free(DBusUserInfo *info)
Frees the members of info (but not info itself)
Definition: dbus-userdb.c:76
Object representing an exception.
Definition: dbus-errors.h:48
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:550
#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:259
#define TRUE
Expands to &quot;1&quot;.
#define DBUS_UID_FORMAT
an appropriate printf format for dbus_uid_t
Definition: dbus-sysdeps.h:121
char * homedir
Home directory.
dbus_bool_t _dbus_homedir_from_current_process(const DBusString **homedir)
Gets homedir of user owning current process.
Definition: dbus-userdb.c:395
Information about a UNIX group.
DBUS_PRIVATE_EXPORT 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:474
dbus_uid_t _dbus_getuid(void)
Gets our UID.
dbus_bool_t _dbus_user_info_fill_uid(DBusUserInfo *info, dbus_uid_t uid, DBusError *error)
Gets user info for the given user ID.
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
#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_PRIVATE_EXPORT 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:810
#define _DBUS_LOCK(name)
Locks a global lock, initializing it first if necessary.
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:676
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:623
unsigned long dbus_uid_t
A user ID.
Definition: dbus-sysdeps.h:107
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_username_from_current_process(const DBusString **username)
Gets username of user owning current process.
Definition: dbus-userdb.c:371
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
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.