dbus-userdb-util.c
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus
*
* Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
*
* SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <config.h>
#include <unistd.h>
#define DBUS_USERDB_INCLUDES_PRIVATE 1
#include "dbus-userdb.h"
#include "dbus-test.h"
#include "dbus-internals.h"
#include "dbus-protocol.h"
#include <dbus/dbus-test-tap.h>
#include <string.h>
/* It isn't obvious from its name, but this file is part of the Unix
* system-dependent part of libdbus. */
#if defined(DBUS_WIN) || !defined(DBUS_UNIX)
#error "This file only makes sense on Unix OSs"
#endif
#ifdef HAVE_SYSTEMD
#include <systemd/sd-login.h>
#endif
static DBusGroupInfo *
_dbus_group_info_ref (DBusGroupInfo *info)
{
_dbus_assert (info->refcount > 0);
_dbus_assert (info->refcount < SIZE_MAX);
info->refcount++;
return info;
}
dbus_bool_t
_dbus_is_console_user (dbus_uid_t uid,
DBusError *error)
{
#ifdef HAVE_SYSTEMD
/* check if we have logind */
if (access ("/run/systemd/seats/", F_OK) >= 0)
{
int r;
/* Check whether this user is logged in on at least one physical
seat */
r = sd_uid_get_seats (uid, 0, NULL);
if (r < 0)
{
dbus_set_error (error, _dbus_error_from_errno (-r),
"Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
uid,
_dbus_strerror (-r));
return FALSE;
}
return (r > 0);
}
#endif
#ifdef HAVE_CONSOLE_OWNER_FILE
DBusString f;
DBusStat st;
if (!_dbus_string_init (&f))
{
_DBUS_SET_OOM (error);
return FALSE;
}
if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
{
_dbus_string_free(&f);
_DBUS_SET_OOM (error);
return FALSE;
}
if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
{
_dbus_string_free(&f);
return TRUE;
}
_dbus_string_free(&f);
#endif /* HAVE_CONSOLE_OWNER_FILE */
return FALSE;
}
dbus_bool_t
_dbus_get_user_id (const DBusString *username,
dbus_uid_t *uid)
{
return _dbus_get_user_id_and_primary_group (username, uid, NULL);
}
dbus_bool_t
_dbus_get_group_id (const DBusString *groupname,
dbus_gid_t *gid)
{
DBusUserDatabase *db;
const DBusGroupInfo *info;
/* FIXME: this can't distinguish ENOMEM from other errors */
if (!_dbus_user_database_lock_system ())
return FALSE;
db = _dbus_user_database_get_system ();
if (db == NULL)
{
_dbus_user_database_unlock_system ();
return FALSE;
}
info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname,
NULL);
if (info == NULL)
{
_dbus_user_database_unlock_system ();
return FALSE;
}
*gid = info->gid;
_dbus_user_database_unlock_system ();
return TRUE;
}
dbus_bool_t
_dbus_get_user_id_and_primary_group (const DBusString *username,
dbus_uid_t *uid_p,
dbus_gid_t *gid_p)
{
DBusUserDatabase *db;
const DBusUserInfo *info;
/* FIXME: this can't distinguish ENOMEM from other errors */
if (!_dbus_user_database_lock_system ())
return FALSE;
db = _dbus_user_database_get_system ();
if (db == NULL)
{
_dbus_user_database_unlock_system ();
return FALSE;
}
if (!_dbus_user_database_get_username (db, username,
&info, NULL))
{
_dbus_user_database_unlock_system ();
return FALSE;
}
if (uid_p)
*uid_p = info->uid;
if (gid_p)
*gid_p = info->primary_gid;
_dbus_user_database_unlock_system ();
return TRUE;
}
const DBusGroupInfo *
_dbus_user_database_lookup_group (DBusUserDatabase *db,
dbus_gid_t gid,
const DBusString *groupname,
DBusError *error)
{
DBusGroupInfo *info;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
/* See if the group is really a number */
if (gid == DBUS_UID_UNSET)
{
unsigned long n;
if (_dbus_is_a_number (groupname, &n))
gid = n;
}
if (gid != DBUS_GID_UNSET)
info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
else
info = _dbus_hash_table_lookup_string (db->groups_by_name,
_dbus_string_get_const_data (groupname));
if (info)
{
_dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
info->gid);
return info;
}
else
{
if (gid != DBUS_GID_UNSET)
_dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
gid);
else
_dbus_verbose ("No cache for groupname \"%s\"\n",
_dbus_string_get_const_data (groupname));
info = dbus_new0 (DBusGroupInfo, 1);
if (info == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
info->refcount = 1;
if (gid != DBUS_GID_UNSET)
{
if (!_dbus_group_info_fill_gid (info, gid, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_group_info_unref (info);
return NULL;
}
}
else
{
if (!_dbus_group_info_fill (info, groupname, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
_dbus_group_info_unref (info);
return NULL;
}
}
/* don't use these past here */
gid = DBUS_GID_UNSET;
groupname = NULL;
if (_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
{
_dbus_group_info_ref (info);
}
else
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
_dbus_group_info_unref (info);
return NULL;
}
if (_dbus_hash_table_insert_string (db->groups_by_name,
info->groupname,
info))
{
_dbus_group_info_ref (info);
}
else
{
_dbus_hash_table_remove_uintptr (db->groups, info->gid);
_dbus_group_info_unref (info);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
/* Release the original reference */
_dbus_group_info_unref (info);
/* Return a borrowed reference to the DBusGroupInfo owned by the
* two hash tables */
return info;
}
}
dbus_bool_t
_dbus_groups_from_uid (dbus_uid_t uid,
dbus_gid_t **group_ids,
int *n_group_ids,
DBusError *error)
{
DBusUserDatabase *db;
const DBusUserInfo *info;
dbus_bool_t ret = FALSE;
*group_ids = NULL;
*n_group_ids = 0;
if (!_dbus_user_database_lock_system ())
{
_DBUS_SET_OOM (error);
return FALSE;
}
db = _dbus_user_database_get_system ();
if (db == NULL)
{
_DBUS_SET_OOM (error);
goto out;
}
if (!_dbus_user_database_get_uid (db, uid, &info, error))
goto out;
_dbus_assert (info->uid == uid);
if (info->n_group_ids > 0)
{
*group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
if (*group_ids == NULL)
{
_DBUS_SET_OOM (error);
goto out;
}
*n_group_ids = info->n_group_ids;
memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
}
ret = TRUE;
out:
_DBUS_ASSERT_ERROR_XOR_BOOL (error, ret);
_dbus_user_database_unlock_system ();
return ret;
}
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:356
_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:1243
_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:1278
_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:1163
_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:1113
_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:1353
_dbus_stat
dbus_bool_t _dbus_stat(const DBusString *filename, DBusStat *statbuf, DBusError *error)
stat() wrapper.
Definition dbus-sysdeps-util-unix.c:593
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition dbus-internals.h:153
_dbus_user_database_lock_system
dbus_bool_t _dbus_user_database_lock_system(void)
Locks global system user database.
Definition dbus-userdb.c:353
_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:565
_dbus_user_database_unlock_system
void _dbus_user_database_unlock_system(void)
Unlocks global system user database.
Definition dbus-userdb.c:370
_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:705
_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:145
_dbus_group_info_unref
void _dbus_group_info_unref(DBusGroupInfo *info)
Decrements the reference count.
Definition dbus-userdb.c:87
_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:67
_dbus_user_database_lookup_group
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.
Definition dbus-userdb-util.c:233
_dbus_groups_from_uid
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.
Definition dbus-userdb-util.c:349
_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:186
_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:724
_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:135
_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:131
_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:383
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
Definition dbus-macros.h:51
TRUE
#define TRUE
Expands to "1".
Definition dbus-macros.h:41
FALSE
#define FALSE
Expands to "0".
Definition dbus-macros.h:44
dbus_new
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition dbus-memory.h:59
dbus_new0
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition dbus-memory.h:60
DBUS_ERROR_NO_MEMORY
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
Definition dbus-protocol.h:363
_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:980
_dbus_string_init
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition dbus-string.c:182
_dbus_string_free
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...
Definition dbus-string.c:278
_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:884
_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:903
dbus_uid_t
unsigned long dbus_uid_t
A user ID.
Definition dbus-sysdeps.h:141
dbus_gid_t
unsigned long dbus_gid_t
A group ID.
Definition dbus-sysdeps.h:143
DBUS_UID_UNSET
#define DBUS_UID_UNSET
an invalid UID used to represent an uninitialized dbus_uid_t field
Definition dbus-sysdeps.h:148
DBUS_GID_UNSET
#define DBUS_GID_UNSET
an invalid GID used to represent an uninitialized dbus_gid_t field
Definition dbus-sysdeps.h:150
DBUS_GID_FORMAT
#define DBUS_GID_FORMAT
an appropriate printf format for dbus_gid_t
Definition dbus-sysdeps.h:157
DBUS_UID_FORMAT
#define DBUS_UID_FORMAT
an appropriate printf format for dbus_uid_t
Definition dbus-sysdeps.h:155
dbus_bool_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition dbus-types.h:37
DBusError
Object representing an exception.
Definition dbus-errors.h:51
DBusGroupInfo
Information about a UNIX group.
Definition dbus-sysdeps-unix.h:107
DBusGroupInfo::gid
dbus_gid_t gid
GID.
Definition dbus-sysdeps-unix.h:109
DBusGroupInfo::groupname
char * groupname
Group name.
Definition dbus-sysdeps-unix.h:110
DBusGroupInfo::refcount
size_t refcount
Reference count.
Definition dbus-sysdeps-unix.h:108
DBusStat
Portable struct with stat() results.
Definition dbus-sysdeps.h:570
DBusStat::uid
dbus_uid_t uid
User owning file.
Definition dbus-sysdeps.h:573
DBusString
Definition dbus-string.h:47
DBusUserInfo
Information about a UNIX user.
Definition dbus-sysdeps-unix.h:93
DBusUserInfo::n_group_ids
int n_group_ids
Size of group IDs array.
Definition dbus-sysdeps-unix.h:98
DBusUserInfo::uid
dbus_uid_t uid
UID.
Definition dbus-sysdeps-unix.h:95
DBusUserInfo::group_ids
dbus_gid_t * group_ids
Groups IDs, including above primary group.
Definition dbus-sysdeps-unix.h:97
DBusUserInfo::primary_gid
dbus_gid_t primary_gid
GID.
Definition dbus-sysdeps-unix.h:96