summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am10
-rw-r--r--clients/cli/agent.c36
-rw-r--r--clients/cli/meson.build29
-rw-r--r--clients/cli/polkit-agent.c97
-rw-r--r--clients/common/meson.build3
-rw-r--r--clients/common/nm-polkit-listener.c1042
-rw-r--r--clients/common/nm-polkit-listener.h133
-rw-r--r--config.h.meson4
-rw-r--r--configure.ac18
-rw-r--r--contrib/fedora/rpm/NetworkManager.spec2
-rw-r--r--meson.build10
11 files changed, 911 insertions, 473 deletions
diff --git a/Makefile.am b/Makefile.am
index c213eb75c7..249a188c81 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4255,6 +4255,8 @@ clients_common_libnmc_base_la_SOURCES = \
clients/common/nm-vpn-helpers.h \
clients/common/nm-client-utils.c \
clients/common/nm-client-utils.h \
+ clients/common/nm-polkit-listener.c \
+ clients/common/nm-polkit-listener.h \
$(NULL)
EXTRA_DIST += \
@@ -4446,14 +4448,6 @@ clients_cli_nmcli_LDADD = \
$(GLIB_LIBS) \
$(READLINE_LIBS)
-if WITH_POLKIT_AGENT
-clients_cli_nmcli_CPPFLAGS += $(POLKIT_CFLAGS)
-clients_cli_nmcli_SOURCES += \
- clients/common/nm-polkit-listener.c \
- clients/common/nm-polkit-listener.h
-clients_cli_nmcli_LDADD += $(POLKIT_LIBS)
-endif
-
clients_cli_nmcli_LDFLAGS = \
-Wl,--version-script="$(srcdir)/linker-script-binary.ver" \
$(SANITIZER_EXEC_LDFLAGS)
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index f4057df9e9..93b5ca079a 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -16,6 +16,7 @@
#include "utils.h"
#include "nm-secret-agent-simple.h"
#include "polkit-agent.h"
+#include "nm-polkit-listener.h"
static void
usage (void)
@@ -149,27 +150,50 @@ do_agent_secret (NmCli *nmc, int argc, char **argv)
return nmc->return_value;
}
+static void
+polkit_registered (gpointer instance,
+ gpointer user_data)
+{
+ g_print (_("nmcli successfully registered as a polkit agent.\n"));
+}
+
+static void
+polkit_error (gpointer instance,
+ const char *error,
+ gpointer user_data)
+{
+ g_main_loop_quit (loop);
+}
+
static NMCResultCode
do_agent_polkit (NmCli *nmc, int argc, char **argv)
{
- GError *error = NULL;
+ gs_free_error GError *error = NULL;
next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete)
return nmc->return_value;
- /* Initialize polkit agent */
if (!nmc_polkit_agent_init (nmc, TRUE, &error)) {
g_dbus_error_strip_remote_error (error);
- g_string_printf (nmc->return_text, _("Error: polkit agent initialization failed: %s"),
+ g_string_printf (nmc->return_text,
+ _("Error: polkit agent initialization failed: %s"),
error->message);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- g_error_free (error);
} else {
/* We keep running */
nmc->should_wait++;
-
- g_print (_("nmcli successfully registered as a polkit agent.\n"));
+ g_signal_connect (nmc->pk_listener,
+ NM_POLKIT_LISTENER_SIGNAL_ERROR,
+ G_CALLBACK (polkit_error),
+ NULL);
+ g_signal_connect (nmc->pk_listener,
+ NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
+ G_CALLBACK (polkit_registered),
+ NULL);
+
+ /* keep running */
+ nmc->should_wait++;
}
return nmc->return_value;
diff --git a/clients/cli/meson.build b/clients/cli/meson.build
index 1c8148920c..b1b2426910 100644
--- a/clients/cli/meson.build
+++ b/clients/cli/meson.build
@@ -6,18 +6,6 @@ install_data(
install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'),
)
-sources = files(
- 'agent.c',
- 'common.c',
- 'connections.c',
- 'devices.c',
- 'general.c',
- 'nmcli.c',
- 'polkit-agent.c',
- 'settings.c',
- 'utils.c',
-)
-
deps = [
libnmc_base_dep,
libnmc_dep,
@@ -25,14 +13,19 @@ deps = [
libnm_libnm_aux_dep,
]
-if enable_polkit_agent
- sources += nm_polkit_listener
- deps += polkit_agent_dep
-endif
-
executable(
name,
- sources,
+ files(
+ 'agent.c',
+ 'common.c',
+ 'connections.c',
+ 'devices.c',
+ 'general.c',
+ 'nmcli.c',
+ 'polkit-agent.c',
+ 'settings.c',
+ 'utils.c',
+ ),
dependencies: deps,
c_args: clients_c_flags + ['-DG_LOG_DOMAIN="@0@"'.format(name)],
link_args: ldflags_linker_script_binary,
diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c
index 69bfb68dd3..376a2f5d52 100644
--- a/clients/cli/polkit-agent.c
+++ b/clients/cli/polkit-agent.c
@@ -14,16 +14,12 @@
#include "nm-polkit-listener.h"
#include "common.h"
-#if WITH_POLKIT_AGENT
static char *
-polkit_request (NMPolkitListener *listener,
- const char *request,
- const char *action_id,
- const char *message,
- const char *icon_name,
- const char *user,
- gboolean echo_on,
- gpointer user_data)
+polkit_read_passwd (gpointer instance,
+ const char *action_id,
+ const char *message,
+ const char *user,
+ gpointer user_data)
{
NmCli *nmc = user_data;
@@ -32,87 +28,68 @@ polkit_request (NMPolkitListener *listener,
/* Ask user for polkit authorization password */
if (user) {
- gs_free char *tmp = NULL;
- char *p;
-
- /* chop of ": " if present */
- tmp = g_strdup (request);
- p = strrchr (tmp, ':');
- if (p && nm_streq (p, ": "))
- *p = '\0';
- return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s (%s): ", tmp, user);
+ return nmc_readline_echo (&nmc->nmc_config, FALSE, "password (%s): ", user);
}
-
- return nmc_readline_echo (&nmc->nmc_config, echo_on, "%s", request);
+ return nmc_readline_echo (&nmc->nmc_config, FALSE, "password: ");
}
static void
-polkit_show_info (NMPolkitListener *listener,
- const char *text,
- gpointer user_data)
+polkit_error (gpointer instance,
+ const char *error,
+ gpointer user_data)
{
- g_print (_("Authentication message: %s\n"), text);
+ g_printerr (_("Error: polkit agent failed: %s\n"), error);
}
-static void
-polkit_show_error (NMPolkitListener *listener,
- const char *text,
- gpointer user_data)
-{
- g_print (_("Authentication error: %s\n"), text);
-}
-
-static void
-polkit_completed (NMPolkitListener *listener,
- gboolean gained_authorization,
- gpointer user_data)
-{
- /* We don't print anything here. The outcome will be evident from
- * the operation result anyway. */
-}
-#endif
-
gboolean
nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
{
-#if WITH_POLKIT_AGENT
- static const NMPolkitListenVtable vtable = {
- .on_request = polkit_request,
- .on_show_info = polkit_show_info,
- .on_show_error = polkit_show_error,
- .on_completed = polkit_completed,
- };
NMPolkitListener *listener;
+ GDBusConnection *dbus_connection = NULL;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- listener = nm_polkit_listener_new (for_session, error);
- if (!listener)
- return FALSE;
+ if (nmc->client && nm_client_get_dbus_connection (nmc->client)) {
+ dbus_connection = nm_client_get_dbus_connection (nmc->client);
+ listener = nm_polkit_listener_new (dbus_connection, for_session);
+ } else {
+ dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
+ NULL,
+ error);
+
+ if (!dbus_connection) {
+ return FALSE;
+ }
+
+ listener = nm_polkit_listener_new (dbus_connection, for_session);
+ g_object_unref (dbus_connection);
+ }
- nm_polkit_listener_set_vtable (listener, &vtable, nmc);
+ g_signal_connect (listener,
+ NM_POLKIT_LISTENER_SIGNAL_REQUEST,
+ G_CALLBACK (polkit_read_passwd),
+ nmc);
+ g_signal_connect (listener,
+ NM_POLKIT_LISTENER_SIGNAL_ERROR,
+ G_CALLBACK (polkit_error),
+ NULL);
nmc->pk_listener = listener;
-#endif
return TRUE;
}
void
nmc_polkit_agent_fini (NmCli* nmc)
{
-#if WITH_POLKIT_AGENT
if (nmc->pk_listener) {
- nm_polkit_listener_set_vtable (nmc->pk_listener, NULL, NULL);
g_clear_object (&nmc->pk_listener);
}
-#endif
}
gboolean
nmc_start_polkit_agent_start_try (NmCli *nmc)
{
-#if WITH_POLKIT_AGENT
- GError *error = NULL;
+ gs_free_error GError *error = NULL;
/* We don't register polkit agent at all when running non-interactively */
if (!nmc->ask)
@@ -121,9 +98,7 @@ nmc_start_polkit_agent_start_try (NmCli *nmc)
if (!nmc_polkit_agent_init (nmc, FALSE, &error)) {
g_printerr (_("Warning: polkit agent initialization failed: %s\n"),
error->message);
- g_error_free (error);
return FALSE;
}
-#endif
return TRUE;
}
diff --git a/clients/common/meson.build b/clients/common/meson.build
index afa257b1df..f68435ec9e 100644
--- a/clients/common/meson.build
+++ b/clients/common/meson.build
@@ -1,7 +1,5 @@
common_inc = include_directories('.')
-nm_polkit_listener = files('nm-polkit-listener.c')
-
common_deps = [
libnm_dep,
libnm_nm_default_dep,
@@ -13,6 +11,7 @@ sources = files(
'nm-client-utils.c',
'nm-secret-agent-simple.c',
'nm-vpn-helpers.c',
+ 'nm-polkit-listener.c',
)
libnmc_base = static_library(
diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c
index b294165237..f1c1ba45a6 100644
--- a/clients/common/nm-polkit-listener.c
+++ b/clients/common/nm-polkit-listener.c
@@ -22,339 +22,917 @@
#include "nm-polkit-listener.h"
-#include <stdio.h>
-#include <stdlib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+#include <pwd.h>
-#if WITH_POLKIT_AGENT
+#include "nm-glib-aux/nm-dbus-aux.h"
+#include "nm-glib-aux/nm-secret-utils.h"
+#include "nm-glib-aux/nm-io-utils.h"
+#include "nm-libnm-core-intern/nm-auth-subject.h"
+#include "c-list/src/c-list.h"
+
+#define LOGIND_BUS_NAME "org.freedesktop.login1"
+#define POLKIT_BUS_NAME "org.freedesktop.PolicyKit1"
+
+#define POLKIT_AUTHORITY_OBJ_PATH "/org/freedesktop/PolicyKit1/Authority"
+#define POLKIT_AUTHORITY_IFACE_NAME "org.freedesktop.PolicyKit1.Authority"
+
+#define POLKIT_AGENT_OBJ_PATH "/org/freedesktop/PolicyKit1/AuthenticationAgent"
+#define POLKIT_AGENT_DBUS_INTERFACE "org.freedesktop.PolicyKit1.AuthenticationAgent"
+
+#define LOGIND_OBJ_PATH "/org/freedesktop/login1"
+#define LOGIND_MANAGER_INTERFACE "org.freedesktop.login1.Manager"
+
+#define NM_POLKIT_LISTENER_DBUS_CONNECTION "dbus-connection"
+#define NM_POLKIT_LISTENER_SESSION_AGENT "session-agent"
/*****************************************************************************/
-typedef struct {
- gpointer reg_handle; /* handle of polkit agent registration */
+enum {
+ REGISTERED,
+ REQUEST,
+ ERROR,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _NMPolkitListener {
+ GObject parent;
- GSimpleAsyncResult *simple;
- PolkitAgentSession *active_session;
- gulong cancel_id;
+ GDBusConnection *dbus_connection;
+ char *name_owner;
+ guint pk_auth_agent_reg_id;
+ guint name_owner_changed_id;
GCancellable *cancellable;
+ GMainContext *main_context;
+ gboolean session_agent;
+ CList request_lst_head;
+};
+
+G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, G_TYPE_OBJECT)
+
+/*****************************************************************************/
+
+typedef struct {
+ CList request_lst;
+ NMPolkitListener *listener;
char *action_id;
char *message;
- char *icon_name;
- char *identity;
+ char *username;
+ char *cookie;
+ GString *in_buffer;
+ GString *out_buffer;
+ size_t out_buffer_offset;
+
+ int child_stdout;
+ int child_stdin;
+ GSource *child_stdout_watch_source;
+ GSource *child_stdin_watch_source;
+ GDBusMethodInvocation *dbus_invocation;
+} AuthRequest;
+
+static const GDBusInterfaceInfo interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
+ POLKIT_AGENT_DBUS_INTERFACE,
+ .methods = NM_DEFINE_GDBUS_METHOD_INFOS (
+ NM_DEFINE_GDBUS_METHOD_INFO (
+ "BeginAuthentication",
+ .in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("action_id", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("message", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("icon_name", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("details", "a{ss}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("cookie", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("identities", "a(sa{sv})"),
+ ),
+ ),
+ NM_DEFINE_GDBUS_METHOD_INFO (
+ "CancelAuthentication",
+ .in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("cookie", "s"),
+ ),
+ ),
+ ),
+);
- const NMPolkitListenVtable *vtable;
- gpointer vtable_user_data;
-} NMPolkitListenerPrivate;
+static void
+remove_request (AuthRequest *request)
+{
+ c_list_unlink (&request->request_lst);
+
+ nm_clear_g_free (&request->action_id);
+ nm_clear_g_free (&request->message);
+ nm_clear_g_free (&request->username);
+ nm_clear_g_free (&request->cookie);
+ nm_clear_g_source_inst (&request->child_stdout_watch_source);
+ nm_clear_g_source_inst (&request->child_stdin_watch_source);
+
+ nm_explicit_bzero (request->out_buffer->str,
+ request->out_buffer->len);
+ g_string_free (request->out_buffer, TRUE);
+ g_string_free (request->in_buffer, TRUE);
+
+ if (request->child_stdout != -1) {
+ nm_close (request->child_stdout);
+ request->child_stdout = -1;
+ }
-G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, POLKIT_AGENT_TYPE_LISTENER)
+ if (request->child_stdin != -1) {
+ nm_close (request->child_stdin);
+ request->child_stdin = -1;
+ }
-#define NM_POLKIT_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerPrivate))
+ g_slice_free (AuthRequest, request);
+}
-/*****************************************************************************/
+static const char *
+uid_to_name (uid_t uid)
+{
+ const char *name = NULL;
+ struct passwd *passwd;
+
+ passwd = getpwuid (uid);
+ if (passwd != NULL)
+ name = passwd->pw_name;
+ return name;
+}
-void
-nm_polkit_listener_set_vtable (NMPolkitListener *self,
- const NMPolkitListenVtable *vtable,
- gpointer user_data)
+static gboolean
+find_identity (uid_t uid, gpointer user_data)
{
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+ return nm_streq0 (user_data, uid_to_name (uid));
+}
- priv->vtable = vtable;
- priv->vtable_user_data = user_data;
+static gboolean
+first_identity (uid_t uid, gpointer user_data)
+{
+ return true;
}
-/*****************************************************************************/
+static gint64
+_choose_identity (GVariant *identities,
+ gboolean (*predicate) (uid_t uid, gpointer user_data),
+ gpointer user_data)
+{
+ GVariantIter identity_iter;
+ GVariantIter *identity_details_iter;
+ GVariant *unix_id_variant;
+ uid_t unix_id;
+
+ g_return_val_if_fail (predicate != NULL, FALSE);
+
+ g_variant_iter_init (&identity_iter, identities);
+
+ while (g_variant_iter_loop (&identity_iter, "(&sa{sv})", NULL, &identity_details_iter)) {
+ while (g_variant_iter_loop (identity_details_iter, "{sv}", NULL, &unix_id_variant)) {
+ unix_id = g_variant_get_uint32 (unix_id_variant);
+
+ if (predicate (unix_id, user_data)) {
+ g_variant_unref (unix_id_variant);
+ g_variant_iter_free (identity_details_iter);
+ return unix_id;
+ }
+ }
+ g_variant_iter_free (identity_details_iter);
+ }
+ return -1;
+}
+
+static uid_t
+choose_identity (GVariant *identities)
+{
+ const char *user;
+ gint64 id;
+
+ /* Choose identity. First try current user, then root, and else
+ * take the first one */
+ user = getenv ("USER");
+
+ if ((id = _choose_identity (identities, find_identity, (gpointer) user)) >= 0) {
+ return id;
+ } else if ((id = _choose_identity (identities, find_identity, "root")) >= 0) {
+ return id;
+ }
+
+ return _choose_identity (identities, first_identity, NULL);
+}
static void
-on_request (PolkitAgentSession *session,
- const char *request,
- gboolean echo_on,
- gpointer user_data)
+agent_register_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
- NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
- gs_free char *response = NULL;
+ NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+ GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source_object);
+ gs_free_error GError *error = NULL;
+ gs_unref_variant GVariant *ret = NULL;
+
+ ret = g_dbus_connection_call_finish (dbus_connection,
+ res,
+ &error);
- if (priv->vtable && priv->vtable->on_request) {
- response = priv->vtable->on_request (self,
- request, priv->action_id,
- priv->message, priv->icon_name,
- priv->identity, echo_on,
- priv->vtable_user_data);
+ if (nm_utils_error_is_cancelled (error, FALSE)) {
+ return;
}
- if (response)
- polkit_agent_session_response (session, response);
- else {
- //FIXME: polkit_agent_session_cancel() should emit "completed", but it doesn't work for me ???
- //polkit_agent_session_cancel (session);
- polkit_agent_session_response (session, "");
+ if (ret) {
+ g_signal_emit (listener,
+ signals[REGISTERED],
+ 0);
+ } else {
+ g_signal_emit (listener,
+ signals[ERROR],
+ 0,
+ error->message);
}
}
static void
-on_show_info (PolkitAgentSession *session,
- const char *text,
- gpointer user_data)
+agent_register (NMPolkitListener *self, const char *session_id)
{
- NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+ const char *locale = NULL;
+ gs_unref_object NMAuthSubject *subject = NULL;
+ GVariant *subject_variant = NULL;
+
+ locale = g_getenv ("LANG");
+ if (locale == NULL) {
+ locale = "en_US.UTF-8";
+ }
- if (priv->vtable && priv->vtable->on_show_info) {
- priv->vtable->on_show_info (self, text,
- priv->vtable_user_data);
+ if (self->session_agent) {
+ subject = nm_auth_subject_new_unix_session (session_id);
+ } else {
+ subject = nm_auth_subject_new_unix_process_self ();
}
+ subject_variant = nm_auth_subject_unix_to_polkit_gvariant (subject);
+
+ g_dbus_connection_call (self->dbus_connection,
+ self->name_owner,
+ POLKIT_AUTHORITY_OBJ_PATH,
+ POLKIT_AUTHORITY_IFACE_NAME,
+ "RegisterAuthenticationAgent",
+ g_variant_new ("(@(sa{sv})ss)",
+ subject_variant,
+ locale,
+ POLKIT_AGENT_OBJ_PATH),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ self->cancellable,
+ agent_register_cb,
+ self);
}
static void
-on_show_error (PolkitAgentSession *session,
- const char *text,
- gpointer user_data)
+agent_unregister (NMPolkitListener *self)
{
- NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+ gs_unref_object NMAuthSubject *subject = NULL;
+ GVariant *subject_variant = NULL;
+
+ subject = nm_auth_subject_new_unix_process_self ();
+ subject_variant = nm_auth_subject_unix_to_polkit_gvariant (subject);
+
+ g_dbus_connection_call (self->dbus_connection,
+ self->name_owner,
+ POLKIT_AUTHORITY_OBJ_PATH,
+ POLKIT_AUTHORITY_IFACE_NAME,
+ "UnregisterAuthenticationAgent",
+ g_variant_new ("(@(sa{sv})s)",
+ subject_variant,
+ POLKIT_AGENT_OBJ_PATH),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ self);
+}
- if (priv->vtable && priv->vtable->on_show_error) {
- priv->vtable->on_show_error (self, text,
- priv->vtable_user_data);
+static void
+retrieve_session_id_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+ char *session_id;
+ guint32 session_uid;
+ nm_auto_free_variant_iter GVariantIter *iter;
+ gs_unref_variant GVariant *ret = NULL;
+ gs_free_error GError *error = NULL;
+ gs_free char *err_str = NULL;
+ uid_t uid = getuid ();
+
+ ret = g_dbus_connection_call_finish (listener->dbus_connection,
+ res,
+ &error);
+
+ if (nm_utils_error_is_cancelled (error, FALSE)) {
+ return;
}
+
+ if (ret) {
+ g_variant_get_child (ret, 0, "a(susso)", &iter);
+
+ while (g_variant_iter_next (iter, "(&su@s@s@o)",
+ &session_id,
+ &session_uid,
+ NULL, NULL, NULL)) {
+ if (session_uid == uid) {
+ agent_register (listener, session_id);
+ return;
+ }
+ }
+ }
+
+ err_str = g_strdup_printf (_("Could not retrieve session id: %s"),
+ error->message);
+
+ g_signal_emit (listener,
+ signals[ERROR],
+ 0,
+ err_str);
}
static void
-on_completed (PolkitAgentSession *session,
- gboolean gained_authorization,
- gpointer user_data)
+retrieve_session_id (NMPolkitListener *self)
{
- NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+ g_dbus_connection_call (self->dbus_connection,
+ LOGIND_BUS_NAME,
+ LOGIND_OBJ_PATH,
+ LOGIND_MANAGER_INTERFACE,
+ "ListSessions",
+ NULL,
+ G_VARIANT_TYPE ("(a(susso))"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ self->cancellable,
+ retrieve_session_id_cb,
+ self);
+}
+
+static void
+complete_authentication (AuthRequest *request,
+ gboolean result)
+{
+ if (result) {
+ g_dbus_method_invocation_return_value (request->dbus_invocation, NULL);
+ } else {
+ g_dbus_method_invocation_return_dbus_error (request->dbus_invocation,
+ "org.freedesktop.PolicyKit1.Error.Failed",
+ "");
+ }
+ remove_request (request);
+}
- if (priv->vtable->on_completed) {
- priv->vtable->on_completed (self, gained_authorization,
- priv->vtable_user_data);
+static gboolean
+io_watch_can_write (int fd,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ AuthRequest *request = user_data;
+ ssize_t n_written;
+ gboolean done = FALSE;
+
+ if (condition & G_IO_HUP ||
+ condition & G_IO_ERR) {
+ done = TRUE;
+ goto done;
}
- g_simple_async_result_complete_in_idle (priv->simple);
+ n_written = write (request->child_stdin,
+ &request->out_buffer->str[request->out_buffer_offset],
+ request->out_buffer->len - request->out_buffer_offset);
+
+ if (n_written < 0 && errno != EAGAIN) {
+ done = TRUE;
+ goto done;
+ }
- g_object_unref (priv->simple);
- g_object_unref (priv->active_session);
- if (priv->cancellable) {
- g_cancellable_disconnect (priv->cancellable, priv->cancel_id);
- g_object_unref (priv->cancellable);
+ if (n_written > 0) {
+ if ((size_t) n_written == (request->out_buffer->len - request->out_buffer_offset)) {
+ done = TRUE;
+ goto done;
+ }
+ request->out_buffer_offset += n_written;
}
- priv->simple = NULL;
- priv->active_session = NULL;
- priv->cancel_id = 0;
+done:
+ if (done) {
+ nm_explicit_bzero (request->out_buffer->str,
+ request->out_buffer->len);
+ g_string_set_size (request->out_buffer, 0);
+ request->out_buffer_offset = 0;
+ nm_clear_g_source_inst (&request->child_stdin_watch_source);
+ }
- g_clear_pointer (&priv->action_id, g_free);
- g_clear_pointer (&priv->message, g_free);
- g_clear_pointer (&priv->icon_name, g_free);
- g_clear_pointer (&priv->identity, g_free);
+ return G_SOURCE_CONTINUE;
}
static void
-on_cancelled (GCancellable *cancellable, gpointer user_data)
+queue_string_to_helper (AuthRequest *request, const char *response)
{
- NMPolkitListener *self = NM_POLKIT_LISTENER (user_data);
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (self);
+ g_return_if_fail (response);
+
+ g_string_append (request->out_buffer, response);
+
+ if ( request->out_buffer->len == 0
+ || request->out_buffer->str[request->out_buffer->len - 1] != '\n')
+ g_string_append_c (request->out_buffer, '\n');
+
+ if (!request->child_stdin_watch_source) {
+ request->child_stdin_watch_source = g_unix_fd_source_new (request->child_stdin,
+ G_IO_OUT | G_IO_ERR | G_IO_HUP);
+ g_source_set_callback (request->child_stdin_watch_source,
+ G_SOURCE_FUNC (io_watch_can_write),
+ request,
+ NULL);
+ g_source_attach (request->child_stdin_watch_source,
+ request->listener->main_context);
+ }
+}
- polkit_agent_session_cancel (priv->active_session);
+static gboolean
+io_watch_have_data (int fd,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ AuthRequest *request = user_data;
+ gs_free char *unescaped = NULL;
+ char *response = NULL;
+ char* line_terminator = 0;
+ gboolean auth_result = FALSE;
+ gboolean complete_auth = FALSE;
+ ssize_t n_read;
+
+ if (condition & G_IO_HUP ||
+ condition & G_IO_ERR) {
+ complete_auth = TRUE;
+ auth_result = FALSE;
+ goto out;
+ }
+
+ n_read = nm_utils_fd_read (fd, request->in_buffer);
+
+ if (n_read == -EAGAIN) {
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (n_read < 0) {
+ complete_auth = TRUE;
+ auth_result = FALSE;
+ goto out;
+ }
+
+ line_terminator = strchr (request->in_buffer->str, '\n');
+ if (!line_terminator) {
+ return G_SOURCE_CONTINUE;
+ }
+ *line_terminator = '\0';
+
+ unescaped = g_strcompress (request->in_buffer->str);
+
+ if (NM_STR_HAS_PREFIX (unescaped, "PAM_PROMPT_ECHO")) {
+ /* emit signal and wait for response */
+ g_signal_emit (request->listener,
+ signals[REQUEST],
+ 0,
+ request->action_id,
+ request->message,
+ request->username,
+ &response);
+
+ if (response) {
+ queue_string_to_helper (request, response);
+ nm_free_secret (response);
+ } else {
+ complete_auth = TRUE;
+ auth_result = FALSE;
+ }
+ } else if (NM_STR_HAS_PREFIX (unescaped, "SUCCESS")) {
+ complete_auth = TRUE;
+ auth_result = TRUE;
+ } else if (NM_STR_HAS_PREFIX (unescaped, "FAILURE")) {
+ complete_auth = TRUE;
+ auth_result = FALSE;
+ } else {
+ complete_auth = TRUE;
+ auth_result = FALSE;
+ }
+
+out:
+ g_string_set_size (request->in_buffer, 0);
+
+ if (complete_auth) {
+ complete_authentication (request, auth_result);
+ }
+ return G_SOURCE_CONTINUE;
}
-static int
-compare_users (gconstpointer a, gconstpointer b)
+static void
+begin_authentication (AuthRequest *request)
{
- char *user;
- int ret;
+ int fd_flags;
+ char *helper_argv[3];
+
+ helper_argv[0] = POLKIT_PACKAGE_PREFIX "/lib/polkit-1/polkit-agent-helper-1";
+ helper_argv[1] = request->username;
+ helper_argv[2] = NULL;
+
+ if (!g_spawn_async_with_pipes (NULL,
+ helper_argv,
+ NULL,
+ G_SPAWN_DEFAULT,
+ NULL,
+ NULL,
+ NULL,
+ &request->child_stdin,
+ &request->child_stdout,
+ NULL,
+ NULL)) {
+ complete_authentication (request, FALSE);
+ return;
+ }
+
+ fd_flags = fcntl (request->child_stdin, F_GETFD, 0);
+ fcntl (request->child_stdin, F_SETFL, fd_flags | O_NONBLOCK);
+
+ fd_flags = fcntl (request->child_stdout, F_GETFD, 0);
+ fcntl (request->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
- if (POLKIT_IS_UNIX_USER (a))
- user = g_strdup (polkit_unix_user_get_name (POLKIT_UNIX_USER (a)));
- else
- user = polkit_identity_to_string (POLKIT_IDENTITY (a));
+ request->child_stdout_watch_source = g_unix_fd_source_new (request->child_stdout,
+ G_IO_IN | G_IO_ERR | G_IO_HUP);
+ g_source_set_callback (request->child_stdout_watch_source,
+ G_SOURCE_FUNC (io_watch_have_data),
+ request,
+ NULL);
+ g_source_attach (request->child_stdout_watch_source,
+ request->listener->main_context);
- ret = g_strcmp0 ((const char *) user, (const char *) b);
- g_free (user);
- return ret;
+ /* Write the cookie on stdin so it can't be seen by other processes */
+ queue_string_to_helper (request, request->cookie);
+
+ return;
}
-static PolkitIdentity *
-choose_identity (GList *identities)
+static AuthRequest*
+get_request (NMPolkitListener *listener,
+ const char *cookie)
{
- const char *user;
- GList *elem;
+ AuthRequest *request;
- /* Choose identity. First try current user, then root, and else
- * take the first one */
- user = getenv("USER");
- elem = g_list_find_custom (identities, user, (GCompareFunc) compare_users);
- if (!elem) {
- elem = g_list_find_custom (identities, "root", (GCompareFunc) compare_users);
- if (!elem)
- elem = identities;
+ c_list_for_each_entry (request, &listener->request_lst_head, request_lst) {
+ if (nm_streq0 (cookie, request->cookie)) {
+ return request;
+ }
+ }
+ return NULL;
+}
+
+static AuthRequest*
+create_request (NMPolkitListener *listener,
+ GDBusMethodInvocation *invocation,
+ const char *action_id,
+ const char *message,
+ const char *username,
+ const char *cookie)
+{
+ AuthRequest *request = g_slice_new0(AuthRequest);
+
+ request->listener = listener;
+ request->dbus_invocation = invocation;
+ request->action_id = g_strdup (action_id);
+ request->message = g_strdup (message);
+ request->username = g_strdup (username);
+ request->cookie = g_strdup (cookie);
+ request->in_buffer = g_string_new ("");
+
+ /* preallocate a large enough buffer so that
+ * secrets don't get reallocated, thus leaked */
+ request->out_buffer = g_string_sized_new (1024);
+
+ c_list_link_tail (&listener->request_lst_head, &request->request_lst);
+ return request;
+}
+
+static void
+dbus_method_call_cb (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ NMPolkitListener *listener = NM_POLKIT_LISTENER (user_data);
+ const char *action_id;
+ const char *message;
+ const char *cookie;
+ AuthRequest *request;
+ gs_unref_variant GVariant *identities_gvariant;
+ uid_t uid;
+
+ if (nm_streq (method_name, "BeginAuthentication")) {
+ g_variant_get (parameters,
+ "(&s&s&s@a{ss}&s@a(sa{sv}))",
+ &action_id,
+ &message,
+ NULL,
+ NULL,
+ &cookie,
+ &identities_gvariant);
+
+ uid = choose_identity (identities_gvariant);
+
+ request = create_request (listener,
+ invocation,
+ action_id,
+ message,
+ uid_to_name (uid),
+ cookie);
+ begin_authentication (request);
+ } else if (nm_streq (method_name, "CancelAuthentication")) {
+ g_variant_get (parameters,
+ "&s",
+ &cookie);
+ request = get_request (listener, cookie);
+
+ if (request) {
+ complete_authentication (request, FALSE);
+ }
+ }
+}
+
+static gboolean
+export_dbus_iface (NMPolkitListener *self, GError **error)
+{
+ GDBusInterfaceVTable interface_vtable = {
+ .method_call = dbus_method_call_cb,
+ .set_property = NULL,
+ .get_property = NULL,
+ };
+
+ g_return_val_if_fail (NM_IS_POLKIT_LISTENER (self), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* Agent listener iface has been exported already */
+ if (self->pk_auth_agent_reg_id) {
+ return TRUE;
}
- return elem->data;
+ self->pk_auth_agent_reg_id =
+ g_dbus_connection_register_object (self->dbus_connection,
+ POLKIT_AGENT_OBJ_PATH,
+ (GDBusInterfaceInfo*) &interface_info,
+ &interface_vtable,
+ self,
+ NULL,
+ error);
+ if (!self->pk_auth_agent_reg_id) {
+ g_signal_emit (self,
+ signals[ERROR],
+ 0,
+ "Could not register as a PolicyKit Authentication Agent");
+ }
+ return self->pk_auth_agent_reg_id;
}
static void
-initiate_authentication (PolkitAgentListener *listener,
- const char *action_id,
- const char *message,
- const char *icon_name,
- PolkitDetails *details,
- const char *cookie,
- GList *identities,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+name_owner_changed (NMPolkitListener *self,
+ const char *name_owner)
{
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener);
- GSimpleAsyncResult *simple;
- PolkitIdentity *identity;
-
- simple = g_simple_async_result_new (G_OBJECT (listener),
- callback,
- user_data,
- initiate_authentication);
- if (cancellable)
- g_simple_async_result_set_check_cancellable (simple, cancellable);
- if (priv->active_session != NULL) {
- g_simple_async_result_set_error (simple,
- POLKIT_ERROR,
- POLKIT_ERROR_FAILED,
- _("An authentication session is already underway."));
- g_simple_async_result_complete_in_idle (simple);
- g_object_unref (simple);
+ gs_free_error GError *error = NULL;
+
+ name_owner = nm_str_not_empty (name_owner);
+
+ if (nm_streq0 (self->name_owner, name_owner)) {
return;
}
- /* Choose identity */
- identity = choose_identity (identities);
-
- priv->active_session = polkit_agent_session_new (identity, cookie);
- g_signal_connect (priv->active_session,
- "completed",
- G_CALLBACK (on_completed),
- listener);
- g_signal_connect (priv->active_session,
- "request",
- G_CALLBACK (on_request),
- listener);
- g_signal_connect (priv->active_session,
- "show-info",
- G_CALLBACK (on_show_info),
- listener);
- g_signal_connect (priv->active_session,
- "show-error",
- G_CALLBACK (on_show_error),
- listener);
-
- priv->action_id = g_strdup (action_id);
- priv->message = g_strdup (message);
- priv->icon_name = g_strdup (icon_name);
- if (POLKIT_IS_UNIX_USER (identity))
- priv->identity = g_strdup (polkit_unix_user_get_name (POLKIT_UNIX_USER (identity)));
- else
- priv->identity = polkit_identity_to_string (identity);
-
- priv->simple = simple;
- priv->cancellable = g_object_ref (cancellable);
- priv->cancel_id = g_cancellable_connect (cancellable,
- G_CALLBACK (on_cancelled),
- listener,
- NULL);
-
- polkit_agent_session_initiate (priv->active_session);
+ g_free (self->name_owner);
+ self->name_owner = g_strdup (name_owner);
+
+ if (!self->name_owner) {
+ return;
+ }
+
+ if (export_dbus_iface (self, &error)) {
+ if (self->session_agent) {
+ retrieve_session_id (self);
+ } else {
+ agent_register (self, NULL);
+ }
+ } else {
+ g_signal_emit (self,
+ signals[ERROR],
+ 0,
+ "Could not export the PolicyKit Authentication Agent DBus interface");
+ }
}
-static gboolean
-initiate_authentication_finish (PolkitAgentListener *listener,
- GAsyncResult *result,
- GError **error)
+static void
+name_owner_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ NMPolkitListener *self = user_data;
+ const char *new_owner;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) {
+ return;
+ }
+
+ g_variant_get (parameters,
+ "(&s&s&s)",
+ NULL,
+ NULL,
+ &new_owner);
+
+ name_owner_changed (self, new_owner);
+}
+
+static void
+get_name_owner_cb (const char *name_owner,
+ GError *error,
+ gpointer user_data)
{
- return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+ if (!name_owner && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ return;
+ }
+ name_owner_changed (user_data, name_owner);
}
/*****************************************************************************/
+NM_GOBJECT_PROPERTIES_DEFINE (NMPolkitListener,
+ PROP_DBUS_CONNECTION,
+ PROP_SESSION_AGENT,
+);
+
static void
-nm_polkit_listener_init (NMPolkitListener *agent)
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
+ NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+
+ switch (prop_id) {
+ case PROP_DBUS_CONNECTION:
+ self->dbus_connection = g_value_dup_object (value);
+ break;
+ case PROP_SESSION_AGENT:
+ self->session_agent = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+nm_polkit_listener_init (NMPolkitListener *self)
+{
+ c_list_init (&self->request_lst_head);
+ self->main_context = g_main_context_ref_thread_default ();
+}
+
+static void
+constructed (GObject *object)
+{
+ NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+
+ self->cancellable = g_cancellable_new ();
+
+ self->name_owner_changed_id =
+ nm_dbus_connection_signal_subscribe_name_owner_changed (self->dbus_connection,
+ POLKIT_BUS_NAME,
+ name_owner_changed_cb,
+ self,
+ NULL);
+
+ nm_dbus_connection_call_get_name_owner (self->dbus_connection,
+ POLKIT_BUS_NAME,
+ -1,
+ self->cancellable,
+ get_name_owner_cb,
+ self);
+
+ G_OBJECT_CLASS (nm_polkit_listener_parent_class)->constructed (object);
}
/**
* nm_polkit_listener_new:
- * @for_session: %TRUE for registering the polkit agent for the user session,
- * %FALSE for registering it for the running process
- * @vtable: mandatory callbacks
- * @user_data: user-data pointer for callbacks
- * @error: location to store error, or %NULL
+ * @dbus_connection: a open DBus connection
+ * @session_agent: TRUE if a session agent is wanted, FALSE for a process agent
*
* Creates a new #NMPolkitListener and registers it as a polkit agent.
*
* Returns: a new #NMPolkitListener
*/
NMPolkitListener *
-nm_polkit_listener_new (gboolean for_session,
- GError **error)
+nm_polkit_listener_new (GDBusConnection *dbus_connection, gboolean session_agent)
{
- NMPolkitListener *listener;
- PolkitSubject* session;
- NMPolkitListenerPrivate *priv;
-
- g_return_val_if_fail (!error || !*error, NULL);
-
- listener = g_object_new (NM_TYPE_POLKIT_LISTENER, NULL);
-
- priv = NM_POLKIT_LISTENER_GET_PRIVATE (listener);
-
- if (for_session) {
- session = polkit_unix_session_new_for_process_sync (getpid (), NULL, error);
- if (!session)
- return NULL;
- } else
- session = polkit_unix_process_new_for_owner (getpid (), 0, getuid ());
-
- priv->reg_handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (listener),
- POLKIT_AGENT_REGISTER_FLAGS_NONE,
- session, NULL, NULL, error);
- if (!priv->reg_handle) {
- g_object_unref (listener);
- g_object_unref (session);
- return NULL;
- }
-
- return listener;
+ return g_object_new (NM_TYPE_POLKIT_LISTENER,
+ NM_POLKIT_LISTENER_DBUS_CONNECTION, dbus_connection,
+ NM_POLKIT_LISTENER_SESSION_AGENT, session_agent,
+ NULL);
}
static void
-nm_polkit_listener_finalize (GObject *object)
+dispose (GObject *object)
{
- NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (object);
+ NMPolkitListener *self = NM_POLKIT_LISTENER (object);
+ AuthRequest *request;
+
+ nm_clear_g_cancellable (&self->cancellable);
- if (priv->reg_handle)
- polkit_agent_listener_unregister (priv->reg_handle);
+ while ((request = c_list_first_entry (&self->request_lst_head, AuthRequest, request_lst))) {
+ remove_request (request);
+ }
+
+ if (self->dbus_connection) {
+ nm_clear_g_dbus_connection_signal (self->dbus_connection,
+ &self->name_owner_changed_id);
+ g_dbus_connection_unregister_object (self->dbus_connection,
+ self->pk_auth_agent_reg_id);
+ agent_unregister (self);
+ nm_clear_g_free (&self->name_owner);
+ g_clear_object (&self->dbus_connection);
+ }
- g_free (priv->action_id);
- g_free (priv->message);
- g_free (priv->icon_name);
- g_free (priv->identity);
+ nm_clear_pointer (&self->main_context, g_main_context_unref);
- G_OBJECT_CLASS (nm_polkit_listener_parent_class)->finalize (object);
+ G_OBJECT_CLASS (nm_polkit_listener_parent_class)->dispose (object);
}
static void
nm_polkit_listener_class_init (NMPolkitListenerClass *klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- PolkitAgentListenerClass *pkal_class = POLKIT_AGENT_LISTENER_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (NMPolkitListenerPrivate));
-
- gobject_class->finalize = nm_polkit_listener_finalize;
-
- pkal_class->initiate_authentication = initiate_authentication;
- pkal_class->initiate_authentication_finish = initiate_authentication_finish;
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = set_property;
+ object_class->constructed = constructed;
+ object_class->dispose = dispose;
+
+ obj_properties[PROP_DBUS_CONNECTION] =
+ g_param_spec_object (NM_POLKIT_LISTENER_DBUS_CONNECTION, "", "",
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_SESSION_AGENT] =
+ g_param_spec_boolean (NM_POLKIT_LISTENER_SESSION_AGENT, "", "",
+ FALSE,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class,
+ _PROPERTY_ENUMS_LAST,
+ obj_properties);
+
+ signals[REQUEST] =
+ g_signal_new (NM_POLKIT_LISTENER_SIGNAL_REQUEST,
+ NM_TYPE_POLKIT_LISTENER,
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_STRING,
+ 3,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ signals[REGISTERED] =
+ g_signal_new (NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
+ NM_TYPE_POLKIT_LISTENER,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 0);
+
+ signals[ERROR] =
+ g_signal_new (NM_POLKIT_LISTENER_SIGNAL_ERROR,
+ NM_TYPE_POLKIT_LISTENER,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
}
-
-#endif /* WITH_POLKIT_AGENT */
diff --git a/clients/common/nm-polkit-listener.h b/clients/common/nm-polkit-listener.h
index 42da1bc13f..d84f3a1bb5 100644
--- a/clients/common/nm-polkit-listener.h
+++ b/clients/common/nm-polkit-listener.h
@@ -6,133 +6,16 @@
#ifndef __NM_POLKIT_LISTENER_H__
#define __NM_POLKIT_LISTENER_H__
-#if WITH_POLKIT_AGENT
-
-typedef struct _NMPolkitListener NMPolkitListener;
-typedef struct _NMPolkitListenerClass NMPolkitListenerClass;
-
-typedef struct {
-
- /*
- * @request: the request asked by polkit agent
- * @action_id: the action_id of the polkit request
- * @message: the message of the polkit request
- * @icon_name: the icon name of the polkit request
- * @user: user name
- * @echo_on: whether the response to the request should be echoed to the screen
- * @user_data: user data for the callback
- *
- * Called as a result of a request by polkit. The function should obtain response
- * to the request from user, i.e. get the password required.
- */
- char *(*on_request) (NMPolkitListener *self,
- const char *request,
- const char *action_id,
- const char *message,
- const char *icon_name,
- const char *user,
- gboolean echo_on,
- gpointer user_data);
-
- /*
- * @text: the info text from polkit
- *
- * Called as a result of show-info signal by polkit.
- */
- void (*on_show_info) (NMPolkitListener *self,
- const char *text,
- gpointer user_data);
-
- /*
- * @text: the error text from polkit
- *
- * Called as a result of show-error signal by polkit.
- */
- void (*on_show_error) (NMPolkitListener *self,
- const char *text,
- gpointer user_data);
-
- /*
- * @gained_authorization: whether the authorization was successful
- *
- * Called as a result of completed signal by polkit.
- */
- void (*on_completed) (NMPolkitListener *self,
- gboolean gained_authorization,
- gpointer user_data);
-} NMPolkitListenVtable;
-
-/*****************************************************************************/
-
-#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
-#include <polkitagent/polkitagent.h>
-
#define NM_TYPE_POLKIT_LISTENER (nm_polkit_listener_get_type ())
-#define NM_POLKIT_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_POLKIT_LISTENER, NMPolkitListener))
-#define NM_POLKIT_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerClass))
-#define NM_IS_POLKIT_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_POLKIT_LISTENER))
-#define NM_IS_POLKIT_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_POLKIT_LISTENER))
-#define NM_POLKIT_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerClass))
-
-/**
- * NMPolkitListenerOnRequestFunc:
- * @request: the request asked by polkit agent
- * @action_id: the action_id of the polkit request
- * @message: the message of the polkit request
- * @icon_name: the icon name of the polkit request
- * @user: user name
- * @echo_on: whether the response to the request should be echoed to the screen
- * @user_data: user data for the callback
- *
- * Called as a result of a request by polkit. The function should obtain response
- * to the request from user, i.e. get the password required.
- */
-typedef char * (*NMPolkitListenerOnRequestFunc) (const char *request,
- const char *action_id,
- const char *message,
- const char *icon_name,
- const char *user,
- gboolean echo_on,
- gpointer user_data);
-/**
- * NMPolkitListenerOnShowInfoFunc:
- * @text: the info text from polkit
- *
- * Called as a result of show-info signal by polkit.
- */
-typedef void (*NMPolkitListenerOnShowInfoFunc) (const char *text);
-/**
- * NMPolkitListenerOnShowErrorFunc:
- * @text: the error text from polkit
- *
- * Called as a result of show-error signal by polkit.
- */
-typedef void (*NMPolkitListenerOnShowErrorFunc) (const char *text);
-/**
- * NMPolkitListenerCompletedFunc:
- * @gained_authorization: whether the authorization was successful
- *
- * Called as a result of completed signal by polkit.
- */
-typedef void (*NMPolkitListenerOnCompletedFunc) (gboolean gained_authorization);
-
-struct _NMPolkitListener {
- PolkitAgentListener parent;
-};
-
-struct _NMPolkitListenerClass {
- PolkitAgentListenerClass parent;
-};
-
-GType nm_polkit_listener_get_type (void);
-
-NMPolkitListener *nm_polkit_listener_new (gboolean for_session,
- GError **error);
+G_DECLARE_FINAL_TYPE (NMPolkitListener, nm_polkit_listener, NM, POLKIT_LISTENER, GObject)
-void nm_polkit_listener_set_vtable (NMPolkitListener *self,
- const NMPolkitListenVtable *vtable,
- gpointer user_data);
+NMPolkitListener *nm_polkit_listener_new (GDBusConnection *dbus_connection, gboolean session_agent);
-#endif
+/* Signals */
+#define NM_POLKIT_LISTENER_SIGNAL_REGISTERED "registered"
+#define NM_POLKIT_LISTENER_SIGNAL_REQUEST "secret-request"
+#define NM_POLKIT_LISTENER_SIGNAL_AUTH_SUCCESS "auth-success"
+#define NM_POLKIT_LISTENER_SIGNAL_AUTH_FAILURE "auth-failure"
+#define NM_POLKIT_LISTENER_SIGNAL_ERROR "error"
#endif /* __NM_POLKIT_LISTENER_H__ */
diff --git a/config.h.meson b/config.h.meson
index 0514418138..009c635da4 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -221,8 +221,8 @@
/* Define if you have oFono support (experimental) */
#mesondefine WITH_OFONO
-/* Define if you have polkit agent */
-#mesondefine WITH_POLKIT_AGENT
+/* Define the polkit agent package prefix */
+#mesondefine POLKIT_PACKAGE_PREFIX
/* Define if you have PPP support */
#mesondefine WITH_PPP
diff --git a/configure.ac b/configure.ac
index 24b3f7c435..22cecb6efc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -655,18 +655,13 @@ AC_DEFINE_UNQUOTED(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT, "$enable_polkit", [The de
AC_SUBST(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_TEXT, "$enable_polkit")
PKG_CHECK_MODULES(POLKIT, [polkit-agent-1 >= 0.97], [have_pk_agent=yes],[have_pk_agent=no])
-AC_ARG_ENABLE(polkit-agent,
- AS_HELP_STRING([--enable-polkit-agent], [enable polkit agent for clients]),
- [enable_polkit_agent=${enableval}], [enable_polkit_agent=${have_pk_agent}])
-if (test "${enable_polkit_agent}" = "yes"); then
- if test x"$have_pk_agent" = x"no"; then
- AC_MSG_ERROR(Polkit agent is required)
- fi
- AC_DEFINE(WITH_POLKIT_AGENT, 1, [Define if you have polkit agent])
-else
- AC_DEFINE(WITH_POLKIT_AGENT, 0, [Define if you have polkit agent])
+if test x"$have_pk_agent" = x"no"; then
+ AC_MSG_ERROR(Polkit agent is required)
fi
-AM_CONDITIONAL(WITH_POLKIT_AGENT, test "${enable_polkit_agent}" = "yes")
+POLKIT_PACKAGE_PREFIX=`$PKG_CONFIG --variable=prefix polkit-agent-1`
+AC_DEFINE_UNQUOTED([POLKIT_PACKAGE_PREFIX],
+ ["$POLKIT_PACKAGE_PREFIX"],
+ [polkit-agent package prefix])
AC_ARG_ENABLE(modify-system, AS_HELP_STRING([--enable-modify-system], [Allow users to modify system connections]))
if test "${enable_modify_system}" = "yes"; then
@@ -1323,7 +1318,6 @@ if test "${enable_modify_system}" = "yes"; then
else
echo " policykit: main.auth-polkit=${enable_polkit} (restrictive modify.system)"
fi
-echo " polkit agent: ${enable_polkit_agent}"
echo " selinux: $have_selinux"
echo " systemd-journald: $have_systemd_journal (default: logging.backend=${nm_config_logging_backend_default})"
echo " hostname persist: ${hostname_persist}"
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
index d7e3612dc4..c706ce1b79 100644
--- a/contrib/fedora/rpm/NetworkManager.spec
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -586,7 +586,6 @@ This tool is still experimental.
-Dselinux=true \
-Dpolkit=true \
-Dconfig_auth_polkit_default=true \
- -Dpolkit_agent=true \
-Dmodify_system=true \
-Dconcheck=true \
%if 0%{?fedora}
@@ -717,7 +716,6 @@ intltoolize --automake --copy --force
%endif
--with-selinux=yes \
--enable-polkit=yes \
- --enable-polkit-agent \
--enable-modify-system=yes \
--enable-concheck \
%if 0%{?fedora}
diff --git a/meson.build b/meson.build
index 69bbccd818..0d7b29e2bf 100644
--- a/meson.build
+++ b/meson.build
@@ -494,11 +494,12 @@ config_h.set_quoted('NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT', config_auth_polkit_def
enable_modify_system = get_option('modify_system')
-enable_polkit_agent = get_option('polkit_agent')
-if enable_polkit_agent
- polkit_agent_dep = dependency('polkit-agent-1', version: '>= 0.97')
+polkit_agent_dep = dependency('polkit-agent-1', version: '>= 0.97', required : false)
+if polkit_agent_dep.found()
+ config_h.set_quoted('POLKIT_PACKAGE_PREFIX', polkit_agent_dep.get_pkgconfig_variable('prefix'))
+else
+ config_h.set_quoted('POLKIT_PACKAGE_PREFIX', '/usr')
endif
-config_h.set10('WITH_POLKIT_AGENT', enable_polkit_agent)
crypto = get_option('crypto')
@@ -971,7 +972,6 @@ if enable_polkit
output += ' modify.system)'
endif
output += '\n'
-output += ' polkit agent: ' + enable_polkit_agent.to_string() + '\n'
output += ' selinux: ' + enable_selinux.to_string() + '\n'
output += ' systemd-journald: ' + enable_systemd_journal.to_string() + ' (default: logging.backend=' + config_logging_backend_default + ')\n'
output += ' hostname persist: ' + hostname_persist + '\n'