device: renew dhcp leases on awake for software devices
[NetworkManager.git] / src / nm-auth-manager.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) 2014 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include "nm-auth-manager.h"
24
25 #include "nm-errors.h"
26 #include "nm-core-internal.h"
27 #include "NetworkManagerUtils.h"
28
29 #define POLKIT_SERVICE                      "org.freedesktop.PolicyKit1"
30 #define POLKIT_OBJECT_PATH                  "/org/freedesktop/PolicyKit1/Authority"
31 #define POLKIT_INTERFACE                    "org.freedesktop.PolicyKit1.Authority"
32
33
34 #define _NMLOG_PREFIX_NAME    "auth"
35 #define _NMLOG_DOMAIN         LOGD_CORE
36 #define _NMLOG(level, ...) \
37     G_STMT_START { \
38         if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
39             char __prefix[30] = _NMLOG_PREFIX_NAME; \
40             \
41             if ((self) != singleton_instance) \
42                 g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", (self)); \
43             _nm_log ((level), (_NMLOG_DOMAIN), 0, \
44                      "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
45                      __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
46         } \
47     } G_STMT_END
48
49 enum {
50         PROP_0,
51         PROP_POLKIT_ENABLED,
52
53         LAST_PROP
54 };
55
56 enum {
57         CHANGED_SIGNAL,
58
59         LAST_SIGNAL,
60 };
61
62 static guint signals[LAST_SIGNAL] = {0};
63
64 typedef struct {
65         gboolean polkit_enabled;
66 #if WITH_POLKIT
67         guint call_id_counter;
68         GCancellable *new_proxy_cancellable;
69         GSList *queued_calls;
70         GDBusProxy *proxy;
71 #endif
72 } NMAuthManagerPrivate;
73
74 NM_DEFINE_SINGLETON_REGISTER (NMAuthManager);
75
76 G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT)
77
78 #define NM_AUTH_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_MANAGER, NMAuthManagerPrivate))
79
80 /*****************************************************************************/
81
82 gboolean
83 nm_auth_manager_get_polkit_enabled (NMAuthManager *self)
84 {
85         g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
86
87         return NM_AUTH_MANAGER_GET_PRIVATE (self)->polkit_enabled;
88 }
89
90 /*****************************************************************************/
91
92 #if WITH_POLKIT
93
94 typedef enum {
95         POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE                   = 0,
96         POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0),
97 } PolkitCheckAuthorizationFlags;
98
99 typedef struct {
100         guint call_id;
101         NMAuthManager *self;
102         GSimpleAsyncResult *simple;
103         gchar *cancellation_id;
104         GVariant *dbus_parameters;
105         GCancellable *cancellable;
106 } CheckAuthData;
107
108 static void
109 _check_auth_data_free (CheckAuthData *data)
110 {
111         if (data->dbus_parameters)
112                 g_variant_unref (data->dbus_parameters);
113         g_object_unref (data->self);
114         g_object_unref (data->simple);
115         g_clear_object (&data->cancellable);
116         g_free (data->cancellation_id);
117         g_free (data);
118 }
119
120 static void
121 _call_check_authorization_complete_with_error (CheckAuthData *data,
122                                                const char *error_message)
123 {
124         NMAuthManager *self = data->self;
125
126         _LOGD ("call[%u]: CheckAuthorization failed due to internal error: %s", data->call_id, error_message);
127         g_simple_async_result_set_error (data->simple,
128                                          NM_MANAGER_ERROR,
129                                          NM_MANAGER_ERROR_FAILED,
130                                          "Authorization check failed: %s",
131                                          error_message);
132
133         g_simple_async_result_complete_in_idle (data->simple);
134
135         _check_auth_data_free (data);
136 }
137
138 static void
139 cancel_check_authorization_cb (GDBusProxy *proxy,
140                                GAsyncResult *res,
141                                gpointer user_data)
142 {
143         NMAuthManager *self = user_data;
144         GVariant *value;
145         GError *error= NULL;
146
147         value = g_dbus_proxy_call_finish (proxy, res, &error);
148         if (value == NULL) {
149                 g_dbus_error_strip_remote_error (error);
150                 _LOGD ("Error cancelling authorization check: %s", error->message);
151                 g_error_free (error);
152         } else
153                 g_variant_unref (value);
154
155         g_object_unref (self);
156 }
157
158 typedef struct {
159         gboolean is_authorized;
160         gboolean is_challenge;
161 } CheckAuthorizationResult;
162
163 static void
164 check_authorization_cb (GDBusProxy *proxy,
165                         GAsyncResult *res,
166                         gpointer user_data)
167 {
168         CheckAuthData *data = user_data;
169         NMAuthManager *self = data->self;
170         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
171         GVariant *value;
172         GError *error = NULL;
173
174         value = _nm_dbus_proxy_call_finish (proxy, res, G_VARIANT_TYPE ("((bba{ss}))"), &error);
175         if (value == NULL) {
176                 if (data->cancellation_id != NULL &&
177                     (   g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
178                      && !g_dbus_error_is_remote_error (error))) {
179                         _LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id);
180                         g_dbus_proxy_call (priv->proxy,
181                                            "CancelCheckAuthorization",
182                                            g_variant_new ("(s)", data->cancellation_id),
183                                            G_DBUS_CALL_FLAGS_NONE,
184                                            -1,
185                                            NULL, /* GCancellable */
186                                            (GAsyncReadyCallback) cancel_check_authorization_cb,
187                                            g_object_ref (self));
188                 } else
189                         _LOGD ("call[%u]: CheckAuthorization failed: %s", data->call_id, error->message);
190                 g_dbus_error_strip_remote_error (error);
191                 g_simple_async_result_set_error (data->simple,
192                                                  NM_MANAGER_ERROR,
193                                                  NM_MANAGER_ERROR_FAILED,
194                                                  "Authorization check failed: %s",
195                                                  error->message);
196                 g_error_free (error);
197         } else {
198                 CheckAuthorizationResult *result;
199
200                 result = g_new0 (CheckAuthorizationResult, 1);
201
202                 g_variant_get (value,
203                                "((bb@a{ss}))",
204                                &result->is_authorized,
205                                &result->is_challenge,
206                                NULL);
207                 g_variant_unref (value);
208
209                 _LOGD ("call[%u]: CheckAuthorization succeeded: (is_authorized=%d, is_challenge=%d)", data->call_id, result->is_authorized, result->is_challenge);
210                 g_simple_async_result_set_op_res_gpointer (data->simple, result, g_free);
211         }
212
213         g_simple_async_result_complete (data->simple);
214
215         _check_auth_data_free (data);
216 }
217
218 static void
219 _call_check_authorization (CheckAuthData *data)
220 {
221         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (data->self);
222
223         g_dbus_proxy_call (priv->proxy,
224                            "CheckAuthorization",
225                            data->dbus_parameters,
226                            G_DBUS_CALL_FLAGS_NONE,
227                            G_MAXINT, /* no timeout */
228                            data->cancellable,
229                            (GAsyncReadyCallback) check_authorization_cb,
230                            data);
231         g_clear_object (&data->cancellable);
232         data->dbus_parameters = NULL;
233 }
234
235 void
236 nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self,
237                                                       NMAuthSubject *subject,
238                                                       const char *action_id,
239                                                       gboolean allow_user_interaction,
240                                                       GCancellable *cancellable,
241                                                       GAsyncReadyCallback callback,
242                                                       gpointer user_data)
243 {
244         NMAuthManagerPrivate *priv;
245         char subject_buf[64];
246         GVariantBuilder builder;
247         PolkitCheckAuthorizationFlags flags;
248         GVariant *subject_value;
249         GVariant *details_value;
250         CheckAuthData *data;
251
252         g_return_if_fail (NM_IS_AUTH_MANAGER (self));
253         g_return_if_fail (NM_IS_AUTH_SUBJECT (subject));
254         g_return_if_fail (nm_auth_subject_is_unix_process (subject));
255         g_return_if_fail (action_id != NULL);
256         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
257
258         priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
259
260         g_return_if_fail (priv->polkit_enabled);
261
262         flags = allow_user_interaction
263             ? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION
264             : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
265
266         subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject);
267         g_assert (g_variant_is_floating (subject_value));
268
269         /* ((PolkitDetails *)NULL) */
270         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
271         details_value = g_variant_builder_end (&builder);
272
273         data = g_new0 (CheckAuthData, 1);
274         data->call_id = ++priv->call_id_counter;
275         data->self = g_object_ref (self);
276         data->simple = g_simple_async_result_new (G_OBJECT (self),
277                                                   callback,
278                                                   user_data,
279                                                   nm_auth_manager_polkit_authority_check_authorization);
280         if (cancellable != NULL) {
281                 data->cancellation_id = g_strdup_printf ("cancellation-id-%u", data->call_id);
282                 data->cancellable = g_object_ref (cancellable);
283         }
284
285         data->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)",
286                                                subject_value,
287                                                action_id,
288                                                details_value,
289                                                (guint32) flags,
290                                                data->cancellation_id != NULL ? data->cancellation_id : "");
291
292         if (priv->new_proxy_cancellable) {
293                 _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (wait for proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
294
295                 priv->queued_calls = g_slist_prepend (priv->queued_calls, data);
296         } else if (!priv->proxy) {
297                 _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (fails due to invalid DBUS proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
298
299                 _call_check_authorization_complete_with_error (data, "invalid DBUS proxy");
300         } else {
301                 _LOGD ("call[%u]: CheckAuthorization(%s), subject=%s", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
302
303                 _call_check_authorization (data);
304         }
305 }
306
307 gboolean
308 nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self,
309                                                              GAsyncResult *res,
310                                                              gboolean *out_is_authorized,
311                                                              gboolean *out_is_challenge,
312                                                              GError **error)
313 {
314         gboolean success = FALSE;
315         gboolean is_authorized = FALSE;
316         gboolean is_challenge = FALSE;
317
318         g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
319         g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE);
320         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
321
322         if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) {
323                 CheckAuthorizationResult *result;
324
325                 result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
326                 is_authorized = !!result->is_authorized;
327                 is_challenge = !!result->is_challenge;
328                 success = TRUE;
329         }
330         g_assert ((success && !error) || (!success || error));
331
332         if (out_is_authorized)
333                 *out_is_authorized = is_authorized;
334         if (out_is_challenge)
335                 *out_is_challenge = is_challenge;
336         return success;
337 }
338
339 /*****************************************************************************/
340
341 static void
342 _emit_changed_signal (NMAuthManager *self)
343 {
344         _LOGD ("emit changed signal");
345         g_signal_emit_by_name (self, NM_AUTH_MANAGER_SIGNAL_CHANGED);
346 }
347
348 static void
349 _log_name_owner (NMAuthManager *self, char **out_name_owner)
350 {
351         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
352         char *name_owner;
353
354         name_owner = g_dbus_proxy_get_name_owner (priv->proxy);
355         if (name_owner)
356                 _LOGD ("dbus name owner: '%s'", name_owner);
357         else
358                 _LOGD ("dbus name owner: none");
359
360         if (out_name_owner)
361                 *out_name_owner = name_owner;
362         else
363                 g_free (name_owner);
364 }
365
366 static void
367 _dbus_on_name_owner_notify_cb (GObject    *object,
368                                GParamSpec *pspec,
369                                gpointer    user_data)
370 {
371         NMAuthManager *self = user_data;
372         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
373         char *name_owner;
374
375         g_return_if_fail (priv->proxy == (void *) object);
376
377         _log_name_owner (self, &name_owner);
378
379         if (!name_owner) {
380                 /* when the name disappears, we also want to raise a emit signal.
381                  * When it appears, we raise one already. */
382                 _emit_changed_signal (self);
383         }
384
385         g_free (name_owner);
386 }
387
388 static void
389 _dbus_on_changed_signal_cb (GDBusProxy *proxy,
390                             gpointer    user_data)
391 {
392         NMAuthManager *self = user_data;
393         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
394
395         g_return_if_fail (priv->proxy == proxy);
396
397         _LOGD ("dbus signal: \"Changed\"");
398         _emit_changed_signal (self);
399 }
400
401 static void
402 _dbus_new_proxy_cb (GObject *source_object,
403                     GAsyncResult *res,
404                     gpointer user_data)
405 {
406         NMAuthManager **p_self = user_data;
407         NMAuthManager *self = NULL;
408         NMAuthManagerPrivate *priv;
409         GError *error = NULL;
410         GDBusProxy *proxy;
411         CheckAuthData *data;
412
413         proxy = g_dbus_proxy_new_for_bus_finish  (res, &error);
414
415         if (!*p_self) {
416                 _LOGD ("_dbus_new_proxy_cb(): manager destroyed before callback finished. Abort");
417                 g_clear_object (&proxy);
418                 g_clear_error (&error);
419                 g_free (p_self);
420                 return;
421         }
422         self = *p_self;
423         g_object_remove_weak_pointer (G_OBJECT (self), (void **)p_self);
424         g_free (p_self);
425
426         priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
427
428         g_return_if_fail (priv->new_proxy_cancellable);
429         g_return_if_fail (!priv->proxy);
430
431         g_clear_object (&priv->new_proxy_cancellable);
432
433         priv->queued_calls = g_slist_reverse (priv->queued_calls);
434
435         priv->proxy = proxy;
436         if (!priv->proxy) {
437                 _LOGE ("could not get polkit proxy: %s", error->message);
438                 g_clear_error (&error);
439
440                 while (priv->queued_calls) {
441                         data = priv->queued_calls->data;
442                         priv->queued_calls = g_slist_remove (priv->queued_calls, data);
443
444                         _call_check_authorization_complete_with_error (data, "error creating DBUS proxy");
445                 }
446                 return;
447         }
448
449         g_signal_connect (priv->proxy,
450                           "notify::g-name-owner",
451                           G_CALLBACK (_dbus_on_name_owner_notify_cb),
452                           self);
453         _nm_dbus_signal_connect (priv->proxy, "Changed", NULL,
454                                  G_CALLBACK (_dbus_on_changed_signal_cb),
455                                  self);
456
457         _log_name_owner (self, NULL);
458
459         while (priv->queued_calls) {
460                 data = priv->queued_calls->data;
461                 priv->queued_calls = g_slist_remove (priv->queued_calls, data);
462                 _LOGD ("call[%u]: CheckAuthorization invoke now", data->call_id);
463                 _call_check_authorization (data);
464         }
465         _emit_changed_signal (self);
466 }
467
468 #endif
469
470 /*****************************************************************************/
471
472 NMAuthManager *
473 nm_auth_manager_get ()
474 {
475         g_return_val_if_fail (singleton_instance, NULL);
476
477         return singleton_instance;
478 }
479
480 NMAuthManager *
481 nm_auth_manager_setup (gboolean polkit_enabled)
482 {
483         NMAuthManager *self;
484
485         g_return_val_if_fail (!singleton_instance, singleton_instance);
486
487         self = g_object_new (NM_TYPE_AUTH_MANAGER,
488                              NM_AUTH_MANAGER_POLKIT_ENABLED, polkit_enabled,
489                              NULL);
490         _LOGD ("set instance");
491
492         singleton_instance = self;
493         nm_singleton_instance_register ();
494
495         nm_log_dbg (LOGD_CORE, "setup %s singleton (%p)", "NMAuthManager", singleton_instance);
496
497         return self;
498 }
499
500 /*****************************************************************************/
501
502 static void
503 get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
504 {
505         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object);
506
507         switch (prop_id) {
508         case PROP_POLKIT_ENABLED:
509                 g_value_set_boolean (value, priv->polkit_enabled);
510                 break;
511         default:
512                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513                 break;
514         }
515 }
516
517 static void
518 set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
519 {
520         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object);
521
522         switch (prop_id) {
523         case PROP_POLKIT_ENABLED:
524                 /* construct only */
525                 priv->polkit_enabled = !!g_value_get_boolean (value);
526                 break;
527         default:
528                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
529                 break;
530         }
531 }
532
533 static void
534 nm_auth_manager_init (NMAuthManager *self)
535 {
536 }
537
538 static void
539 constructed (GObject *object)
540 {
541         NMAuthManager *self = NM_AUTH_MANAGER (object);
542         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
543
544         G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object);
545
546 #if WITH_POLKIT
547         _LOGD ("create auth-manager: polkit %s", priv->polkit_enabled ? "enabled" : "disabled");
548
549         if (priv->polkit_enabled) {
550                 NMAuthManager **p_self;
551
552                 priv->new_proxy_cancellable = g_cancellable_new ();
553                 p_self = g_new (NMAuthManager *, 1);
554                 *p_self = self;
555                 g_object_add_weak_pointer (G_OBJECT (self), (void **) p_self);
556                 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
557                                           G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
558                                           NULL,
559                                           POLKIT_SERVICE,
560                                           POLKIT_OBJECT_PATH,
561                                           POLKIT_INTERFACE,
562                                           priv->new_proxy_cancellable,
563                                           _dbus_new_proxy_cb,
564                                           p_self);
565         }
566 #else
567         if (priv->polkit_enabled)
568                 _LOGW ("create auth-manager: polkit disabled at compile time. All authentication requests will fail");
569         else
570                 _LOGD ("create auth-manager: polkit disabled at compile time");
571 #endif
572 }
573
574
575 static void
576 dispose (GObject *object)
577 {
578         NMAuthManager* self = NM_AUTH_MANAGER (object);
579 #if WITH_POLKIT
580         NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
581 #endif
582
583         _LOGD ("dispose");
584
585 #if WITH_POLKIT
586         /* since we take a reference for each queued call, we don't expect to have any queued calls in dispose() */
587         g_assert (!priv->queued_calls);
588
589         if (priv->new_proxy_cancellable) {
590                 g_cancellable_cancel (priv->new_proxy_cancellable);
591                 g_clear_object (&priv->new_proxy_cancellable);
592         }
593
594         if (priv->proxy) {
595                 g_signal_handlers_disconnect_by_data (priv->proxy, self);
596                 g_clear_object (&priv->proxy);
597         }
598 #endif
599
600         G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object);
601 }
602
603 static void
604 nm_auth_manager_class_init (NMAuthManagerClass *klass)
605 {
606         GObjectClass *object_class = G_OBJECT_CLASS (klass);
607
608         g_type_class_add_private (klass, sizeof (NMAuthManagerPrivate));
609
610         object_class->get_property = get_property;
611         object_class->set_property = set_property;
612         object_class->constructed = constructed;
613         object_class->dispose = dispose;
614
615         g_object_class_install_property
616             (object_class, PROP_POLKIT_ENABLED,
617              g_param_spec_boolean (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "",
618                                    FALSE,
619                                    G_PARAM_READWRITE |
620                                    G_PARAM_CONSTRUCT_ONLY |
621                                    G_PARAM_STATIC_STRINGS));
622
623         signals[CHANGED_SIGNAL] = g_signal_new (NM_AUTH_MANAGER_SIGNAL_CHANGED,
624                                                 NM_TYPE_AUTH_MANAGER,
625                                                 G_SIGNAL_RUN_LAST,
626                                                 0,                      /* class offset     */
627                                                 NULL,                   /* accumulator      */
628                                                 NULL,                   /* accumulator data */
629                                                 g_cclosure_marshal_VOID__VOID,
630                                                 G_TYPE_NONE,
631                                                 0);
632
633 }
634