summaryrefslogtreecommitdiff
path: root/src/nm-manager-auth.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-05-28 18:23:00 -0700
committerDan Williams <dcbw@redhat.com>2010-05-28 18:23:00 -0700
commit716a9c6c0df95c18840c700a4320c81869b8b78d (patch)
tree7e166ae6f0d44476307afaab81a8b197f1b46511 /src/nm-manager-auth.c
parent6810ef1422ec873240520b4f0b6e626908bc320c (diff)
downloadNetworkManager-716a9c6c0df95c18840c700a4320c81869b8b78d.tar.gz
core: add permissions framework for various operations (rh #585182) (bgo #619323)
Diffstat (limited to 'src/nm-manager-auth.c')
-rw-r--r--src/nm-manager-auth.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c
new file mode 100644
index 0000000000..bc04e2544b
--- /dev/null
+++ b/src/nm-manager-auth.c
@@ -0,0 +1,212 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#include "nm-manager-auth.h"
+#include "nm-logging.h"
+
+#include <dbus/dbus-glib-lowlevel.h>
+#include <string.h>
+
+struct NMAuthChain {
+ guint32 refcount;
+ PolkitAuthority *authority;
+ GSList *calls;
+
+ DBusGMethodInvocation *context;
+ GError *error;
+
+ NMAuthChainResultFunc done_func;
+ NMAuthChainCallFunc call_func;
+ gpointer user_data;
+ gpointer user_data2;
+};
+
+typedef struct {
+ NMAuthChain *chain;
+ GCancellable *cancellable;
+ char *permission;
+ gboolean disposed;
+} PolkitCall;
+
+
+NMAuthChain *
+nm_auth_chain_new (PolkitAuthority *authority,
+ DBusGMethodInvocation *context,
+ NMAuthChainResultFunc done_func,
+ NMAuthChainCallFunc call_func,
+ gpointer user_data,
+ gpointer user_data2)
+{
+ NMAuthChain *self;
+
+ self = g_malloc0 (sizeof (NMAuthChain));
+ self->refcount = 1;
+ self->authority = g_object_ref (authority);
+ self->done_func = done_func;
+ self->call_func = call_func;
+ self->context = context;
+ self->user_data = user_data;
+ self->user_data2 = user_data2;
+ return self;
+}
+
+static void
+nm_auth_chain_check_done (NMAuthChain *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (g_slist_length (self->calls) == 0) {
+ /* Ensure we say alive across the callback */
+ self->refcount++;
+ self->done_func (self, self->error, self->context, self->user_data, self->user_data2);
+ nm_auth_chain_unref (self);
+ }
+}
+
+static void
+polkit_call_cancel (PolkitCall *call)
+{
+ call->disposed = TRUE;
+ g_cancellable_cancel (call->cancellable);
+}
+
+static void
+polkit_call_free (PolkitCall *call)
+{
+ g_return_if_fail (call != NULL);
+
+ call->disposed = TRUE;
+ g_free (call->permission);
+ call->permission = NULL;
+ call->chain = NULL;
+ g_object_unref (call->cancellable);
+ call->cancellable = NULL;
+ g_free (call);
+}
+
+static void
+pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+ PolkitCall *call = user_data;
+ NMAuthChain *chain;
+ PolkitAuthorizationResult *pk_result;
+ GError *error = NULL;
+ guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN;
+
+ /* If the call is already disposed do nothing */
+ if (call->disposed) {
+ polkit_call_free (call);
+ return;
+ }
+
+ chain = call->chain;
+ chain->calls = g_slist_remove (chain->calls, call);
+
+ pk_result = polkit_authority_check_authorization_finish (chain->authority,
+ result,
+ &error);
+ if (error) {
+ if (!chain->error)
+ chain->error = g_error_copy (error);
+
+ nm_log_warn (LOGD_CORE, "error requesting auth for %s: (%d) %s",
+ call->permission,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ } else {
+ if (polkit_authorization_result_get_is_authorized (pk_result)) {
+ /* Caller has the permission */
+ call_result = NM_AUTH_CALL_RESULT_YES;
+ } else if (polkit_authorization_result_get_is_challenge (pk_result)) {
+ /* Caller could authenticate to get the permission */
+ call_result = NM_AUTH_CALL_RESULT_AUTH;
+ } else
+ call_result = NM_AUTH_CALL_RESULT_NO;
+ }
+
+ chain->call_func (chain, call->permission, error, call_result, chain->user_data, chain->user_data2);
+ nm_auth_chain_check_done (chain);
+
+ g_clear_error (&error);
+ polkit_call_free (call);
+ if (pk_result)
+ g_object_unref (pk_result);
+}
+
+gboolean
+nm_auth_chain_add_call (NMAuthChain *self,
+ const char *permission)
+{
+ PolkitCall *call;
+ char *sender;
+ PolkitSubject *subject;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (self->context != NULL, FALSE);
+ g_return_val_if_fail (permission != NULL, FALSE);
+
+ sender = dbus_g_method_get_sender (self->context);
+ subject = polkit_system_bus_name_new (sender);
+ g_free (sender);
+ if (!subject)
+ return FALSE;
+
+ call = g_malloc0 (sizeof (PolkitCall));
+ call->chain = self;
+ call->permission = g_strdup (permission);
+ call->cancellable = g_cancellable_new ();
+
+ self->calls = g_slist_append (self->calls, call);
+
+ polkit_authority_check_authorization (self->authority,
+ subject,
+ permission,
+ NULL,
+ POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE,
+ call->cancellable,
+ pk_call_cb,
+ call);
+ g_object_unref (subject);
+ return TRUE;
+}
+
+void
+nm_auth_chain_unref (NMAuthChain *self)
+{
+ GSList *iter;
+
+ g_return_if_fail (self != NULL);
+
+ self->refcount--;
+ if (self->refcount > 0)
+ return;
+
+ g_object_unref (self->authority);
+
+ for (iter = self->calls; iter; iter = g_slist_next (iter))
+ polkit_call_cancel ((PolkitCall *) iter->data);
+ g_slist_free (self->calls);
+
+ g_clear_error (&self->error);
+
+ memset (self, 0, sizeof (NMAuthChain));
+ g_free (self);
+}
+