Blame src/nm-auth-manager.c

Packit Service b23acc
// SPDX-License-Identifier: GPL-2.0+
Packit Service b23acc
/*
Packit Service b23acc
 * Copyright (C) 2014 Red Hat, Inc.
Packit Service b23acc
 */
Packit Service b23acc
Packit Service b23acc
#include "nm-default.h"
Packit Service b23acc
Packit Service b23acc
#include "nm-auth-manager.h"
Packit Service b23acc
Packit Service b23acc
#include "c-list/src/c-list.h"
Packit Service b23acc
#include "nm-glib-aux/nm-dbus-aux.h"
Packit Service b23acc
#include "nm-errors.h"
Packit Service b23acc
#include "nm-core-internal.h"
Packit Service b23acc
#include "nm-dbus-manager.h"
Packit Service b23acc
#include "NetworkManagerUtils.h"
Packit Service b23acc
Packit Service b23acc
#define POLKIT_SERVICE                      "org.freedesktop.PolicyKit1"
Packit Service b23acc
#define POLKIT_OBJECT_PATH                  "/org/freedesktop/PolicyKit1/Authority"
Packit Service b23acc
#define POLKIT_INTERFACE                    "org.freedesktop.PolicyKit1.Authority"
Packit Service b23acc
Packit Service b23acc
#define CANCELLATION_ID_PREFIX "cancellation-id-"
Packit Service b23acc
#define CANCELLATION_TIMEOUT_MS 5000
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
Packit Service b23acc
	PROP_POLKIT_ENABLED,
Packit Service b23acc
);
Packit Service b23acc
Packit Service b23acc
enum {
Packit Service b23acc
	CHANGED_SIGNAL,
Packit Service b23acc
	LAST_SIGNAL,
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
static guint signals[LAST_SIGNAL] = {0};
Packit Service b23acc
Packit Service b23acc
typedef struct {
Packit Service b23acc
	CList calls_lst_head;
Packit Service b23acc
	GDBusConnection *dbus_connection;
Packit Service b23acc
	GCancellable *main_cancellable;
Packit Service b23acc
	char *name_owner;
Packit Service b23acc
	guint64 call_numid_counter;
Packit Service b23acc
	guint changed_id;
Packit Service b23acc
	guint name_owner_changed_id;
Packit Service b23acc
	bool disposing:1;
Packit Service b23acc
	bool shutting_down:1;
Packit Service b23acc
	bool got_name_owner:1;
Packit Service b23acc
	NMAuthPolkitMode auth_polkit_mode:3;
Packit Service b23acc
} NMAuthManagerPrivate;
Packit Service b23acc
Packit Service b23acc
struct _NMAuthManager {
Packit Service b23acc
	GObject parent;
Packit Service b23acc
	NMAuthManagerPrivate _priv;
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
struct _NMAuthManagerClass {
Packit Service b23acc
	GObjectClass parent;
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT)
Packit Service b23acc
Packit Service b23acc
#define NM_AUTH_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAuthManager, NM_IS_AUTH_MANAGER)
Packit Service b23acc
Packit Service b23acc
NM_DEFINE_SINGLETON_REGISTER (NMAuthManager);
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
#define _NMLOG_PREFIX_NAME    "auth"
Packit Service b23acc
#define _NMLOG_DOMAIN         LOGD_CORE
Packit Service b23acc
#define _NMLOG(level, ...) \
Packit Service b23acc
    G_STMT_START { \
Packit Service b23acc
        if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
Packit Service b23acc
            char __prefix[30] = _NMLOG_PREFIX_NAME; \
Packit Service b23acc
            \
Packit Service b23acc
            if ((self) != singleton_instance) \
Packit Service b23acc
                g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", (self)); \
Packit Service b23acc
            _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \
Packit Service b23acc
                     "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
Packit Service b23acc
                     __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
Packit Service b23acc
        } \
Packit Service b23acc
    } G_STMT_END
Packit Service b23acc
Packit Service b23acc
#define _NMLOG2(level, call_id, ...) \
Packit Service b23acc
    G_STMT_START { \
Packit Service b23acc
        if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
Packit Service b23acc
            NMAuthManagerCallId *_call_id = (call_id); \
Packit Service b23acc
            char __prefix[30] = _NMLOG_PREFIX_NAME; \
Packit Service b23acc
            \
Packit Service b23acc
            if (_call_id->self != singleton_instance) \
Packit Service b23acc
                g_snprintf (__prefix, sizeof (__prefix), ""_NMLOG_PREFIX_NAME"[%p]", _call_id->self); \
Packit Service b23acc
            _nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \
Packit Service b23acc
                     "%s: call[%"G_GUINT64_FORMAT"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
Packit Service b23acc
                     __prefix, \
Packit Service b23acc
                     _call_id->call_numid \
Packit Service b23acc
                     _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
Packit Service b23acc
        } \
Packit Service b23acc
    } G_STMT_END
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
gboolean
Packit Service b23acc
nm_auth_manager_get_polkit_enabled (NMAuthManager *self)
Packit Service b23acc
{
Packit Service b23acc
	g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
Packit Service b23acc
Packit Service b23acc
	return NM_AUTH_MANAGER_GET_PRIVATE (self)->dbus_connection != NULL;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_emit_changed_signal (NMAuthManager *self)
Packit Service b23acc
{
Packit Service b23acc
	g_signal_emit (self, signals[CHANGED_SIGNAL], 0);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
typedef enum {
Packit Service b23acc
	POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE                   = 0,
Packit Service b23acc
	POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0),
Packit Service b23acc
} PolkitCheckAuthorizationFlags;
Packit Service b23acc
Packit Service b23acc
struct _NMAuthManagerCallId {
Packit Service b23acc
	CList calls_lst;
Packit Service b23acc
	NMAuthManager *self;
Packit Service b23acc
	GCancellable *dbus_cancellable;
Packit Service b23acc
	NMAuthManagerCheckAuthorizationCallback callback;
Packit Service b23acc
	gpointer user_data;
Packit Service b23acc
	guint64 call_numid;
Packit Service b23acc
	guint idle_id;
Packit Service b23acc
	bool idle_is_authorized:1;
Packit Service b23acc
};
Packit Service b23acc
Packit Service b23acc
#define cancellation_id_to_str_a(call_numid) \
Packit Service b23acc
	nm_sprintf_bufa (NM_STRLEN (CANCELLATION_ID_PREFIX) + 60, \
Packit Service b23acc
	                 CANCELLATION_ID_PREFIX"%"G_GUINT64_FORMAT, \
Packit Service b23acc
	                 (call_numid))
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_call_id_free (NMAuthManagerCallId *call_id)
Packit Service b23acc
{
Packit Service b23acc
	c_list_unlink (&call_id->calls_lst);
Packit Service b23acc
	nm_clear_g_source (&call_id->idle_id);
Packit Service b23acc
Packit Service b23acc
	if (call_id->dbus_cancellable) {
Packit Service b23acc
		/* we have a pending D-Bus call. We keep the call-id instance alive
Packit Service b23acc
		 * for _call_check_authorize_cb() */
Packit Service b23acc
		g_cancellable_cancel (call_id->dbus_cancellable);
Packit Service b23acc
		return;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	g_object_unref (call_id->self);
Packit Service b23acc
	g_slice_free (NMAuthManagerCallId, call_id);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_call_id_invoke_callback (NMAuthManagerCallId *call_id,
Packit Service b23acc
                          gboolean is_authorized,
Packit Service b23acc
                          gboolean is_challenge,
Packit Service b23acc
                          GError *error)
Packit Service b23acc
{
Packit Service b23acc
	c_list_unlink (&call_id->calls_lst);
Packit Service b23acc
Packit Service b23acc
	call_id->callback (call_id->self,
Packit Service b23acc
	                   call_id,
Packit Service b23acc
	                   is_authorized,
Packit Service b23acc
	                   is_challenge,
Packit Service b23acc
	                   error,
Packit Service b23acc
	                   call_id->user_data);
Packit Service b23acc
	_call_id_free (call_id);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
cancel_check_authorization_cb (GObject *source,
Packit Service b23acc
                               GAsyncResult *res,
Packit Service b23acc
                               gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerCallId *call_id = user_data;
Packit Service b23acc
	gs_unref_variant GVariant *value = NULL;
Packit Service b23acc
	gs_free_error GError *error= NULL;
Packit Service b23acc
Packit Service b23acc
	value = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error);
Packit Service b23acc
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit Service b23acc
		_LOG2T (call_id, "cancel request was cancelled");
Packit Service b23acc
	else if (error)
Packit Service b23acc
		_LOG2T (call_id, "cancel request failed: %s", error->message);
Packit Service b23acc
	else
Packit Service b23acc
		_LOG2T (call_id, "cancel request succeeded");
Packit Service b23acc
Packit Service b23acc
	_call_id_free (call_id);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_call_check_authorize_cb (GObject *proxy,
Packit Service b23acc
                          GAsyncResult *res,
Packit Service b23acc
                          gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerCallId *call_id = user_data;
Packit Service b23acc
	NMAuthManager *self;
Packit Service b23acc
	NMAuthManagerPrivate *priv;
Packit Service b23acc
	gs_unref_variant GVariant *value = NULL;
Packit Service b23acc
	gs_free_error GError *error = NULL;
Packit Service b23acc
	gboolean is_authorized = FALSE;
Packit Service b23acc
	gboolean is_challenge = FALSE;
Packit Service b23acc
Packit Service b23acc
	/* we need to clear the cancelable, to signal for _call_id_free() that we
Packit Service b23acc
	 * are not in a pending call.
Packit Service b23acc
	 *
Packit Service b23acc
	 * Note how _call_id_free() kept call-id alive, even if the request was
Packit Service b23acc
	 * already cancelled. */
Packit Service b23acc
	g_clear_object (&call_id->dbus_cancellable);
Packit Service b23acc
Packit Service b23acc
	self = call_id->self;
Packit Service b23acc
	priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	value = g_dbus_connection_call_finish (G_DBUS_CONNECTION (proxy), res, &error);
Packit Service b23acc
Packit Service b23acc
	if (nm_utils_error_is_cancelled (error)) {
Packit Service b23acc
		/* call_id was cancelled externally, but _call_id_free() kept call_id
Packit Service b23acc
		 * alive (and it has still the reference on @self. */
Packit Service b23acc
Packit Service b23acc
		if (!priv->main_cancellable) {
Packit Service b23acc
			/* we do a forced shutdown. There is no more time for cancelling... */
Packit Service b23acc
			_call_id_free (call_id);
Packit Service b23acc
Packit Service b23acc
			/* this shouldn't really happen, because:
Packit Service b23acc
			 * nm_auth_manager_check_authorization() only scheduled the D-Bus request at a time when
Packit Service b23acc
			 * main_cancellable was still set. It means, somebody called force-shutdown
Packit Service b23acc
			 * after call-id was schedule.
Packit Service b23acc
			 * force-shutdown should only be called after:
Packit Service b23acc
			 *   - cancel all pending requests
Packit Service b23acc
			 *   - give enough time to cancel the request and schedule a D-Bus call
Packit Service b23acc
			 *     to CancelCheckAuthorization (below), before issuing force-shutdown. */
Packit Service b23acc
			g_return_if_reached ();
Packit Service b23acc
		}
Packit Service b23acc
Packit Service b23acc
		g_dbus_connection_call (priv->dbus_connection,
Packit Service b23acc
		                        POLKIT_SERVICE,
Packit Service b23acc
		                        POLKIT_OBJECT_PATH,
Packit Service b23acc
		                        POLKIT_INTERFACE,
Packit Service b23acc
		                        "CancelCheckAuthorization",
Packit Service b23acc
		                        g_variant_new ("(s)",
Packit Service b23acc
		                                       cancellation_id_to_str_a (call_id->call_numid)),
Packit Service b23acc
		                        G_VARIANT_TYPE ("()"),
Packit Service b23acc
		                        G_DBUS_CALL_FLAGS_NONE,
Packit Service b23acc
		                        CANCELLATION_TIMEOUT_MS,
Packit Service b23acc
		                        priv->main_cancellable,
Packit Service b23acc
		                        cancel_check_authorization_cb,
Packit Service b23acc
		                        call_id);
Packit Service b23acc
		return;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (!error) {
Packit Service b23acc
		g_variant_get (value,
Packit Service b23acc
		               "((bb@a{ss}))",
Packit Service b23acc
		               &is_authorized,
Packit Service b23acc
		               &is_challenge,
Packit Service b23acc
		               NULL);
Packit Service b23acc
		_LOG2T (call_id, "completed: authorized=%d, challenge=%d",
Packit Service b23acc
		        is_authorized, is_challenge);
Packit Service b23acc
	} else
Packit Service b23acc
		_LOG2T (call_id, "completed: failed: %s", error->message);
Packit Service b23acc
Packit Service b23acc
	_call_id_invoke_callback (call_id, is_authorized, is_challenge, error);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static gboolean
Packit Service b23acc
_call_on_idle (gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerCallId *call_id = user_data;
Packit Service b23acc
	gboolean is_authorized;
Packit Service b23acc
	gboolean is_challenge = FALSE;
Packit Service b23acc
Packit Service b23acc
	is_authorized = call_id->idle_is_authorized;
Packit Service b23acc
	call_id->idle_id = 0;
Packit Service b23acc
Packit Service b23acc
	_LOG2T (call_id, "completed: authorized=%d, challenge=%d (simulated)",
Packit Service b23acc
	        is_authorized, is_challenge);
Packit Service b23acc
Packit Service b23acc
	_call_id_invoke_callback (call_id, is_authorized, is_challenge, NULL);
Packit Service b23acc
	return G_SOURCE_REMOVE;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*
Packit Service b23acc
 * @callback must never be invoked synchronously.
Packit Service b23acc
 *
Packit Service b23acc
 * @callback is always invoked exactly once, and never synchronously.
Packit Service b23acc
 * You may cancel the invocation with nm_auth_manager_check_authorization_cancel(),
Packit Service b23acc
 * but: you may only do so exactly once, and only before @callback is
Packit Service b23acc
 * invoked. Even if you cancel the request, @callback will still be invoked
Packit Service b23acc
 * (synchronously, during the _cancel() callback).
Packit Service b23acc
 *
Packit Service b23acc
 * The request keeps @self alive (it needs to do so, because when cancelling a
Packit Service b23acc
 * request we might need to do an additional CancelCheckAuthorization call, for
Packit Service b23acc
 * which @self must be live long enough).
Packit Service b23acc
 */
Packit Service b23acc
NMAuthManagerCallId *
Packit Service b23acc
nm_auth_manager_check_authorization (NMAuthManager *self,
Packit Service b23acc
                                     NMAuthSubject *subject,
Packit Service b23acc
                                     const char *action_id,
Packit Service b23acc
                                     gboolean allow_user_interaction,
Packit Service b23acc
                                     NMAuthManagerCheckAuthorizationCallback callback,
Packit Service b23acc
                                     gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerPrivate *priv;
Packit Service b23acc
	PolkitCheckAuthorizationFlags flags;
Packit Service b23acc
	char subject_buf[64];
Packit Service b23acc
	NMAuthManagerCallId *call_id;
Packit Service b23acc
Packit Service b23acc
	g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), NULL);
Packit Service b23acc
	g_return_val_if_fail (NM_IN_SET (nm_auth_subject_get_subject_type (subject),
Packit Service b23acc
	                                 NM_AUTH_SUBJECT_TYPE_INTERNAL,
Packit Service b23acc
	                                 NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS),
Packit Service b23acc
	                      NULL);
Packit Service b23acc
	g_return_val_if_fail (action_id, NULL);
Packit Service b23acc
Packit Service b23acc
	priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	g_return_val_if_fail (!priv->disposing, NULL);
Packit Service b23acc
	g_return_val_if_fail (!priv->shutting_down, NULL);
Packit Service b23acc
Packit Service b23acc
	flags = allow_user_interaction
Packit Service b23acc
	    ? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION
Packit Service b23acc
	    : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
Packit Service b23acc
Packit Service b23acc
	call_id = g_slice_new (NMAuthManagerCallId);
Packit Service b23acc
	*call_id = (NMAuthManagerCallId) {
Packit Service b23acc
		.self               = g_object_ref (self),
Packit Service b23acc
		.callback           = callback,
Packit Service b23acc
		.user_data          = user_data,
Packit Service b23acc
		.call_numid         = ++priv->call_numid_counter,
Packit Service b23acc
		.idle_is_authorized = TRUE,
Packit Service b23acc
	};
Packit Service b23acc
	c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst);
Packit Service b23acc
Packit Service b23acc
	if (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL) {
Packit Service b23acc
		_LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for internal request)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
Packit Service b23acc
		call_id->idle_id = g_idle_add (_call_on_idle, call_id);
Packit Service b23acc
	} else if (nm_auth_subject_get_unix_process_uid (subject) == 0) {
Packit Service b23acc
		_LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for root)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
Packit Service b23acc
		call_id->idle_id = g_idle_add (_call_on_idle, call_id);
Packit Service b23acc
	} else if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) {
Packit Service b23acc
		_LOG2T (call_id, "CheckAuthorization(%s), subject=%s (PolicyKit disabled and always %s authorization to non-root user)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)),
Packit Service b23acc
		        priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL ? "grant" : "deny");
Packit Service b23acc
		call_id->idle_is_authorized = (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ALLOW_ALL);
Packit Service b23acc
		call_id->idle_id = g_idle_add (_call_on_idle, call_id);
Packit Service b23acc
	} else {
Packit Service b23acc
		GVariant *parameters;
Packit Service b23acc
		GVariantBuilder builder;
Packit Service b23acc
		GVariant *subject_value;
Packit Service b23acc
		GVariant *details_value;
Packit Service b23acc
Packit Service b23acc
		subject_value = nm_auth_subject_unix_to_polkit_gvariant (subject);
Packit Service b23acc
		nm_assert (g_variant_is_floating (subject_value));
Packit Service b23acc
Packit Service b23acc
		/* ((PolkitDetails *)NULL) */
Packit Service b23acc
		g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
Packit Service b23acc
		details_value = g_variant_builder_end (&builder);
Packit Service b23acc
Packit Service b23acc
		parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)",
Packit Service b23acc
		                            subject_value,
Packit Service b23acc
		                            action_id,
Packit Service b23acc
		                            details_value,
Packit Service b23acc
		                            (guint32) flags,
Packit Service b23acc
		                            cancellation_id_to_str_a (call_id->call_numid));
Packit Service b23acc
Packit Service b23acc
		_LOG2T (call_id, "CheckAuthorization(%s), subject=%s", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
Packit Service b23acc
Packit Service b23acc
		call_id->dbus_cancellable = g_cancellable_new ();
Packit Service b23acc
Packit Service b23acc
		nm_assert (priv->main_cancellable);
Packit Service b23acc
Packit Service b23acc
		g_dbus_connection_call (priv->dbus_connection,
Packit Service b23acc
		                        POLKIT_SERVICE,
Packit Service b23acc
		                        POLKIT_OBJECT_PATH,
Packit Service b23acc
		                        POLKIT_INTERFACE,
Packit Service b23acc
		                        "CheckAuthorization",
Packit Service b23acc
		                        parameters,
Packit Service b23acc
		                        G_VARIANT_TYPE ("((bba{ss}))"),
Packit Service b23acc
		                        G_DBUS_CALL_FLAGS_NONE,
Packit Service b23acc
		                        G_MAXINT, /* no timeout */
Packit Service b23acc
		                        call_id->dbus_cancellable,
Packit Service b23acc
		                        _call_check_authorize_cb,
Packit Service b23acc
		                        call_id);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	return call_id;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_auth_manager_check_authorization_cancel (NMAuthManagerCallId *call_id)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager *self;
Packit Service b23acc
	gs_free_error GError *error = NULL;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (call_id);
Packit Service b23acc
Packit Service b23acc
	self = call_id->self;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (NM_IS_AUTH_MANAGER (self));
Packit Service b23acc
	g_return_if_fail (!c_list_is_empty (&call_id->calls_lst));
Packit Service b23acc
Packit Service b23acc
	nm_assert (c_list_contains (&NM_AUTH_MANAGER_GET_PRIVATE (self)->calls_lst_head, &call_id->calls_lst));
Packit Service b23acc
Packit Service b23acc
	nm_utils_error_set_cancelled (&error, FALSE, "NMAuthManager");
Packit Service b23acc
	_LOG2T (call_id, "completed: failed due to call cancelled");
Packit Service b23acc
	_call_id_invoke_callback (call_id,
Packit Service b23acc
	                          FALSE,
Packit Service b23acc
	                          FALSE,
Packit Service b23acc
	                          error);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
changed_signal_cb (GDBusConnection *connection,
Packit Service b23acc
                   const char *sender_name,
Packit Service b23acc
                   const char *object_path,
Packit Service b23acc
                   const char *interface_name,
Packit Service b23acc
                   const char *signal_name,
Packit Service b23acc
                   GVariant *parameters,
Packit Service b23acc
                   gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager *self = user_data;
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
	gboolean valid_sender;
Packit Service b23acc
Packit Service b23acc
	nm_assert (nm_streq0 (signal_name, "Changed"));
Packit Service b23acc
Packit Service b23acc
	valid_sender = nm_streq0 (priv->name_owner, sender_name);
Packit Service b23acc
Packit Service b23acc
	_LOGD ("dbus-signal: \"Changed\" notification%s", valid_sender ? "" : " (ignore)");
Packit Service b23acc
Packit Service b23acc
	if (valid_sender)
Packit Service b23acc
		_emit_changed_signal (self);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_name_owner_changed (NMAuthManager *self,
Packit Service b23acc
                     const char *name_owner,
Packit Service b23acc
                     gboolean is_initial)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
	gboolean is_changed;
Packit Service b23acc
	gs_free char *old_name_owner = NULL;
Packit Service b23acc
Packit Service b23acc
	if (is_initial)
Packit Service b23acc
		priv->got_name_owner = TRUE;
Packit Service b23acc
	else {
Packit Service b23acc
		if (!priv->got_name_owner)
Packit Service b23acc
			return;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	name_owner = nm_str_not_empty (name_owner);
Packit Service b23acc
Packit Service b23acc
	is_changed = !nm_streq0 (priv->name_owner, name_owner);
Packit Service b23acc
	if (is_changed) {
Packit Service b23acc
		old_name_owner = g_steal_pointer (&priv->name_owner);
Packit Service b23acc
		priv->name_owner = g_strdup (name_owner);
Packit Service b23acc
	} else {
Packit Service b23acc
		if (!is_initial)
Packit Service b23acc
			return;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (!priv->name_owner) {
Packit Service b23acc
		if (is_initial)
Packit Service b23acc
			_LOGT ("name-owner: polkit not running");
Packit Service b23acc
		else
Packit Service b23acc
			_LOGT ("name-owner: polkit stopped (was %s)", old_name_owner);
Packit Service b23acc
	} else {
Packit Service b23acc
		if (is_initial)
Packit Service b23acc
			_LOGT ("name-owner: polkit is running (now %s)", priv->name_owner);
Packit Service b23acc
		else if (old_name_owner)
Packit Service b23acc
			_LOGT ("name-owner: polkit restarted (now %s, was %s)", priv->name_owner, old_name_owner);
Packit Service b23acc
		else
Packit Service b23acc
			_LOGT ("name-owner: polkit started (now %s)", priv->name_owner);
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	if (priv->name_owner)
Packit Service b23acc
		_emit_changed_signal (self);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_name_owner_changed_cb (GDBusConnection *connection,
Packit Service b23acc
                        const char *sender_name,
Packit Service b23acc
                        const char *object_path,
Packit Service b23acc
                        const char *interface_name,
Packit Service b23acc
                        const char *signal_name,
Packit Service b23acc
                        GVariant *parameters,
Packit Service b23acc
                        gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager *self = user_data;
Packit Service b23acc
	const char *new_owner;
Packit Service b23acc
Packit Service b23acc
	if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)")))
Packit Service b23acc
		return;
Packit Service b23acc
Packit Service b23acc
	g_variant_get (parameters,
Packit Service b23acc
	               "(&s&s&s)",
Packit Service b23acc
	               NULL,
Packit Service b23acc
	               NULL,
Packit Service b23acc
	               &new_owner);
Packit Service b23acc
Packit Service b23acc
	_name_owner_changed (self, new_owner, FALSE);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
_name_owner_get_cb (const char *name_owner,
Packit Service b23acc
                    GError *error,
Packit Service b23acc
                    gpointer user_data)
Packit Service b23acc
{
Packit Service b23acc
	if (!nm_utils_error_is_cancelled (error))
Packit Service b23acc
		_name_owner_changed (user_data, name_owner, TRUE);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
NMAuthManager *
Packit Service b23acc
nm_auth_manager_get ()
Packit Service b23acc
{
Packit Service b23acc
	g_return_val_if_fail (singleton_instance, NULL);
Packit Service b23acc
Packit Service b23acc
	return singleton_instance;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
void
Packit Service b23acc
nm_auth_manager_force_shutdown (NMAuthManager *self)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerPrivate *priv;
Packit Service b23acc
Packit Service b23acc
	g_return_if_fail (NM_IS_AUTH_MANAGER (self));
Packit Service b23acc
Packit Service b23acc
	priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	/* FIXME(shutdown): ensure we properly call this API during shutdown as
Packit Service b23acc
	 * described next. */
Packit Service b23acc
Packit Service b23acc
	/* while we have pending requests (NMAuthManagerCallId), the instance
Packit Service b23acc
	 * is kept alive.
Packit Service b23acc
	 *
Packit Service b23acc
	 * Even if the caller cancels all pending call-ids, we still need to keep
Packit Service b23acc
	 * a reference to self, in order to handle pending CancelCheckAuthorization
Packit Service b23acc
	 * requests.
Packit Service b23acc
	 *
Packit Service b23acc
	 * To do a coordinated shutdown, do the following:
Packit Service b23acc
	 * - cancel all pending NMAuthManagerCallId requests.
Packit Service b23acc
	 * - ensure everybody unrefs the NMAuthManager instance. If by that, the instance
Packit Service b23acc
	 *   gets destroyed, the shutdown already completed successfully.
Packit Service b23acc
	 * - Otherwise, the object is kept alive by pending CancelCheckAuthorization requests.
Packit Service b23acc
	 *   wait a certain timeout (1 second) for all requests to complete (by watching
Packit Service b23acc
	 *   for destruction of NMAuthManager).
Packit Service b23acc
	 * - if that doesn't happen within timeout, issue nm_auth_manager_force_shutdown() and
Packit Service b23acc
	 *   wait longer. After that, soon the instance should be destroyed and you
Packit Service b23acc
	 *   did a successful shutdown.
Packit Service b23acc
	 * - if the instance was still not destroyed within a short timeout, you leaked
Packit Service b23acc
	 *   resources. You cannot properly shutdown.
Packit Service b23acc
	 */
Packit Service b23acc
Packit Service b23acc
	priv->shutting_down = TRUE;
Packit Service b23acc
	nm_clear_g_cancellable (&priv->main_cancellable);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object);
Packit Service b23acc
	int v_int;
Packit Service b23acc
Packit Service b23acc
	switch (prop_id) {
Packit Service b23acc
	case PROP_POLKIT_ENABLED:
Packit Service b23acc
		/* construct-only */
Packit Service b23acc
		v_int = g_value_get_int (value);
Packit Service b23acc
		g_return_if_fail (NM_IN_SET (v_int, NM_AUTH_POLKIT_MODE_ROOT_ONLY,
Packit Service b23acc
		                                    NM_AUTH_POLKIT_MODE_ALLOW_ALL,
Packit Service b23acc
		                                    NM_AUTH_POLKIT_MODE_USE_POLKIT));
Packit Service b23acc
		priv->auth_polkit_mode = v_int;
Packit Service b23acc
		nm_assert (priv->auth_polkit_mode == v_int);
Packit Service b23acc
		break;
Packit Service b23acc
	default:
Packit Service b23acc
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service b23acc
		break;
Packit Service b23acc
	}
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
/*****************************************************************************/
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_auth_manager_init (NMAuthManager *self)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	c_list_init (&priv->calls_lst_head);
Packit Service b23acc
	priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
constructed (GObject *object)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager *self = NM_AUTH_MANAGER (object);
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
	NMLogLevel logl = LOGL_DEBUG;
Packit Service b23acc
	const char *create_message;
Packit Service b23acc
Packit Service b23acc
	G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object);
Packit Service b23acc
Packit Service b23acc
	if (priv->auth_polkit_mode != NM_AUTH_POLKIT_MODE_USE_POLKIT) {
Packit Service b23acc
		if (priv->auth_polkit_mode == NM_AUTH_POLKIT_MODE_ROOT_ONLY)
Packit Service b23acc
			create_message = "polkit disabled, root-only";
Packit Service b23acc
		else
Packit Service b23acc
			create_message = "polkit disabled, allow-all";
Packit Service b23acc
		goto out;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	priv->dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET);
Packit Service b23acc
Packit Service b23acc
	if (!priv->dbus_connection) {
Packit Service b23acc
		/* This warrants an info level message. */
Packit Service b23acc
		logl = LOGL_INFO;
Packit Service b23acc
		create_message = "D-Bus connection not available. Polkit is disabled and only root will be authorized.";
Packit Service b23acc
		priv->auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
Packit Service b23acc
		goto out;
Packit Service b23acc
	}
Packit Service b23acc
Packit Service b23acc
	priv->main_cancellable = g_cancellable_new ();
Packit Service b23acc
Packit Service b23acc
	priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection,
Packit Service b23acc
	                                                                                      POLKIT_SERVICE,
Packit Service b23acc
	                                                                                      _name_owner_changed_cb,
Packit Service b23acc
	                                                                                      self,
Packit Service b23acc
	                                                                                      NULL);
Packit Service b23acc
Packit Service b23acc
	priv->changed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection,
Packit Service b23acc
	                                                       POLKIT_SERVICE,
Packit Service b23acc
	                                                       POLKIT_INTERFACE,
Packit Service b23acc
	                                                       "Changed",
Packit Service b23acc
	                                                       POLKIT_OBJECT_PATH,
Packit Service b23acc
	                                                       NULL,
Packit Service b23acc
	                                                       G_DBUS_SIGNAL_FLAGS_NONE,
Packit Service b23acc
	                                                       changed_signal_cb,
Packit Service b23acc
	                                                       self,
Packit Service b23acc
	                                                       NULL);
Packit Service b23acc
Packit Service b23acc
	nm_dbus_connection_call_get_name_owner (priv->dbus_connection,
Packit Service b23acc
	                                        POLKIT_SERVICE,
Packit Service b23acc
	                                        -1,
Packit Service b23acc
	                                        priv->main_cancellable,
Packit Service b23acc
	                                        _name_owner_get_cb,
Packit Service b23acc
	                                        self);
Packit Service b23acc
Packit Service b23acc
	create_message = "polkit enabled";
Packit Service b23acc
Packit Service b23acc
out:
Packit Service b23acc
	_NMLOG (logl, "create auth-manager: %s", create_message);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
NMAuthManager *
Packit Service b23acc
nm_auth_manager_setup (NMAuthPolkitMode auth_polkit_mode)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager *self;
Packit Service b23acc
Packit Service b23acc
	g_return_val_if_fail (!singleton_instance, singleton_instance);
Packit Service b23acc
	nm_assert (NM_IN_SET (auth_polkit_mode, NM_AUTH_POLKIT_MODE_ROOT_ONLY,
Packit Service b23acc
	                                        NM_AUTH_POLKIT_MODE_ALLOW_ALL,
Packit Service b23acc
	                                        NM_AUTH_POLKIT_MODE_USE_POLKIT));
Packit Service b23acc
Packit Service b23acc
	self = g_object_new (NM_TYPE_AUTH_MANAGER,
Packit Service b23acc
	                     NM_AUTH_MANAGER_POLKIT_ENABLED, (int) auth_polkit_mode,
Packit Service b23acc
	                     NULL);
Packit Service b23acc
	_LOGD ("set instance");
Packit Service b23acc
Packit Service b23acc
	singleton_instance = self;
Packit Service b23acc
	nm_singleton_instance_register ();
Packit Service b23acc
Packit Service b23acc
	nm_log_dbg (LOGD_CORE, "setup %s singleton ("NM_HASH_OBFUSCATE_PTR_FMT")",
Packit Service b23acc
	            "NMAuthManager", NM_HASH_OBFUSCATE_PTR (singleton_instance));
Packit Service b23acc
Packit Service b23acc
	return self;
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
dispose (GObject *object)
Packit Service b23acc
{
Packit Service b23acc
	NMAuthManager* self = NM_AUTH_MANAGER (object);
Packit Service b23acc
	NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
Packit Service b23acc
Packit Service b23acc
	_LOGD ("dispose");
Packit Service b23acc
Packit Service b23acc
	nm_assert (c_list_is_empty (&priv->calls_lst_head));
Packit Service b23acc
Packit Service b23acc
	priv->disposing = TRUE;
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_cancellable (&priv->main_cancellable);
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_dbus_connection_signal (priv->dbus_connection,
Packit Service b23acc
	                                   &priv->name_owner_changed_id);
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_dbus_connection_signal (priv->dbus_connection,
Packit Service b23acc
	                                   &priv->changed_id);
Packit Service b23acc
Packit Service b23acc
	G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object);
Packit Service b23acc
Packit Service b23acc
	g_clear_object (&priv->dbus_connection);
Packit Service b23acc
Packit Service b23acc
	nm_clear_g_free (&priv->name_owner);
Packit Service b23acc
}
Packit Service b23acc
Packit Service b23acc
static void
Packit Service b23acc
nm_auth_manager_class_init (NMAuthManagerClass *klass)
Packit Service b23acc
{
Packit Service b23acc
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service b23acc
Packit Service b23acc
	object_class->set_property = set_property;
Packit Service b23acc
	object_class->constructed = constructed;
Packit Service b23acc
	object_class->dispose = dispose;
Packit Service b23acc
Packit Service b23acc
	obj_properties[PROP_POLKIT_ENABLED] =
Packit Service b23acc
	     g_param_spec_int (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "",
Packit Service b23acc
	                       NM_AUTH_POLKIT_MODE_ROOT_ONLY, NM_AUTH_POLKIT_MODE_USE_POLKIT, NM_AUTH_POLKIT_MODE_USE_POLKIT,
Packit Service b23acc
	                       G_PARAM_WRITABLE |
Packit Service b23acc
	                       G_PARAM_CONSTRUCT_ONLY |
Packit Service b23acc
	                       G_PARAM_STATIC_STRINGS);
Packit Service b23acc
Packit Service b23acc
	g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
Packit Service b23acc
Packit Service b23acc
	signals[CHANGED_SIGNAL] = g_signal_new (NM_AUTH_MANAGER_SIGNAL_CHANGED,
Packit Service b23acc
	                                        NM_TYPE_AUTH_MANAGER,
Packit Service b23acc
	                                        G_SIGNAL_RUN_LAST,
Packit Service b23acc
	                                        0, NULL, NULL,
Packit Service b23acc
	                                        g_cclosure_marshal_VOID__VOID,
Packit Service b23acc
	                                        G_TYPE_NONE, 0);
Packit Service b23acc
}