1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Copyright (C) 2013 - 2014 Red Hat, Inc.
22 * SECTION:nm-auth-subject
23 * @short_description: Encapsulates authentication information about a requestor
25 * #NMAuthSubject encpasulates identifying information about an entity that
26 * makes requests, like process identifier and user UID.
29 #include "nm-default.h"
31 #include "nm-auth-subject.h"
36 #include "nm-bus-manager.h"
37 #include "nm-enum-types.h"
38 #include "NetworkManagerUtils.h"
40 G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
42 #define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate))
47 PROP_UNIX_PROCESS_DBUS_SENDER,
48 PROP_UNIX_PROCESS_PID,
49 PROP_UNIX_PROCESS_UID,
55 NMAuthSubjectType subject_type;
62 } NMAuthSubjectPrivate;
64 /**************************************************************/
66 #define CHECK_SUBJECT(self, error_value) \
67 NMAuthSubjectPrivate *priv; \
68 g_return_val_if_fail (NM_IS_AUTH_SUBJECT (self), error_value); \
69 priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); \
71 #define CHECK_SUBJECT_TYPED(self, expected_subject_type, error_value) \
72 CHECK_SUBJECT (self, error_value); \
73 g_return_val_if_fail (priv->subject_type == (expected_subject_type), error_value);
76 nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len)
78 CHECK_SUBJECT (self, NULL);
80 switch (priv->subject_type) {
81 case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
82 g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]",
83 (long unsigned) priv->unix_process.pid,
84 (long unsigned) priv->unix_process.uid,
85 (long long unsigned) priv->unix_process.start_time);
87 case NM_AUTH_SUBJECT_TYPE_INTERNAL:
88 g_strlcat (buf, "internal", buf_len);
91 g_strlcat (buf, "invalid", buf_len);
99 /* returns a floating variant */
101 nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self)
103 GVariantBuilder builder;
106 CHECK_SUBJECT_TYPED (self, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
108 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
109 g_variant_builder_add (&builder, "{sv}", "pid",
110 g_variant_new_uint32 (priv->unix_process.pid));
111 g_variant_builder_add (&builder, "{sv}", "start-time",
112 g_variant_new_uint64 (priv->unix_process.start_time));
113 g_variant_builder_add (&builder, "{sv}", "uid",
114 g_variant_new_int32 (priv->unix_process.uid));
115 dict = g_variant_builder_end (&builder);
116 ret = g_variant_new ("(s@a{sv})", "unix-process", dict);
123 nm_auth_subject_get_subject_type (NMAuthSubject *subject)
125 CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID);
127 return priv->subject_type;
131 nm_auth_subject_is_internal (NMAuthSubject *subject)
133 return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL;
137 nm_auth_subject_is_unix_process (NMAuthSubject *subject)
139 return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
143 nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject)
145 CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
147 return priv->unix_process.pid;
151 nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject)
153 CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
155 return priv->unix_process.uid;
159 nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject)
161 CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
163 return priv->unix_process.dbus_sender;
166 /**************************************************************/
168 static NMAuthSubject *
169 _new_unix_process (GDBusMethodInvocation *context,
170 GDBusConnection *connection,
171 GDBusMessage *message)
174 gboolean success = FALSE;
175 gulong pid = 0, uid = 0;
176 gs_free char *dbus_sender = NULL;
178 g_return_val_if_fail (context || (connection && message), NULL);
181 success = nm_bus_manager_get_caller_info (nm_bus_manager_get (),
186 } else if (message) {
187 success = nm_bus_manager_get_caller_info_from_message (nm_bus_manager_get (),
194 g_assert_not_reached ();
199 g_return_val_if_fail (dbus_sender && *dbus_sender, NULL);
200 /* polkit glib library stores uid and pid as gint. There might be some
201 * pitfalls if the id ever happens to be larger then that. Just assert against
203 g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL);
204 g_return_val_if_fail (pid > 0 && pid <= MIN (G_MAXINT, G_MAXINT32), NULL);
206 self = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
207 NM_AUTH_SUBJECT_SUBJECT_TYPE, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
208 NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, dbus_sender,
209 NM_AUTH_SUBJECT_UNIX_PROCESS_PID, (gulong) pid,
210 NM_AUTH_SUBJECT_UNIX_PROCESS_UID, (gulong) uid,
213 if (NM_AUTH_SUBJECT_GET_PRIVATE (self)->subject_type != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) {
214 /* this most likely happened because the process is gone (start_time==0).
215 * Either that is not assert-worthy, or constructed() already asserted.
216 * Just return NULL. */
217 g_clear_object (&self);
223 nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context)
225 return _new_unix_process (context, NULL, NULL);
229 nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection,
230 GDBusMessage *message)
232 return _new_unix_process (NULL, connection, message);
236 * nm_auth_subject_new_internal():
238 * Creates a new auth subject representing the NetworkManager process itself.
240 * Returns: the new #NMAuthSubject
243 nm_auth_subject_new_internal (void)
245 return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
246 NM_AUTH_SUBJECT_SUBJECT_TYPE, NM_AUTH_SUBJECT_TYPE_INTERNAL,
250 /**************************************************************/
253 get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
255 NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
258 case PROP_SUBJECT_TYPE:
259 g_value_set_enum (value, priv->subject_type);
261 case PROP_UNIX_PROCESS_DBUS_SENDER:
262 g_value_set_string (value, priv->unix_process.dbus_sender);
264 case PROP_UNIX_PROCESS_PID:
265 g_value_set_ulong (value, priv->unix_process.pid);
267 case PROP_UNIX_PROCESS_UID:
268 g_value_set_ulong (value, priv->unix_process.uid);
271 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
277 set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
279 NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
280 NMAuthSubjectType subject_type;
284 /* all properties are construct-only */
286 case PROP_SUBJECT_TYPE:
287 subject_type = g_value_get_enum (value);
288 g_return_if_fail (subject_type != NM_AUTH_SUBJECT_TYPE_INVALID);
289 priv->subject_type |= subject_type;
290 g_return_if_fail (priv->subject_type == subject_type);
292 case PROP_UNIX_PROCESS_DBUS_SENDER:
293 if ((str = g_value_get_string (value))) {
294 priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
295 g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
296 priv->unix_process.dbus_sender = g_strdup (str);
299 case PROP_UNIX_PROCESS_PID:
300 if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
301 priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
302 g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
303 priv->unix_process.pid = id;
306 case PROP_UNIX_PROCESS_UID:
307 if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
308 priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
309 g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
310 priv->unix_process.uid = id;
314 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320 _clear_private (NMAuthSubjectPrivate *priv)
322 priv->subject_type = NM_AUTH_SUBJECT_TYPE_INVALID;
323 priv->unix_process.pid = G_MAXULONG;
324 priv->unix_process.uid = G_MAXULONG;
325 g_clear_pointer (&priv->unix_process.dbus_sender, g_free);
329 nm_auth_subject_init (NMAuthSubject *self)
331 _clear_private (NM_AUTH_SUBJECT_GET_PRIVATE (self));
335 constructed (GObject *object)
337 NMAuthSubject *self = NM_AUTH_SUBJECT (object);
338 NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
340 /* validate that the created instance. */
342 switch (priv->subject_type) {
343 case NM_AUTH_SUBJECT_TYPE_INTERNAL:
344 priv->unix_process.pid = G_MAXULONG;
345 priv->unix_process.uid = 0; /* internal uses 'root' user */
347 case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
348 /* Ensure pid and uid to be representable as int32.
349 * DBUS treats them as uint32, polkit library as gint. */
350 if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32))
352 if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) {
353 /* for uid==-1, libpolkit-gobject-1 detects the user based on the process id.
354 * Don't bother and require the user id as parameter. */
357 if (!priv->unix_process.dbus_sender || !*priv->unix_process.dbus_sender)
360 priv->unix_process.start_time = nm_utils_get_start_time_for_pid (priv->unix_process.pid, NULL, NULL);
362 if (!priv->unix_process.start_time) {
363 /* could not detect the process start time. The subject is invalid, but don't
364 * assert against it. */
365 _clear_private (priv);
372 _clear_private (priv);
373 g_return_if_reached ();
377 finalize (GObject *object)
379 NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
381 _clear_private (priv);
383 G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
387 nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
389 GObjectClass *object_class = G_OBJECT_CLASS (config_class);
391 g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate));
393 /* virtual methods */
394 object_class->get_property = get_property;
395 object_class->set_property = set_property;
396 object_class->constructed = constructed;
397 object_class->finalize = finalize;
399 g_object_class_install_property
400 (object_class, PROP_SUBJECT_TYPE,
401 g_param_spec_enum (NM_AUTH_SUBJECT_SUBJECT_TYPE, "", "",
402 NM_TYPE_AUTH_SUBJECT_TYPE,
403 NM_AUTH_SUBJECT_TYPE_INVALID,
405 G_PARAM_CONSTRUCT_ONLY |
406 G_PARAM_STATIC_STRINGS));
408 g_object_class_install_property
409 (object_class, PROP_UNIX_PROCESS_DBUS_SENDER,
410 g_param_spec_string (NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, "", "",
413 G_PARAM_CONSTRUCT_ONLY |
414 G_PARAM_STATIC_STRINGS));
416 g_object_class_install_property
417 (object_class, PROP_UNIX_PROCESS_PID,
418 g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_PID, "", "",
419 0, G_MAXULONG, G_MAXULONG,
421 G_PARAM_CONSTRUCT_ONLY |
422 G_PARAM_STATIC_STRINGS));
424 g_object_class_install_property
425 (object_class, PROP_UNIX_PROCESS_UID,
426 g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_UID, "", "",
427 0, G_MAXULONG, G_MAXULONG,
429 G_PARAM_CONSTRUCT_ONLY |
430 G_PARAM_STATIC_STRINGS));