D-Bus 1.12.4

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#include <unistd.h>
25#define DBUS_USERDB_INCLUDES_PRIVATE 1
26#include "dbus-userdb.h"
27#include "dbus-test.h"
28#include "dbus-internals.h"
29#include "dbus-protocol.h"
30#include <string.h>
31
32#ifdef HAVE_SYSTEMD
33#include <systemd/sd-login.h>
34#endif
35
48 dbus_bool_t
49_dbus_is_console_user (dbus_uid_t uid,
50 DBusError *error)
51{
52
53 DBusUserDatabase *db;
54 const DBusUserInfo *info;
55 dbus_bool_t result = FALSE;
56
57#ifdef HAVE_SYSTEMD
58 /* check if we have logind */
59 if (access ("/run/systemd/seats/", F_OK) >= 0)
60 {
61 int r;
62
63 /* Check whether this user is logged in on at least one physical
64 seat */
65 r = sd_uid_get_seats (uid, 0, NULL);
66 if (r < 0)
67 {
68 dbus_set_error (error, _dbus_error_from_errno (-r),
69 "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
70 uid,
71 _dbus_strerror (-r));
72 return FALSE;
73 }
74
75 return (r > 0);
76 }
77#endif
78
79#ifdef HAVE_CONSOLE_OWNER_FILE
80
81 DBusString f;
82 DBusStat st;
83
84 if (!_dbus_string_init (&f))
85 {
86 _DBUS_SET_OOM (error);
87 return FALSE;
88 }
89
90 if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
91 {
92 _dbus_string_free(&f);
93 _DBUS_SET_OOM (error);
94 return FALSE;
95 }
96
97 if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
98 {
99 _dbus_string_free(&f);
100 return TRUE;
101 }
102
103 _dbus_string_free(&f);
104
105#endif /* HAVE_CONSOLE_OWNER_FILE */
106
107 if (!_dbus_user_database_lock_system ())
108 {
109 _DBUS_SET_OOM (error);
110 return FALSE;
111 }
112
113 db = _dbus_user_database_get_system ();
114 if (db == NULL)
115 {
116 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
117 _dbus_user_database_unlock_system ();
118 return FALSE;
119 }
120
121 /* TPTD: this should be cache-safe, we've locked the DB and
122 _dbus_user_at_console doesn't pass it on. */
123 info = _dbus_user_database_lookup (db, uid, NULL, error);
124
125 if (info == NULL)
126 {
127 _dbus_user_database_unlock_system ();
128 return FALSE;
129 }
130
131 result = _dbus_user_at_console (info->username, error);
132
133 _dbus_user_database_unlock_system ();
134
135 return result;
136}
137
145 dbus_bool_t
146_dbus_get_user_id (const DBusString *username,
147 dbus_uid_t *uid)
148{
149 return _dbus_get_user_id_and_primary_group (username, uid, NULL);
150}
151
159 dbus_bool_t
160_dbus_get_group_id (const DBusString *groupname,
161 dbus_gid_t *gid)
162{
163 DBusUserDatabase *db;
164 const DBusGroupInfo *info;
165
166 /* FIXME: this can't distinguish ENOMEM from other errors */
167 if (!_dbus_user_database_lock_system ())
168 return FALSE;
169
170 db = _dbus_user_database_get_system ();
171 if (db == NULL)
172 {
173 _dbus_user_database_unlock_system ();
174 return FALSE;
175 }
176
177 if (!_dbus_user_database_get_groupname (db, groupname,
178 &info, NULL))
179 {
180 _dbus_user_database_unlock_system ();
181 return FALSE;
182 }
183
184 *gid = info->gid;
185
186 _dbus_user_database_unlock_system ();
187 return TRUE;
188}
189
198 dbus_bool_t
199_dbus_get_user_id_and_primary_group (const DBusString *username,
200 dbus_uid_t *uid_p,
201 dbus_gid_t *gid_p)
202{
203 DBusUserDatabase *db;
204 const DBusUserInfo *info;
205
206 /* FIXME: this can't distinguish ENOMEM from other errors */
207 if (!_dbus_user_database_lock_system ())
208 return FALSE;
209
210 db = _dbus_user_database_get_system ();
211 if (db == NULL)
212 {
213 _dbus_user_database_unlock_system ();
214 return FALSE;
215 }
216
217 if (!_dbus_user_database_get_username (db, username,
218 &info, NULL))
219 {
220 _dbus_user_database_unlock_system ();
221 return FALSE;
222 }
223
224 if (uid_p)
225 *uid_p = info->uid;
226 if (gid_p)
227 *gid_p = info->primary_gid;
228
229 _dbus_user_database_unlock_system ();
230 return TRUE;
231}
232
245 DBusGroupInfo*
246_dbus_user_database_lookup_group (DBusUserDatabase *db,
247 dbus_gid_t gid,
248 const DBusString *groupname,
249 DBusError *error)
250{
251 DBusGroupInfo *info;
252
253 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
254
255 /* See if the group is really a number */
256 if (gid == DBUS_UID_UNSET)
257 {
258 unsigned long n;
259
260 if (_dbus_is_a_number (groupname, &n))
261 gid = n;
262 }
263
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 {
277 if (gid != DBUS_GID_UNSET)
278 _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
279 gid);
280 else
281 _dbus_verbose ("No cache for groupname \"%s\"\n",
282 _dbus_string_get_const_data (groupname));
283
284 info = dbus_new0 (DBusGroupInfo, 1);
285 if (info == NULL)
286 {
287 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
288 return NULL;
289 }
290
291 if (gid != DBUS_GID_UNSET)
292 {
293 if (!_dbus_group_info_fill_gid (info, gid, error))
294 {
295 _DBUS_ASSERT_ERROR_IS_SET (error);
296 _dbus_group_info_free_allocated (info);
297 return NULL;
298 }
299 }
300 else
301 {
302 if (!_dbus_group_info_fill (info, groupname, error))
303 {
304 _DBUS_ASSERT_ERROR_IS_SET (error);
305 _dbus_group_info_free_allocated (info);
306 return NULL;
307 }
308 }
309
310 /* don't use these past here */
311 gid = DBUS_GID_UNSET;
312 groupname = NULL;
313
314 if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
315 {
316 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
317 _dbus_group_info_free_allocated (info);
318 return NULL;
319 }
320
321
322 if (!_dbus_hash_table_insert_string (db->groups_by_name,
323 info->groupname,
324 info))
325 {
326 _dbus_hash_table_remove_uintptr (db->groups, info->gid);
327 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
328 return NULL;
329 }
330
331 return info;
332 }
333}
334
335
346 dbus_bool_t
347_dbus_user_database_get_groupname (DBusUserDatabase *db,
348 const DBusString *groupname,
349 const DBusGroupInfo **info,
350 DBusError *error)
351{
352 *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
353 return *info != NULL;
354}
355
366 dbus_bool_t
367_dbus_user_database_get_gid (DBusUserDatabase *db,
368 dbus_gid_t gid,
369 const DBusGroupInfo **info,
370 DBusError *error)
371{
372 *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
373 return *info != NULL;
374}
375
376
387 dbus_bool_t
388_dbus_groups_from_uid (dbus_uid_t uid,
389 dbus_gid_t **group_ids,
390 int *n_group_ids)
391{
392 DBusUserDatabase *db;
393 const DBusUserInfo *info;
394 *group_ids = NULL;
395 *n_group_ids = 0;
396
397 /* FIXME: this can't distinguish ENOMEM from other errors */
398 if (!_dbus_user_database_lock_system ())
399 return FALSE;
400
401 db = _dbus_user_database_get_system ();
402 if (db == NULL)
403 {
404 _dbus_user_database_unlock_system ();
405 return FALSE;
406 }
407
408 if (!_dbus_user_database_get_uid (db, uid,
409 &info, NULL))
410 {
411 _dbus_user_database_unlock_system ();
412 return FALSE;
413 }
414
415 _dbus_assert (info->uid == uid);
416
417 if (info->n_group_ids > 0)
418 {
419 *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
420 if (*group_ids == NULL)
421 {
422 _dbus_user_database_unlock_system ();
423 return FALSE;
424 }
425
426 *n_group_ids = info->n_group_ids;
427
428 memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
429 }
430
431 _dbus_user_database_unlock_system ();
432 return TRUE;
433}
436#ifdef DBUS_ENABLE_EMBEDDED_TESTS
437#include <stdio.h>
438
444 dbus_bool_t
445_dbus_userdb_test (const char *test_data_dir)
446{
447 const DBusString *username;
448 const DBusString *homedir;
449 dbus_uid_t uid;
450 unsigned long *group_ids;
451 int n_group_ids, i;
452 DBusError error;
453
454 if (!_dbus_username_from_current_process (&username))
455 _dbus_assert_not_reached ("didn't get username");
456
457 if (!_dbus_homedir_from_current_process (&homedir))
458 _dbus_assert_not_reached ("didn't get homedir");
459
460 if (!_dbus_get_user_id (username, &uid))
461 _dbus_assert_not_reached ("didn't get uid");
462
463 if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
464 _dbus_assert_not_reached ("didn't get groups");
465
466 printf (" Current user: %s homedir: %s gids:",
467 _dbus_string_get_const_data (username),
468 _dbus_string_get_const_data (homedir));
469
470 for (i=0; i<n_group_ids; i++)
471 printf(" %ld", group_ids[i]);
472
473 printf ("\n");
474
475 dbus_error_init (&error);
476 printf ("Is Console user: %i\n",
477 _dbus_is_console_user (uid, &error));
478 printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
479 dbus_error_free (&error);
480 printf ("Is Console user 4711: %i\n",
481 _dbus_is_console_user (4711, &error));
482 printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
483 dbus_error_free (&error);
484
485 dbus_free (group_ids);
486
487 return TRUE;
488}
489#endif /* DBUS_ENABLE_EMBEDDED_TESTS */
dbus_error_init
void dbus_error_init(DBusError *error)
Initializes a DBusError structure.
Definition: dbus-errors.c:188
dbus_set_error
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
dbus_error_free
void dbus_error_free(DBusError *error)
Frees an error that's been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
_dbus_hash_table_remove_uintptr
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:1189
_dbus_hash_table_insert_string
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:1224
_dbus_hash_table_lookup_uintptr
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:1109
_dbus_hash_table_lookup_string
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:1059
_dbus_hash_table_insert_uintptr
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:1299
_dbus_stat
dbus_bool_t _dbus_stat(const DBusString *filename, DBusStat *statbuf, DBusError *error)
stat() wrapper.
Definition: dbus-sysdeps-util-unix.c:612
_dbus_assert_not_reached
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
Definition: dbus-internals.h:163
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition: dbus-internals.h:152
_dbus_user_database_lock_system
dbus_bool_t _dbus_user_database_lock_system(void)
Locks global system user database.
Definition: dbus-userdb.c:306
_dbus_homedir_from_current_process
dbus_bool_t _dbus_homedir_from_current_process(const DBusString **homedir)
Gets homedir of user owning current process.
Definition: dbus-userdb.c:395
_dbus_user_database_lookup_group
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.
Definition: dbus-userdb-util.c:246
_dbus_user_at_console
dbus_bool_t _dbus_user_at_console(const char *username, DBusError *error)
Checks if user is at the console.
Definition: dbus-sysdeps-util-unix.c:548
_dbus_error_from_errno
const char * _dbus_error_from_errno(int error_number)
Converts a UNIX errno, or Windows errno or WinSock error value into a DBusError name.
Definition: dbus-sysdeps.c:592
_dbus_user_database_unlock_system
void _dbus_user_database_unlock_system(void)
Unlocks global system user database.
Definition: dbus-userdb.c:323
_dbus_user_database_get_uid
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:667
_dbus_user_database_get_gid
dbus_bool_t _dbus_user_database_get_gid(DBusUserDatabase *db, dbus_gid_t gid, const DBusGroupInfo **info, DBusError *error)
Gets the user information for the given GID, returned group info should not be freed.
Definition: dbus-userdb-util.c:367
_dbus_user_database_lookup
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
_dbus_get_group_id
dbus_bool_t _dbus_get_group_id(const DBusString *groupname, dbus_gid_t *gid)
Gets group ID given groupname.
Definition: dbus-userdb-util.c:160
_dbus_username_from_current_process
dbus_bool_t _dbus_username_from_current_process(const DBusString **username)
Gets username of user owning current process.
Definition: dbus-userdb.c:371
_dbus_is_console_user
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.
Definition: dbus-userdb-util.c:49
_dbus_group_info_free_allocated
void _dbus_group_info_free_allocated(DBusGroupInfo *info)
Frees the given DBusGroupInfo's members with _dbus_group_info_free() and also calls dbus_free() on th...
Definition: dbus-userdb.c:61
_dbus_get_user_id_and_primary_group
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.
Definition: dbus-userdb-util.c:199
_dbus_user_database_get_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.
Definition: dbus-userdb.c:686
_dbus_is_a_number
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
_dbus_user_database_get_groupname
dbus_bool_t _dbus_user_database_get_groupname(DBusUserDatabase *db, const DBusString *groupname, const DBusGroupInfo **info, DBusError *error)
Gets the user information for the given group name, returned group info should not be freed.
Definition: dbus-userdb-util.c:347
_dbus_groups_from_uid
dbus_bool_t _dbus_groups_from_uid(dbus_uid_t uid, dbus_gid_t **group_ids, int *n_group_ids)
Gets all groups corresponding to the given UID.
Definition: dbus-userdb-util.c:388
_dbus_get_user_id
dbus_bool_t _dbus_get_user_id(const DBusString *username, dbus_uid_t *uid)
Gets user ID given username.
Definition: dbus-userdb-util.c:146
_dbus_user_database_get_system
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
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
TRUE
#define TRUE
Expands to "1".
FALSE
#define FALSE
Expands to "0".
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:702
dbus_new
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition: dbus-memory.h:58
dbus_new0
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
DBUS_ERROR_FAILED
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
Definition: dbus-protocol.h:355
DBUS_ERROR_NO_MEMORY
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
Definition: dbus-protocol.h:357
_dbus_string_append
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
_dbus_string_init
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
_dbus_string_free
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
_dbus_group_info_fill
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.
Definition: dbus-sysdeps-util-unix.c:906
_dbus_group_info_fill_gid
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.
Definition: dbus-sysdeps-util-unix.c:925
dbus_uid_t
unsigned long dbus_uid_t
A user ID.
Definition: dbus-sysdeps.h:108
dbus_gid_t
unsigned long dbus_gid_t
A group ID.
Definition: dbus-sysdeps.h:110
DBUS_UID_UNSET
#define DBUS_UID_UNSET
an invalid UID used to represent an uninitialized dbus_uid_t field
Definition: dbus-sysdeps.h:115
DBUS_GID_UNSET
#define DBUS_GID_UNSET
an invalid GID used to represent an uninitialized dbus_gid_t field
Definition: dbus-sysdeps.h:117
DBUS_GID_FORMAT
#define DBUS_GID_FORMAT
an appropriate printf format for dbus_gid_t
Definition: dbus-sysdeps.h:124
DBUS_UID_FORMAT
#define DBUS_UID_FORMAT
an appropriate printf format for dbus_uid_t
Definition: dbus-sysdeps.h:122
dbus_bool_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
DBusError
Object representing an exception.
Definition: dbus-errors.h:49
DBusError::message
const char * message
public error message field
Definition: dbus-errors.h:51
DBusGroupInfo
Information about a UNIX group.
Definition: dbus-sysdeps-unix.h:120
DBusGroupInfo::gid
dbus_gid_t gid
GID.
Definition: dbus-sysdeps-unix.h:121
DBusGroupInfo::groupname
char * groupname
Group name.
Definition: dbus-sysdeps-unix.h:122
DBusStat
Portable struct with stat() results.
Definition: dbus-sysdeps.h:502
DBusStat::uid
dbus_uid_t uid
User owning file.
Definition: dbus-sysdeps.h:505
DBusString
Definition: dbus-string.h:43
DBusUserInfo
Information about a UNIX user.
Definition: dbus-sysdeps-unix.h:107
DBusUserInfo::n_group_ids
int n_group_ids
Size of group IDs array.
Definition: dbus-sysdeps-unix.h:111
DBusUserInfo::uid
dbus_uid_t uid
UID.
Definition: dbus-sysdeps-unix.h:108
DBusUserInfo::group_ids
dbus_gid_t * group_ids
Groups IDs, including above primary group.
Definition: dbus-sysdeps-unix.h:110
DBusUserInfo::username
char * username
Username.
Definition: dbus-sysdeps-unix.h:112
DBusUserInfo::primary_gid
dbus_gid_t primary_gid
GID.
Definition: dbus-sysdeps-unix.h:109