diff --git a/clients/cli/Makefile.am b/clients/cli/Makefile.am index 4f4fcf4c6..2060c4bff 100644 --- a/clients/cli/Makefile.am +++ b/clients/cli/Makefile.am @@ -30,6 +30,8 @@ nmcli_SOURCES = \ nmcli.h \ utils.c \ utils.h \ + polkit-agent.c \ + polkit-agent.h \ \ $(srcdir)/../common/nm-secret-agent-simple.c \ $(srcdir)/../common/nm-secret-agent-simple.h \ @@ -40,6 +42,12 @@ nmcli_LDADD = \ $(READLINE_LIBS) \ $(top_builddir)/libnm/libnm.la +if WITH_POLKIT_AGENT +AM_CPPFLAGS += $(POLKIT_CFLAGS) +nmcli_SOURCES += $(srcdir)/../common/nm-polkit-listener.c $(srcdir)/../common/nm-polkit-listener.h +nmcli_LDADD += $(POLKIT_LIBS) +endif + if BUILD_SETTING_DOCS settings-docs.c: settings-docs.xsl $(top_builddir)/libnm-util/nm-setting-docs.xml $(AM_V_GEN) xsltproc --output $@ $^ diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c index 8410020fe..76033417e 100644 --- a/clients/cli/nmcli.c +++ b/clients/cli/nmcli.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +36,7 @@ #include #include +#include "polkit-agent.h" #include "nmcli.h" #include "utils.h" #include "common.h" @@ -61,6 +64,7 @@ typedef struct { /* --- Global variables --- */ GMainLoop *loop = NULL; static sigset_t signal_set; +struct termios termios_orig; /* Get an error quark for use with GError */ @@ -261,8 +265,18 @@ parse_command_line (NmCli *nmc, int argc, char **argv) argv++; } - if (argc > 1) + if (argc > 1) { + GError *error = NULL; + + /* Initialize polkit agent */ + if (!nmc_polkit_agent_init (&nm_cli, FALSE, &error)) { + g_printerr ("Polkit agent initialization failed: %s\n", error->message); + g_error_free (error); + } + + /* Now run the requested command */ return do_cmd (nmc, argv[1], argc-1, argv+1); + } usage (base); return nmc->return_value; @@ -332,6 +346,7 @@ signal_handling_thread (void *arg) { pthread_mutex_unlock (&sigint_mutex); } else { /* We can quit nmcli */ + tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig); nmc_cleanup_readline (); g_print (_("\nError: nmcli terminated by signal %s (%d)\n"), strsignal (signo), signo); @@ -340,6 +355,7 @@ signal_handling_thread (void *arg) { break; case SIGQUIT: case SIGTERM: + tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig); nmc_cleanup_readline (); if (!nmcli_sigquit_internal) g_print (_("\nError: nmcli terminated by signal %s (%d)\n"), @@ -502,6 +518,7 @@ nmc_init (NmCli *nmc) nmc->secret_agent = NULL; nmc->pwds_hash = NULL; + nmc->pk_listener = NULL; nmc->should_wait = FALSE; nmc->nowait_flag = TRUE; @@ -539,6 +556,8 @@ nmc_cleanup (NmCli *nmc) g_free (nmc->required_fields); nmc_empty_output_fields (nmc); g_ptr_array_unref (nmc->output_data); + + nmc_polkit_agent_fini (nmc); } static gboolean @@ -576,6 +595,9 @@ main (int argc, char *argv[]) #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif + + /* Save terminal settings */ + tcgetattr (STDIN_FILENO, &termios_orig); /* readline init */ rl_event_hook = event_hook_for_readline; diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h index a18de1854..5cd7526a8 100644 --- a/clients/cli/nmcli.h +++ b/clients/cli/nmcli.h @@ -20,8 +20,17 @@ #ifndef NMC_NMCLI_H #define NMC_NMCLI_H +#include "config.h" + #include +#if WITH_POLKIT_AGENT +#include "nm-polkit-listener.h" +#else +/* polkit agent is not available; define fake NMPolkitListener */ +typedef gpointer NMPolkitListener; +#endif + /* nmcli exit codes */ typedef enum { /* Indicates successful execution */ @@ -114,6 +123,7 @@ typedef struct _NmCli { NMSecretAgent *secret_agent; /* Secret agent */ GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */ + NMPolkitListener *pk_listener ; /* polkit agent listener */ gboolean should_wait; /* Indication that nmcli should not end yet */ gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */ diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c new file mode 100644 index 000000000..e8502884e --- /dev/null +++ b/clients/cli/polkit-agent.c @@ -0,0 +1,146 @@ +/* nmcli - command-line tool to control NetworkManager + * + * 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 2014 Red Hat, Inc. + */ + +#include "config.h" + +#if WITH_POLKIT_AGENT + +#include +#include +#include +#include +#include + +#include +#include + +#include "polkit-agent.h" +#include "nm-polkit-listener.h" +#include "common.h" + +static char * +polkit_request (const char *request, + const char *action_id, + const char *message, + const char *icon_name, + const char *user, + gboolean echo_on, + gpointer user_data) +{ + char *response, *tmp, *p; + struct termios termios_orig, termios_new; + + g_print ("%s\n", message); + g_print ("(action_id: %s)\n", action_id); + + if (!echo_on) { + tcgetattr (STDIN_FILENO, &termios_orig); + termios_new = termios_orig; + termios_new.c_lflag &= ~(ECHO); + tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_new); + } + + /* Ask user for polkit authorization password */ + if (user) { + /* chop of ": " if present */ + tmp = g_strdup (request); + p = strrchr (tmp, ':'); + if (p && !strcmp (p, ": ")) + *p = '\0'; + response = nmc_readline ("%s (%s): ", tmp, user); + g_free (tmp); + } else + response = nmc_readline ("%s", request); + g_print ("\n"); + + /* Restore original terminal settings */ + if (!echo_on) + tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig); + + return response; +} + +static void +polkit_show_info (const char *text) +{ + g_print (_("Authentication message: %s\n"), text); +} + +static void +polkit_show_error (const char *text) +{ + g_print (_("Authentication error: %s\n"), text); +} + +static void +polkit_completed (gboolean gained_authorization) +{ + /* We don't print anything here. The outcome will be evident from + * the operation result anyway. */ +} + +gboolean +nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error) +{ + PolkitAgentListener *listener; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* We don't register polkit agent at all when running non-interactively */ + if (!nmc->ask) + return TRUE; + + listener = nm_polkit_listener_new (for_session, error); + if (!listener) + return FALSE; + + nm_polkit_listener_set_request_callback (NM_POLKIT_LISTENER (listener), polkit_request, nmc); + nm_polkit_listener_set_show_info_callback (NM_POLKIT_LISTENER (listener), polkit_show_info); + nm_polkit_listener_set_show_error_callback (NM_POLKIT_LISTENER (listener), polkit_show_error); + nm_polkit_listener_set_completed_callback (NM_POLKIT_LISTENER (listener), polkit_completed); + + nmc->pk_listener = NM_POLKIT_LISTENER (listener); + return TRUE; +} + +void +nmc_polkit_agent_fini (NmCli* nmc) +{ + g_clear_object (&nmc->pk_listener); +} + +#else +/* polkit agent is not avalable; implement stub functions. */ + +#include +#include "nmcli.h" +#include "polkit-agent.h" + +gboolean +nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error) +{ + return TRUE; +} + +void +nmc_polkit_agent_fini (NmCli* nmc) +{ +} + +#endif /* #if WITH_POLKIT_AGENT */ diff --git a/clients/cli/polkit-agent.h b/clients/cli/polkit-agent.h new file mode 100644 index 000000000..2e0326bc9 --- /dev/null +++ b/clients/cli/polkit-agent.h @@ -0,0 +1,28 @@ +/* nmcli - command-line tool to control NetworkManager + * + * 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 2014 Red Hat, Inc. + */ + +#ifndef __NMC_POLKIT_AGENT_H__ +#define __NMC_POLKIT_AGENT_H__ + +#include "nmcli.h" + +gboolean nmc_polkit_agent_init (NmCli *nmc, gboolean for_session, GError **error); +void nmc_polkit_agent_fini (NmCli* nmc); + +#endif /* __NMC_POLKIT_AGENT_H__ */ diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c new file mode 100644 index 000000000..82df1b2de --- /dev/null +++ b/clients/common/nm-polkit-listener.c @@ -0,0 +1,415 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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, see . + * + * Copyright 2014 Red Hat, Inc. + */ + +/** + * SECTION:nm-polkit-listener + * @short_description: A polkit agent listener + * + * #NMPolkitListener is the polkit agent listener used by nmcli and nmtui. + * http://www.freedesktop.org/software/polkit/docs/latest/index.html + * + * For an example polkit agent you can look at polkit source tree: + * http://cgit.freedesktop.org/polkit/tree/src/polkitagent/polkitagenttextlistener.c + * http://cgit.freedesktop.org/polkit/tree/src/programs/pkttyagent.c + * or LXDE polkit agent: + * http://git.lxde.org/gitweb/?p=debian/lxpolkit.git;a=blob;f=src/lxpolkit-listener.c + * https://github.com/lxde/lxqt-policykit/tree/master/src + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "nm-glib-compat.h" +#include "nm-polkit-listener.h" + +G_DEFINE_TYPE (NMPolkitListener, nm_polkit_listener, POLKIT_AGENT_TYPE_LISTENER) + +#define NM_POLKIT_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_POLKIT_LISTENER, NMPolkitListenerPrivate)) + +typedef struct { + gpointer reg_handle; /* handle of polkit agent registration */ + + GSimpleAsyncResult *simple; + PolkitAgentSession *active_session; + gulong cancel_id; + GCancellable *cancellable; + + char *action_id; + char *message; + char *icon_name; + char *identity; + + /* callbacks */ + NMPolkitListenerOnRequestFunc on_request_callback; + NMPolkitListenerOnShowInfoFunc on_show_info_callback; + NMPolkitListenerOnShowErrorFunc on_show_error_callback; + NMPolkitListenerOnCompletedFunc on_completed_callback; + gpointer request_callback_data; +} NMPolkitListenerPrivate; + + +static void +on_request (PolkitAgentSession *session, + const char *request, + gboolean echo_on, + gpointer user_data) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data); + char *response = NULL; + + if (priv->on_request_callback) { + response = priv->on_request_callback (request, priv->action_id, + priv->message, priv->icon_name, + priv->identity, echo_on, + priv->request_callback_data); + } + + if (response) { + polkit_agent_session_response (session, response); + g_free (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, ""); + } +} + +static void +on_show_info (PolkitAgentSession *session, + const char *text, + gpointer user_data) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data); + + if (priv->on_show_info_callback) + priv->on_show_info_callback (text); +} + +static void +on_show_error (PolkitAgentSession *session, + const char *text, + gpointer user_data) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data); + + if (priv->on_show_error_callback) + priv->on_show_error_callback (text); +} + +static void +on_completed (PolkitAgentSession *session, + gboolean gained_authorization, + gpointer user_data) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data); + + if (priv->on_completed_callback) + priv->on_completed_callback (gained_authorization); + + g_simple_async_result_complete_in_idle (priv->simple); + + 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); + } + + priv->simple = NULL; + priv->active_session = NULL; + priv->cancel_id = 0; + + 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); +} + +static void +on_cancelled (GCancellable *cancellable, gpointer user_data) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (user_data); + + polkit_agent_session_cancel (priv->active_session); +} + +static gint +compare_users (gconstpointer a, gconstpointer b) +{ + char *user; + int ret; + + 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)); + + ret = g_strcmp0 ((const char *) user, (const char *) b); + g_free (user); + return ret; +} + +static PolkitIdentity * +choose_identity (GList *identities) +{ + const char *user; + GList *elem; + + /* Choose identity. First try current user, then root, and else + * take the firts 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; + } + + return elem->data; +} + +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) +{ + 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 (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); + 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); +} + +static gboolean +initiate_authentication_finish (PolkitAgentListener *listener, + GAsyncResult *result, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); +} + + +static void +nm_polkit_listener_init (NMPolkitListener *agent) +{ +} + +static void +nm_polkit_listener_finalize (GObject *object) +{ + NMPolkitListenerPrivate *priv = NM_POLKIT_LISTENER_GET_PRIVATE (object); + + if (priv->reg_handle) + polkit_agent_listener_unregister (priv->reg_handle); + + g_free (priv->action_id); + g_free (priv->message); + g_free (priv->icon_name); + g_free (priv->identity); + + G_OBJECT_CLASS (nm_polkit_listener_parent_class)->finalize (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; +} + +/** + * nm_polkit_listener_new: + * @for_session: %TRUE for registering the polkit agent for the user session, + * %FALSE for registering it for the running process + * @error: location to store error, or %NULL + * + * Creates a new #NMPolkitListener and registers it as a polkit agent. + * + * Returns: a new #NMPolkitListener + */ +PolkitAgentListener * +nm_polkit_listener_new (gboolean for_session, GError **error) +{ + PolkitAgentListener *listener; + PolkitSubject* session; + NMPolkitListenerPrivate *priv; + + g_return_val_if_fail (error == NULL || *error == NULL, 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, NULL); + else + session = polkit_unix_process_new_for_owner (getpid (), 0, getuid ()); + + priv->reg_handle = polkit_agent_listener_register (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; +} + +/** + * nm_polkit_listener_set_request_callback: + * @self: a #NMPolkitListener object + * @request_callback: callback to install for polkit requests + * @request_callback_data: usaer data passed to request_callback when it is called + * + * Set a callback for "request" signal. The callback will be invoked when polkit + * requests an authorization. + */ +void +nm_polkit_listener_set_request_callback (NMPolkitListener *self, + NMPolkitListenerOnRequestFunc request_callback, + gpointer request_callback_data) +{ + NMPolkitListenerPrivate *priv; + + g_return_if_fail (NM_IS_POLKIT_LISTENER (self)); + + priv = NM_POLKIT_LISTENER_GET_PRIVATE (self); + + priv->on_request_callback = request_callback; + priv->request_callback_data = request_callback_data; +} + +/** + * nm_polkit_listener_set_show_info_callback: + * @self: a #NMPolkitListener object + * @show_info_callback: callback to install for polkit show info trigger + * + * Set a callback for "show-info" signal. The callback will be invoked when polkit + * has an info text to display. + */ +void +nm_polkit_listener_set_show_info_callback (NMPolkitListener *self, + NMPolkitListenerOnShowInfoFunc show_info_callback) +{ + g_return_if_fail (NM_IS_POLKIT_LISTENER (self)); + + NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_show_info_callback = show_info_callback; +} + +/** + * nm_polkit_listener_set_show_error_callback: + * @self: a #NMPolkitListener object + * @show_error_callback: callback to install for polkit show error trigger + * + * Set a callback for "show-error" signal. The callback will be invoked when polkit + * has an error text to display. + */ +void +nm_polkit_listener_set_show_error_callback (NMPolkitListener *self, + NMPolkitListenerOnShowErrorFunc show_error_callback) +{ + g_return_if_fail (NM_IS_POLKIT_LISTENER (self)); + + NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_show_error_callback = show_error_callback; +} + +/** + * nm_polkit_listener_set_completed_callback: + * @self: a #NMPolkitListener object + * @completed_callback: callback to install for polkit completing authorization + * + * Set a callback for "completed" signal. The callback will be invoked when polkit + * completed the request. + */ +void +nm_polkit_listener_set_completed_callback (NMPolkitListener *self, + NMPolkitListenerOnCompletedFunc completed_callback) +{ + g_return_if_fail (NM_IS_POLKIT_LISTENER (self)); + + NM_POLKIT_LISTENER_GET_PRIVATE (self)->on_completed_callback = completed_callback; +} diff --git a/clients/common/nm-polkit-listener.h b/clients/common/nm-polkit-listener.h new file mode 100644 index 000000000..3cd750192 --- /dev/null +++ b/clients/common/nm-polkit-listener.h @@ -0,0 +1,104 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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, see . + * + * Copyright 2014 Red Hat, Inc. + */ + +#ifndef __NM_POLKIT_LISTENER_H__ +#define __NM_POLKIT_LISTENER_H__ + +#include + +#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE +#include + +G_BEGIN_DECLS + +#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 autorization was successful + * + * Called as a result of completed signal by polkit. + */ +typedef void (*NMPolkitListenerOnCompletedFunc) (gboolean gained_authorization); + + +typedef struct { + PolkitAgentListener parent; + +} NMPolkitListener; + +typedef struct { + PolkitAgentListenerClass parent; + +} NMPolkitListenerClass; + +GType nm_polkit_listener_get_type (void); + +PolkitAgentListener* nm_polkit_listener_new (gboolean for_session, GError **error); +void nm_polkit_listener_set_request_callback (NMPolkitListener *self, + NMPolkitListenerOnRequestFunc request_callback, + gpointer request_callback_data); +void nm_polkit_listener_set_show_info_callback (NMPolkitListener *self, + NMPolkitListenerOnShowInfoFunc show_info_callback); +void nm_polkit_listener_set_show_error_callback (NMPolkitListener *self, + NMPolkitListenerOnShowErrorFunc show_error_callback); +void nm_polkit_listener_set_completed_callback (NMPolkitListener *self, + NMPolkitListenerOnCompletedFunc completed_callback); + +G_END_DECLS + +#endif /* __NM_POLKIT_LISTENER_H__ */ diff --git a/configure.ac b/configure.ac index f14fb8e0b..61f865687 100644 --- a/configure.ac +++ b/configure.ac @@ -498,6 +498,22 @@ else fi AC_SUBST(NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT) +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_SUBST(POLKIT_CFLAGS) + AC_SUBST(POLKIT_LIBS) + 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]) +fi +AM_CONDITIONAL(WITH_POLKIT_AGENT, test "${enable_polkit_agent}" = "yes") + AC_ARG_ENABLE(modify-system, AS_HELP_STRING([--enable-modify-system], [Allow users to modify system connections])) if test "${enable_modify_system}" = "yes"; then @@ -1013,6 +1029,7 @@ if test "${enable_polkit}" = "yes"; then else echo " policykit: no" fi +echo " polkit agent: ${enable_polkit_agent}" echo " selinux: $have_selinux" echo diff --git a/po/POTFILES.in b/po/POTFILES.in index 869cd6e7c..5417b07dc 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -6,8 +6,10 @@ clients/cli/connections.c clients/cli/devices.c clients/cli/general.c clients/cli/nmcli.c +clients/cli/polkit-agent.c clients/cli/settings.c clients/cli/utils.c +clients/common/nm-polkit-listener.c clients/common/nm-secret-agent-simple.c clients/nm-online.c clients/tui/newt/nmt-newt-utils.c