mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-01 21:10:12 +01:00
$ git shortlog -n -s a3e75f3294 -- shared/nm-libnm-core-intern/nm-auth-subject.'[hc]' src/nm-auth-subject.'[hc]'
28 Thomas Haller
7 Dan Winship
1 Beniamino Galvani
1 Dan Williams
1 Jiří Klimeš
All contributors agreed to the relicensing according to "RELICENSE.md".
446 lines
13 KiB
C
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));
|
|
}
|