D-Bus  1.6.12
dbus-userdb-util.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
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., 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-test.h"
27 #include "dbus-internals.h"
28 #include "dbus-protocol.h"
29 #include <string.h>
30 
31 #if HAVE_SYSTEMD
32 #include <systemd/sd-daemon.h>
33 #include <systemd/sd-login.h>
34 #endif
35 
50  DBusError *error)
51 {
52 
53  DBusUserDatabase *db;
54  const DBusUserInfo *info;
55  dbus_bool_t result = FALSE;
56 
57 #ifdef HAVE_SYSTEMD
58  if (sd_booted () > 0)
59  {
60  int r;
61 
62  /* Check whether this user is logged in on at least one physical
63  seat */
64  r = sd_uid_get_seats (uid, 0, NULL);
65  if (r < 0)
66  {
68  "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
69  uid,
70  _dbus_strerror (-r));
71  return FALSE;
72  }
73 
74  return (r > 0);
75  }
76 #endif
77 
78 #ifdef HAVE_CONSOLE_OWNER_FILE
79 
80  DBusString f;
81  DBusStat st;
82 
83  if (!_dbus_string_init (&f))
84  {
85  _DBUS_SET_OOM (error);
86  return FALSE;
87  }
88 
89  if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
90  {
92  _DBUS_SET_OOM (error);
93  return FALSE;
94  }
95 
96  if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
97  {
99  return TRUE;
100  }
101 
102  _dbus_string_free(&f);
103 
104 #endif /* HAVE_CONSOLE_OWNER_FILE */
105 
107  {
108  _DBUS_SET_OOM (error);
109  return FALSE;
110  }
111 
113  if (db == NULL)
114  {
115  dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
117  return FALSE;
118  }
119 
120  /* TPTD: this should be cache-safe, we've locked the DB and
121  _dbus_user_at_console doesn't pass it on. */
122  info = _dbus_user_database_lookup (db, uid, NULL, error);
123 
124  if (info == NULL)
125  {
127  return FALSE;
128  }
129 
130  result = _dbus_user_at_console (info->username, error);
131 
133 
134  return result;
135 }
136 
145 _dbus_get_user_id (const DBusString *username,
146  dbus_uid_t *uid)
147 {
148  return _dbus_get_user_id_and_primary_group (username, uid, NULL);
149 }
150 
159 _dbus_get_group_id (const DBusString *groupname,
160  dbus_gid_t *gid)
161 {
162  DBusUserDatabase *db;
163  const DBusGroupInfo *info;
164 
165  /* FIXME: this can't distinguish ENOMEM from other errors */
167  return FALSE;
168 
170  if (db == NULL)
171  {
173  return FALSE;
174  }
175 
176  if (!_dbus_user_database_get_groupname (db, groupname,
177  &info, NULL))
178  {
180  return FALSE;
181  }
182 
183  *gid = info->gid;
184 
186  return TRUE;
187 }
188 
199  dbus_uid_t *uid_p,
200  dbus_gid_t *gid_p)
201 {
202  DBusUserDatabase *db;
203  const DBusUserInfo *info;
204 
205  /* FIXME: this can't distinguish ENOMEM from other errors */
207  return FALSE;
208 
210  if (db == NULL)
211  {
213  return FALSE;
214  }
215 
216  if (!_dbus_user_database_get_username (db, username,
217  &info, NULL))
218  {
220  return FALSE;
221  }
222 
223  if (uid_p)
224  *uid_p = info->uid;
225  if (gid_p)
226  *gid_p = info->primary_gid;
227 
229  return TRUE;
230 }
231 
245 _dbus_user_database_lookup_group (DBusUserDatabase *db,
246  dbus_gid_t gid,
247  const DBusString *groupname,
248  DBusError *error)
249 {
250  DBusGroupInfo *info;
251 
252  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
253 
254  /* See if the group is really a number */
255  if (gid == DBUS_UID_UNSET)
256  {
257  unsigned long n;
258 
259  if (_dbus_is_a_number (groupname, &n))
260  gid = n;
261  }
262 
263 #ifdef DBUS_ENABLE_USERDB_CACHE
264  if (gid != DBUS_GID_UNSET)
265  info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
266  else
267  info = _dbus_hash_table_lookup_string (db->groups_by_name,
268  _dbus_string_get_const_data (groupname));
269  if (info)
270  {
271  _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
272  info->gid);
273  return info;
274  }
275  else
276 #else
277  if (1)
278 #endif
279  {
280  if (gid != DBUS_GID_UNSET)
281  _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
282  gid);
283  else
284  _dbus_verbose ("No cache for groupname \"%s\"\n",
285  _dbus_string_get_const_data (groupname));
286 
287  info = dbus_new0 (DBusGroupInfo, 1);
288  if (info == NULL)
289  {
291  return NULL;
292  }
293 
294  if (gid != DBUS_GID_UNSET)
295  {
296  if (!_dbus_group_info_fill_gid (info, gid, error))
297  {
298  _DBUS_ASSERT_ERROR_IS_SET (error);
300  return NULL;
301  }
302  }
303  else
304  {
305  if (!_dbus_group_info_fill (info, groupname, error))
306  {
307  _DBUS_ASSERT_ERROR_IS_SET (error);
309  return NULL;
310  }
311  }
312 
313  /* don't use these past here */
314  gid = DBUS_GID_UNSET;
315  groupname = NULL;
316 
317  if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
318  {
321  return NULL;
322  }
323 
324 
325  if (!_dbus_hash_table_insert_string (db->groups_by_name,
326  info->groupname,
327  info))
328  {
329  _dbus_hash_table_remove_uintptr (db->groups, info->gid);
331  return NULL;
332  }
333 
334  return info;
335  }
336 }
337 
338 
350 _dbus_user_database_get_groupname (DBusUserDatabase *db,
351  const DBusString *groupname,
352  const DBusGroupInfo **info,
353  DBusError *error)
354 {
355  *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
356  return *info != NULL;
357 }
358 
370 _dbus_user_database_get_gid (DBusUserDatabase *db,
371  dbus_gid_t gid,
372  const DBusGroupInfo **info,
373  DBusError *error)
374 {
375  *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
376  return *info != NULL;
377 }
378 
379 
392  dbus_gid_t **group_ids,
393  int *n_group_ids)
394 {
395  DBusUserDatabase *db;
396  const DBusUserInfo *info;
397  *group_ids = NULL;
398  *n_group_ids = 0;
399 
400  /* FIXME: this can't distinguish ENOMEM from other errors */
402  return FALSE;
403 
405  if (db == NULL)
406  {
408  return FALSE;
409  }
410 
411  if (!_dbus_user_database_get_uid (db, uid,
412  &info, NULL))
413  {
415  return FALSE;
416  }
417 
418  _dbus_assert (info->uid == uid);
419 
420  if (info->n_group_ids > 0)
421  {
422  *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
423  if (*group_ids == NULL)
424  {
426  return FALSE;
427  }
428 
429  *n_group_ids = info->n_group_ids;
430 
431  memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
432  }
433 
435  return TRUE;
436 }
439 #ifdef DBUS_BUILD_TESTS
440 #include <stdio.h>
441 
448 _dbus_userdb_test (const char *test_data_dir)
449 {
450  const DBusString *username;
451  const DBusString *homedir;
452  dbus_uid_t uid;
453  unsigned long *group_ids;
454  int n_group_ids, i;
455  DBusError error;
456 
457  if (!_dbus_username_from_current_process (&username))
458  _dbus_assert_not_reached ("didn't get username");
459 
460  if (!_dbus_homedir_from_current_process (&homedir))
461  _dbus_assert_not_reached ("didn't get homedir");
462 
463  if (!_dbus_get_user_id (username, &uid))
464  _dbus_assert_not_reached ("didn't get uid");
465 
466  if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
467  _dbus_assert_not_reached ("didn't get groups");
468 
469  printf (" Current user: %s homedir: %s gids:",
470  _dbus_string_get_const_data (username),
471  _dbus_string_get_const_data (homedir));
472 
473  for (i=0; i<n_group_ids; i++)
474  printf(" %ld", group_ids[i]);
475 
476  printf ("\n");
477 
478  dbus_error_init (&error);
479  printf ("Is Console user: %i\n",
480  _dbus_is_console_user (uid, &error));
481  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
482  dbus_error_free (&error);
483  printf ("Is Console user 4711: %i\n",
484  _dbus_is_console_user (4711, &error));
485  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
486  dbus_error_free (&error);
487 
488  dbus_free (group_ids);
489 
490  return TRUE;
491 }
492 #endif /* DBUS_BUILD_TESTS */