D-Bus 1.16.2
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 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 */
25#include <config.h>
26#include <unistd.h>
27#define DBUS_USERDB_INCLUDES_PRIVATE 1
28#include "dbus-userdb.h"
29#include "dbus-test.h"
30#include "dbus-internals.h"
31#include "dbus-protocol.h"
32#include <dbus/dbus-test-tap.h>
33#include <string.h>
34
35/* It isn't obvious from its name, but this file is part of the Unix
36 * system-dependent part of libdbus. */
37#if defined(DBUS_WIN) || !defined(DBUS_UNIX)
38#error "This file only makes sense on Unix OSs"
39#endif
40
41#ifdef HAVE_SYSTEMD
42#include <systemd/sd-login.h>
43#endif
44
45#ifdef HAVE_ELOGIND
46#include <elogind/sd-login.h>
47#endif
48
53
54static DBusGroupInfo *
55_dbus_group_info_ref (DBusGroupInfo *info)
56{
57 _dbus_assert (info->refcount > 0);
58 _dbus_assert (info->refcount < SIZE_MAX);
59 info->refcount++;
60 return info;
61}
62
72 DBusError *error)
73{
74#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
75 /* check if we have logind */
76 if (access ("/run/systemd/seats/", F_OK) >= 0)
77 {
78 int r;
79
80 /* Check whether this user is logged in on at least one physical
81 seat */
82 r = sd_uid_get_seats (uid, 0, NULL);
83 if (r < 0)
84 {
86 "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
87 uid,
88 _dbus_strerror (-r));
89 return FALSE;
90 }
91
92 return (r > 0);
93 }
94#endif
95
96#ifdef HAVE_CONSOLE_OWNER_FILE
97
98 DBusString f;
99 DBusStat st;
100
101 if (!_dbus_string_init (&f))
102 {
103 _DBUS_SET_OOM (error);
104 return FALSE;
105 }
106
107 if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
108 {
110 _DBUS_SET_OOM (error);
111 return FALSE;
112 }
113
114 if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
115 {
117 return TRUE;
118 }
119
121
122#endif /* HAVE_CONSOLE_OWNER_FILE */
123
124 return FALSE;
125}
126
136 dbus_uid_t *uid)
137{
138 return _dbus_get_user_id_and_primary_group (username, uid, NULL);
139}
140
150 dbus_gid_t *gid)
151{
152 DBusUserDatabase *db;
153 const DBusGroupInfo *info;
154
155 /* FIXME: this can't distinguish ENOMEM from other errors */
157 return FALSE;
158
160 if (db == NULL)
161 {
163 return FALSE;
164 }
165
167 NULL);
168
169 if (info == NULL)
170 {
172 return FALSE;
173 }
174
175 *gid = info->gid;
176
178 return TRUE;
179}
180
191 dbus_uid_t *uid_p,
192 dbus_gid_t *gid_p)
193{
194 DBusUserDatabase *db;
195 const DBusUserInfo *info;
196
197 /* FIXME: this can't distinguish ENOMEM from other errors */
199 return FALSE;
200
202 if (db == NULL)
203 {
205 return FALSE;
206 }
207
208 if (!_dbus_user_database_get_username (db, username,
209 &info, NULL))
210 {
212 return FALSE;
213 }
214
215 if (uid_p)
216 *uid_p = info->uid;
217 if (gid_p)
218 *gid_p = info->primary_gid;
219
221 return TRUE;
222}
223
236const DBusGroupInfo *
238 dbus_gid_t gid,
239 const DBusString *groupname,
240 DBusError *error)
241{
242 DBusGroupInfo *info;
243
244 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
245
246 /* See if the group is really a number */
247 if (gid == DBUS_UID_UNSET)
248 {
249 unsigned long n;
250
251 if (_dbus_is_a_number (groupname, &n))
252 gid = n;
253 }
254
255 if (gid != DBUS_GID_UNSET)
256 info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
257 else
258 info = _dbus_hash_table_lookup_string (db->groups_by_name,
259 _dbus_string_get_const_data (groupname));
260 if (info)
261 {
262 _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
263 info->gid);
264 return info;
265 }
266 else
267 {
268 if (gid != DBUS_GID_UNSET)
269 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
270 gid);
271 else
272 _dbus_verbose ("No cache for groupname \"%s\"\n",
273 _dbus_string_get_const_data (groupname));
274
275 info = dbus_new0 (DBusGroupInfo, 1);
276 if (info == NULL)
277 {
279 return NULL;
280 }
281 info->refcount = 1;
282
283 if (gid != DBUS_GID_UNSET)
284 {
285 if (!_dbus_group_info_fill_gid (info, gid, error))
286 {
287 _DBUS_ASSERT_ERROR_IS_SET (error);
289 return NULL;
290 }
291 }
292 else
293 {
294 if (!_dbus_group_info_fill (info, groupname, error))
295 {
296 _DBUS_ASSERT_ERROR_IS_SET (error);
298 return NULL;
299 }
300 }
301
302 /* don't use these past here */
303 gid = DBUS_GID_UNSET;
304 groupname = NULL;
305
306 if (_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
307 {
308 _dbus_group_info_ref (info);
309 }
310 else
311 {
314 return NULL;
315 }
316
317
318 if (_dbus_hash_table_insert_string (db->groups_by_name,
319 info->groupname,
320 info))
321 {
322 _dbus_group_info_ref (info);
323 }
324 else
325 {
326 _dbus_hash_table_remove_uintptr (db->groups, info->gid);
329 return NULL;
330 }
331
332 /* Release the original reference */
334
335 /* Return a borrowed reference to the DBusGroupInfo owned by the
336 * two hash tables */
337 return info;
338 }
339}
340
354 dbus_gid_t **group_ids,
355 int *n_group_ids,
356 DBusError *error)
357{
358 DBusUserDatabase *db;
359 const DBusUserInfo *info;
360 dbus_bool_t ret = FALSE;
361
362 *group_ids = NULL;
363 *n_group_ids = 0;
364
366 {
367 _DBUS_SET_OOM (error);
368 return FALSE;
369 }
370
372 if (db == NULL)
373 {
374 _DBUS_SET_OOM (error);
375 goto out;
376 }
377
378 if (!_dbus_user_database_get_uid (db, uid, &info, error))
379 goto out;
380
381 _dbus_assert (info->uid == uid);
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_OOM (error);
389 goto out;
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 ret = TRUE;
398out:
399 _DBUS_ASSERT_ERROR_XOR_BOOL (error, ret);
401 return ret;
402}
403
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
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:1243
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:1278
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:1163
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:1113
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:1353
dbus_bool_t _dbus_stat(const DBusString *filename, DBusStat *statbuf, DBusError *error)
stat() wrapper.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
dbus_bool_t _dbus_user_database_lock_system(void)
Locks global system user database.
const char * _dbus_error_from_errno(int error_number)
Converts a UNIX errno, or Windows errno or WinSock error value into a DBusError name.
void _dbus_user_database_unlock_system(void)
Unlocks global system user database.
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.
dbus_bool_t _dbus_get_group_id(const DBusString *groupname, dbus_gid_t *gid)
Gets group ID given groupname.
void _dbus_group_info_unref(DBusGroupInfo *info)
Decrements the reference count.
Definition dbus-userdb.c:87
dbus_bool_t _dbus_is_console_user(dbus_uid_t uid, DBusError *error)
Checks to see if the UID sent in is the console user.
const DBusGroupInfo * _dbus_user_database_lookup_group(DBusUserDatabase *db, dbus_gid_t gid, const DBusString *groupname, DBusError *error)
Looks up a gid or group name in the user database.
dbus_bool_t _dbus_groups_from_uid(dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids, DBusError *error)
Gets all groups corresponding to the given UID.
dbus_bool_t _dbus_get_user_id_and_primary_group(const DBusString *username, dbus_uid_t *uid_p, dbus_gid_t *gid_p)
Gets user ID and primary group given username.
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.
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.
dbus_bool_t _dbus_get_user_id(const DBusString *username, dbus_uid_t *uid)
Gets user ID 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(...
#define NULL
A null pointer, defined appropriately for C or C++.
Definition dbus-macros.h:51
#define TRUE
Expands to "1".
Definition dbus-macros.h:41
#define FALSE
Expands to "0".
Definition dbus-macros.h:44
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition dbus-memory.h:59
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition dbus-memory.h:60
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as _DBUS_STRING_IN...
dbus_bool_t _dbus_group_info_fill(DBusGroupInfo *info, const DBusString *groupname, DBusError *error)
Initializes the given DBusGroupInfo struct with information about the given group name.
dbus_bool_t _dbus_group_info_fill_gid(DBusGroupInfo *info, dbus_gid_t gid, DBusError *error)
Initializes the given DBusGroupInfo struct with information about the given group ID.
unsigned long dbus_uid_t
A user ID.
unsigned long dbus_gid_t
A group ID.
#define DBUS_UID_UNSET
an invalid UID used to represent an uninitialized dbus_uid_t field
#define DBUS_GID_UNSET
an invalid GID used to represent an uninitialized dbus_gid_t field
#define DBUS_GID_FORMAT
an appropriate printf format for dbus_gid_t
#define DBUS_UID_FORMAT
an appropriate printf format for dbus_uid_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition dbus-types.h:37
Object representing an exception.
Definition dbus-errors.h:51
Information about a UNIX group.
dbus_gid_t gid
GID.
char * groupname
Group name.
size_t refcount
Reference count.
Portable struct with stat() results.
dbus_uid_t uid
User owning file.
Information about a UNIX user.
int n_group_ids
Size of group IDs array.
dbus_uid_t uid
UID.
dbus_gid_t * group_ids
Groups IDs, including above primary group.
dbus_gid_t primary_gid
GID.