D-Bus  1.6.18
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 */