device: renew dhcp leases on awake for software devices
[NetworkManager.git] / src / nm-auth-subject.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
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.
8  *
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.
13  *
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.
17  *
18  * Copyright (C) 2013 - 2014 Red Hat, Inc.
19  */
20
21 /**
22  * SECTION:nm-auth-subject
23  * @short_description: Encapsulates authentication information about a requestor
24  *
25  * #NMAuthSubject encpasulates identifying information about an entity that
26  * makes requests, like process identifier and user UID.
27  */
28
29 #include "nm-default.h"
30
31 #include "nm-auth-subject.h"
32
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "nm-bus-manager.h"
37 #include "nm-enum-types.h"
38 #include "NetworkManagerUtils.h"
39
40 G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
41
42 #define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate))
43
44 enum {
45         PROP_0,
46         PROP_SUBJECT_TYPE,
47         PROP_UNIX_PROCESS_DBUS_SENDER,
48         PROP_UNIX_PROCESS_PID,
49         PROP_UNIX_PROCESS_UID,
50
51         PROP_LAST,
52 };
53
54 typedef struct {
55         NMAuthSubjectType subject_type;
56         struct {
57                 gulong pid;
58                 gulong uid;
59                 guint64 start_time;
60                 char *dbus_sender;
61         } unix_process;
62 } NMAuthSubjectPrivate;
63
64 /**************************************************************/
65
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); \
70
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);
74
75 const char *
76 nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len)
77 {
78         CHECK_SUBJECT (self, NULL);
79
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);
86                 break;
87         case NM_AUTH_SUBJECT_TYPE_INTERNAL:
88                 g_strlcat (buf, "internal", buf_len);
89                 break;
90         default:
91                 g_strlcat (buf, "invalid", buf_len);
92                 break;
93         }
94         return buf;
95 }
96
97 #if WITH_POLKIT
98
99 /* returns a floating variant */
100 GVariant *
101 nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self)
102 {
103         GVariantBuilder builder;
104         GVariant *dict;
105         GVariant *ret;
106         CHECK_SUBJECT_TYPED (self, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
107
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);
117         return ret;
118 }
119
120 #endif
121
122 NMAuthSubjectType
123 nm_auth_subject_get_subject_type (NMAuthSubject *subject)
124 {
125         CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID);
126
127         return priv->subject_type;
128 }
129
130 gboolean
131 nm_auth_subject_is_internal (NMAuthSubject *subject)
132 {
133         return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL;
134 }
135
136 gboolean
137 nm_auth_subject_is_unix_process (NMAuthSubject *subject)
138 {
139         return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
140 }
141
142 gulong
143 nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject)
144 {
145         CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
146
147         return priv->unix_process.pid;
148 }
149
150 gulong
151 nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject)
152 {
153         CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
154
155         return priv->unix_process.uid;
156 }
157
158 const char *
159 nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject)
160 {
161         CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
162
163         return priv->unix_process.dbus_sender;
164 }
165
166 /**************************************************************/
167
168 static NMAuthSubject *
169 _new_unix_process (GDBusMethodInvocation *context,
170                    GDBusConnection *connection,
171                    GDBusMessage *message)
172 {
173         NMAuthSubject *self;
174         gboolean success = FALSE;
175         gulong pid = 0, uid = 0;
176         gs_free char *dbus_sender = NULL;
177
178         g_return_val_if_fail (context || (connection && message), NULL);
179
180         if (context) {
181                 success = nm_bus_manager_get_caller_info (nm_bus_manager_get (),
182                                                           context,
183                                                           &dbus_sender,
184                                                           &uid,
185                                                           &pid);
186         } else if (message) {
187                 success = nm_bus_manager_get_caller_info_from_message (nm_bus_manager_get (),
188                                                                        connection,
189                                                                        message,
190                                                                        &dbus_sender,
191                                                                        &uid,
192                                                                        &pid);
193         } else
194                 g_assert_not_reached ();
195
196         if (!success)
197                 return NULL;
198
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
202          * it here. */
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);
205
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,
211                                               NULL));
212
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);
218         }
219         return self;
220 }
221
222 NMAuthSubject *
223 nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context)
224 {
225         return _new_unix_process (context, NULL, NULL);
226 }
227
228 NMAuthSubject *
229 nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection,
230                                                GDBusMessage *message)
231 {
232         return _new_unix_process (NULL, connection, message);
233 }
234
235 /**
236  * nm_auth_subject_new_internal():
237  *
238  * Creates a new auth subject representing the NetworkManager process itself.
239  *
240  * Returns: the new #NMAuthSubject
241  */
242 NMAuthSubject *
243 nm_auth_subject_new_internal (void)
244 {
245         return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
246                                               NM_AUTH_SUBJECT_SUBJECT_TYPE, NM_AUTH_SUBJECT_TYPE_INTERNAL,
247                                               NULL));
248 }
249
250 /**************************************************************/
251
252 static void
253 get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
254 {
255         NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
256
257         switch (prop_id) {
258         case PROP_SUBJECT_TYPE:
259                 g_value_set_enum (value, priv->subject_type);
260                 break;
261         case PROP_UNIX_PROCESS_DBUS_SENDER:
262                 g_value_set_string (value, priv->unix_process.dbus_sender);
263                 break;
264         case PROP_UNIX_PROCESS_PID:
265                 g_value_set_ulong (value, priv->unix_process.pid);
266                 break;
267         case PROP_UNIX_PROCESS_UID:
268                 g_value_set_ulong (value, priv->unix_process.uid);
269                 break;
270         default:
271                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
272                  break;
273         }
274 }
275
276 static void
277 set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
278 {
279         NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
280         NMAuthSubjectType subject_type;
281         const char *str;
282         gulong id;
283
284         /* all properties are construct-only */
285         switch (prop_id) {
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);
291                 break;
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);
297                 }
298                 break;
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;
304                 }
305                 break;
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;
311                 }
312                 break;
313         default:
314                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315                  break;
316         }
317 }
318
319 static void
320 _clear_private (NMAuthSubjectPrivate *priv)
321 {
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);
326 }
327
328 static void
329 nm_auth_subject_init (NMAuthSubject *self)
330 {
331         _clear_private (NM_AUTH_SUBJECT_GET_PRIVATE (self));
332 }
333
334 static void
335 constructed (GObject *object)
336 {
337         NMAuthSubject *self = NM_AUTH_SUBJECT (object);
338         NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
339
340         /* validate that the created instance. */
341
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 */
346                 return;
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))
351                         break;
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. */
355                         break;
356                 }
357                 if (!priv->unix_process.dbus_sender || !*priv->unix_process.dbus_sender)
358                         break;
359
360                 priv->unix_process.start_time = nm_utils_get_start_time_for_pid (priv->unix_process.pid, NULL, NULL);
361
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);
366                 }
367                 return;
368         default:
369                 break;
370         }
371
372         _clear_private (priv);
373         g_return_if_reached ();
374 }
375
376 static void
377 finalize (GObject *object)
378 {
379         NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
380
381         _clear_private (priv);
382
383         G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
384 }
385
386 static void
387 nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
388 {
389         GObjectClass *object_class = G_OBJECT_CLASS (config_class);
390
391         g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate));
392
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;
398
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,
404                                 G_PARAM_READWRITE |
405                                 G_PARAM_CONSTRUCT_ONLY |
406                                 G_PARAM_STATIC_STRINGS));
407
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, "", "",
411                                   NULL,
412                                   G_PARAM_READWRITE |
413                                   G_PARAM_CONSTRUCT_ONLY |
414                                   G_PARAM_STATIC_STRINGS));
415
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,
420                                   G_PARAM_READWRITE |
421                                   G_PARAM_CONSTRUCT_ONLY |
422                                   G_PARAM_STATIC_STRINGS));
423
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,
428                                   G_PARAM_READWRITE |
429                                   G_PARAM_CONSTRUCT_ONLY |
430                                   G_PARAM_STATIC_STRINGS));
431
432 }