NetworkManager/libnm-core/nm-libnm-core-intern/nm-auth-subject.c
Thomas Haller e17a067e68
all: move "shared/nm-libnm-core-intern" to "libnm-core/nm-libnm-core-intern"
The "shared" directory is used by libnm-core, it should thus only depend on
code that is in the "shared" directory. Otherwise there is a circular
dependency, and meson's subdir() does not work nicely.

Also, libnm-core is really part of (and also an extension of) libnm-core,
so it belongs there.

I guess, the original idea was that this is also an extension for libnm,
so another project could take these utility functions (by copying them
into their source tree) and use them. That is still possible, it's
just that the sources are no longer under the shared directory.

Also add a readme to explain the non-obvious meaning of these files.
2020-06-11 10:53:50 +02:00

446 lines
13 KiB
C

// SPDX-License-Identifier: LGPL-2.1+
/*
* Copyright (C) 2013 - 2014 Red Hat, Inc.
*/
/**
* SECTION:nm-auth-subject
* @short_description: Encapsulates authentication information about a requestor
*
* #NMAuthSubject encpasulates identifying information about an entity that
* makes requests, like process identifier and user UID.
*/
#include "nm-default.h"
#include "nm-auth-subject.h"
#include <stdlib.h>
enum {
PROP_0,
PROP_SUBJECT_TYPE,
PROP_UNIX_PROCESS_DBUS_SENDER,
PROP_UNIX_PROCESS_PID,
PROP_UNIX_PROCESS_UID,
PROP_UNIX_SESSION_ID,
PROP_LAST,
};
typedef struct {
NMAuthSubjectType subject_type;
struct {
gulong pid;
gulong uid;
guint64 start_time;
char *dbus_sender;
} unix_process;
struct {
char *id;
} unix_session;
} NMAuthSubjectPrivate;
struct _NMAuthSubject {
GObject parent;
NMAuthSubjectPrivate _priv;
};
struct _NMAuthSubjectClass {
GObjectClass parent;
};
G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
#define NM_AUTH_SUBJECT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAuthSubject, NM_IS_AUTH_SUBJECT)
/*****************************************************************************/
#define CHECK_SUBJECT(self, error_value) \
NMAuthSubjectPrivate *priv; \
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (self), error_value); \
priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); \
#define CHECK_SUBJECT_TYPED(self, expected_subject_type, error_value) \
CHECK_SUBJECT (self, error_value); \
g_return_val_if_fail (priv->subject_type == (expected_subject_type), error_value);
const char *
nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len)
{
CHECK_SUBJECT (self, NULL);
switch (priv->subject_type) {
case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]",
(unsigned long) priv->unix_process.pid,
(unsigned long) priv->unix_process.uid,
(unsigned long long) priv->unix_process.start_time);
break;
case NM_AUTH_SUBJECT_TYPE_INTERNAL:
g_strlcpy (buf, "internal", buf_len);
break;
case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
g_snprintf (buf, buf_len, "unix-session[id=%s]",
priv->unix_session.id);
break;
default:
g_strlcpy (buf, "invalid", buf_len);
break;
}
return buf;
}
/* returns a floating variant */
GVariant *
nm_auth_subject_unix_to_polkit_gvariant (NMAuthSubject *self)
{
GVariantBuilder builder;
CHECK_SUBJECT (self, NULL);
switch (priv->subject_type) {
case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "session-id",
g_variant_new_string (priv->unix_session.id));
return g_variant_new ("(sa{sv})", "unix-session", &builder);
case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "pid",
g_variant_new_uint32 (priv->unix_process.pid));
g_variant_builder_add (&builder, "{sv}", "start-time",
g_variant_new_uint64 (priv->unix_process.start_time));
g_variant_builder_add (&builder, "{sv}", "uid",
g_variant_new_int32 (priv->unix_process.uid));
return g_variant_new ("(sa{sv})", "unix-process", &builder);
default:
g_return_val_if_reached (NULL);
}
}
NMAuthSubjectType
nm_auth_subject_get_subject_type (NMAuthSubject *subject)
{
CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID);
return priv->subject_type;
}
gulong
nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject)
{
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
return priv->unix_process.pid;
}
gulong
nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject)
{
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
return priv->unix_process.uid;
}
const char *
nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject)
{
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
return priv->unix_process.dbus_sender;
}
const char *
nm_auth_subject_get_unix_session_id (NMAuthSubject *subject)
{
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_SESSION, NULL);
return priv->unix_session.id;
}
/*****************************************************************************/
/**
* nm_auth_subject_new_internal():
*
* Creates a new auth subject representing the NetworkManager process itself.
*
* Returns: the new #NMAuthSubject
*/
NMAuthSubject *
nm_auth_subject_new_internal (void)
{
return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_INTERNAL,
NULL));
}
/**
* nm_auth_subject_new_unix_session():
*
* Creates a new auth subject representing a given unix session.
*
* Returns: the new #NMAuthSubject
*/
NMAuthSubject *
nm_auth_subject_new_unix_session (const char *session_id)
{
return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION,
NM_AUTH_SUBJECT_UNIX_SESSION_ID, session_id,
NULL));
}
/**
* nm_auth_subject_new_unix_process():
*
* Creates a new auth subject representing a given unix process.
*
* Returns: the new #NMAuthSubject
*/
NMAuthSubject *
nm_auth_subject_new_unix_process (const char *dbus_sender, gulong pid, gulong uid)
{
return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, dbus_sender,
NM_AUTH_SUBJECT_UNIX_PROCESS_PID, pid,
NM_AUTH_SUBJECT_UNIX_PROCESS_UID, uid,
NULL));
}
/**
* nm_auth_subject_new_unix_process_self():
*
* Creates a new auth subject representing the current executing process.
*
* Returns: the new #NMAuthSubject
*/
NMAuthSubject *
nm_auth_subject_new_unix_process_self (void)
{
return nm_auth_subject_new_unix_process (NULL, getpid(), getuid());
}
/*****************************************************************************/
static void
get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
switch (prop_id) {
case PROP_SUBJECT_TYPE:
g_value_set_int (value, priv->subject_type);
break;
case PROP_UNIX_PROCESS_DBUS_SENDER:
g_value_set_string (value, priv->unix_process.dbus_sender);
break;
case PROP_UNIX_PROCESS_PID:
g_value_set_ulong (value, priv->unix_process.pid);
break;
case PROP_UNIX_PROCESS_UID:
g_value_set_ulong (value, priv->unix_process.uid);
break;
case PROP_UNIX_SESSION_ID:
g_value_set_string (value, priv->unix_session.id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
NMAuthSubjectType subject_type;
int i;
const char *str;
gulong id;
switch (prop_id) {
case PROP_SUBJECT_TYPE:
/* construct-only */
i = g_value_get_int (value);
g_return_if_fail (NM_IN_SET (i,
(int) NM_AUTH_SUBJECT_TYPE_INTERNAL,
(int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
(int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION));
subject_type = i;
priv->subject_type |= subject_type;
g_return_if_fail (priv->subject_type == subject_type);
break;
case PROP_UNIX_PROCESS_DBUS_SENDER:
/* construct-only */
if ((str = g_value_get_string (value))) {
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
priv->unix_process.dbus_sender = g_strdup (str);
}
break;
case PROP_UNIX_PROCESS_PID:
/* construct-only */
if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
priv->unix_process.pid = id;
}
break;
case PROP_UNIX_PROCESS_UID:
/* construct-only */
if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
priv->unix_process.uid = id;
}
break;
case PROP_UNIX_SESSION_ID:
/* construct-only */
if ((str = g_value_get_string (value))) {
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_SESSION;
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_SESSION);
priv->unix_session.id = g_strdup (str);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
_clear_private (NMAuthSubject *self)
{
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
priv->subject_type = NM_AUTH_SUBJECT_TYPE_INVALID;
priv->unix_process.pid = G_MAXULONG;
priv->unix_process.uid = G_MAXULONG;
nm_clear_g_free (&priv->unix_process.dbus_sender);
nm_clear_g_free (&priv->unix_session.id);
}
static void
nm_auth_subject_init (NMAuthSubject *self)
{
_clear_private (self);
}
static void
constructed (GObject *object)
{
NMAuthSubject *self = NM_AUTH_SUBJECT (object);
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
/* validate that the created instance. */
switch (priv->subject_type) {
case NM_AUTH_SUBJECT_TYPE_INTERNAL:
priv->unix_process.pid = G_MAXULONG;
priv->unix_process.uid = 0; /* internal uses 'root' user */
return;
case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
/* Ensure pid and uid to be representable as int32.
* DBUS treats them as uint32, polkit library as int. */
if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32))
break;
if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) {
/* for uid==-1, libpolkit-gobject-1 detects the user based on the process id.
* Don't bother and require the user id as parameter. */
break;
}
priv->unix_process.start_time = nm_utils_get_start_time_for_pid (priv->unix_process.pid, NULL, NULL);
if (!priv->unix_process.start_time) {
/* Is the process already gone? Then fail creation of the auth subject
* by clearing the type. */
if (kill (priv->unix_process.pid, 0) != 0)
_clear_private (self);
/* Otherwise, although we didn't detect a start_time, the process is still around.
* That could be due to procfs mounted with hidepid. So just accept the request.
*
* Polkit on the other side, will accept 0 and try to lookup /proc/$PID/stat
* itself (and if it fails to do so, assume a start-time of 0 and proceed).
* The only combination that would fail here, is when NM is able to read the
* start-time, but polkit is not. */
}
return;
case NM_AUTH_SUBJECT_TYPE_UNIX_SESSION:
return;
default:
break;
}
_clear_private (self);
g_return_if_reached ();
}
static void
finalize (GObject *object)
{
_clear_private ((NMAuthSubject *) object);
G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
}
static void
nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (config_class);
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->constructed = constructed;
object_class->finalize = finalize;
g_object_class_install_property
(object_class, PROP_SUBJECT_TYPE,
g_param_spec_int (NM_AUTH_SUBJECT_SUBJECT_TYPE, "", "",
NM_AUTH_SUBJECT_TYPE_INVALID,
NM_AUTH_SUBJECT_TYPE_UNIX_SESSION,
NM_AUTH_SUBJECT_TYPE_INVALID,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_UNIX_PROCESS_DBUS_SENDER,
g_param_spec_string (NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_UNIX_PROCESS_PID,
g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_PID, "", "",
0, G_MAXULONG, G_MAXULONG,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_UNIX_PROCESS_UID,
g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_UID, "", "",
0, G_MAXULONG, G_MAXULONG,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_UNIX_SESSION_ID,
g_param_spec_string (NM_AUTH_SUBJECT_UNIX_SESSION_ID, "", "",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}