merge: implement a polkit agent and use it in nmcli (bgo #739413)
The polkit agent listener code is generic and will be used by nmtui as well. https://bugzilla.gnome.org/show_bug.cgi?id=739413
This commit is contained in:
@@ -30,6 +30,8 @@ nmcli_SOURCES = \
|
|||||||
nmcli.h \
|
nmcli.h \
|
||||||
utils.c \
|
utils.c \
|
||||||
utils.h \
|
utils.h \
|
||||||
|
polkit-agent.c \
|
||||||
|
polkit-agent.h \
|
||||||
\
|
\
|
||||||
$(srcdir)/../common/nm-secret-agent-simple.c \
|
$(srcdir)/../common/nm-secret-agent-simple.c \
|
||||||
$(srcdir)/../common/nm-secret-agent-simple.h \
|
$(srcdir)/../common/nm-secret-agent-simple.h \
|
||||||
@@ -40,6 +42,12 @@ nmcli_LDADD = \
|
|||||||
$(READLINE_LIBS) \
|
$(READLINE_LIBS) \
|
||||||
$(top_builddir)/libnm/libnm.la
|
$(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
|
if BUILD_SETTING_DOCS
|
||||||
settings-docs.c: settings-docs.xsl $(top_builddir)/libnm-util/nm-setting-docs.xml
|
settings-docs.c: settings-docs.xsl $(top_builddir)/libnm-util/nm-setting-docs.xml
|
||||||
$(AM_V_GEN) xsltproc --output $@ $^
|
$(AM_V_GEN) xsltproc --output $@ $^
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
@@ -34,6 +36,7 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gi18n.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "polkit-agent.h"
|
||||||
#include "nmcli.h"
|
#include "nmcli.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@@ -61,6 +64,7 @@ typedef struct {
|
|||||||
/* --- Global variables --- */
|
/* --- Global variables --- */
|
||||||
GMainLoop *loop = NULL;
|
GMainLoop *loop = NULL;
|
||||||
static sigset_t signal_set;
|
static sigset_t signal_set;
|
||||||
|
struct termios termios_orig;
|
||||||
|
|
||||||
|
|
||||||
/* Get an error quark for use with GError */
|
/* Get an error quark for use with GError */
|
||||||
@@ -261,8 +265,18 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
|
|||||||
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);
|
return do_cmd (nmc, argv[1], argc-1, argv+1);
|
||||||
|
}
|
||||||
|
|
||||||
usage (base);
|
usage (base);
|
||||||
return nmc->return_value;
|
return nmc->return_value;
|
||||||
@@ -332,6 +346,7 @@ signal_handling_thread (void *arg) {
|
|||||||
pthread_mutex_unlock (&sigint_mutex);
|
pthread_mutex_unlock (&sigint_mutex);
|
||||||
} else {
|
} else {
|
||||||
/* We can quit nmcli */
|
/* We can quit nmcli */
|
||||||
|
tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
|
||||||
nmc_cleanup_readline ();
|
nmc_cleanup_readline ();
|
||||||
g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
|
g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
|
||||||
strsignal (signo), signo);
|
strsignal (signo), signo);
|
||||||
@@ -340,6 +355,7 @@ signal_handling_thread (void *arg) {
|
|||||||
break;
|
break;
|
||||||
case SIGQUIT:
|
case SIGQUIT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
|
tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
|
||||||
nmc_cleanup_readline ();
|
nmc_cleanup_readline ();
|
||||||
if (!nmcli_sigquit_internal)
|
if (!nmcli_sigquit_internal)
|
||||||
g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
|
g_print (_("\nError: nmcli terminated by signal %s (%d)\n"),
|
||||||
@@ -502,6 +518,7 @@ nmc_init (NmCli *nmc)
|
|||||||
|
|
||||||
nmc->secret_agent = NULL;
|
nmc->secret_agent = NULL;
|
||||||
nmc->pwds_hash = NULL;
|
nmc->pwds_hash = NULL;
|
||||||
|
nmc->pk_listener = NULL;
|
||||||
|
|
||||||
nmc->should_wait = FALSE;
|
nmc->should_wait = FALSE;
|
||||||
nmc->nowait_flag = TRUE;
|
nmc->nowait_flag = TRUE;
|
||||||
@@ -539,6 +556,8 @@ nmc_cleanup (NmCli *nmc)
|
|||||||
g_free (nmc->required_fields);
|
g_free (nmc->required_fields);
|
||||||
nmc_empty_output_fields (nmc);
|
nmc_empty_output_fields (nmc);
|
||||||
g_ptr_array_unref (nmc->output_data);
|
g_ptr_array_unref (nmc->output_data);
|
||||||
|
|
||||||
|
nmc_polkit_agent_fini (nmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -577,6 +596,9 @@ main (int argc, char *argv[])
|
|||||||
g_type_init ();
|
g_type_init ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Save terminal settings */
|
||||||
|
tcgetattr (STDIN_FILENO, &termios_orig);
|
||||||
|
|
||||||
/* readline init */
|
/* readline init */
|
||||||
rl_event_hook = event_hook_for_readline;
|
rl_event_hook = event_hook_for_readline;
|
||||||
/* Set 0.01s timeout to mitigate slowness in readline when a broken version is used.
|
/* Set 0.01s timeout to mitigate slowness in readline when a broken version is used.
|
||||||
|
@@ -20,8 +20,17 @@
|
|||||||
#ifndef NMC_NMCLI_H
|
#ifndef NMC_NMCLI_H
|
||||||
#define NMC_NMCLI_H
|
#define NMC_NMCLI_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <NetworkManager.h>
|
#include <NetworkManager.h>
|
||||||
|
|
||||||
|
#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 */
|
/* nmcli exit codes */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Indicates successful execution */
|
/* Indicates successful execution */
|
||||||
@@ -114,6 +123,7 @@ typedef struct _NmCli {
|
|||||||
|
|
||||||
NMSecretAgent *secret_agent; /* Secret agent */
|
NMSecretAgent *secret_agent; /* Secret agent */
|
||||||
GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */
|
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 should_wait; /* Indication that nmcli should not end yet */
|
||||||
gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */
|
gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */
|
||||||
|
146
clients/cli/polkit-agent.c
Normal file
146
clients/cli/polkit-agent.c
Normal file
@@ -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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gi18n-lib.h>
|
||||||
|
|
||||||
|
#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 <glib.h>
|
||||||
|
#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 */
|
28
clients/cli/polkit-agent.h
Normal file
28
clients/cli/polkit-agent.h
Normal file
@@ -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__ */
|
415
clients/common/nm-polkit-listener.c
Normal file
415
clients/common/nm-polkit-listener.c
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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 <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gi18n-lib.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
104
clients/common/nm-polkit-listener.h
Normal file
104
clients/common/nm-polkit-listener.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2014 Red Hat, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NM_POLKIT_LISTENER_H__
|
||||||
|
#define __NM_POLKIT_LISTENER_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#define POLKIT_AGENT_I_KNOW_API_IS_SUBJECT_TO_CHANGE
|
||||||
|
#include <polkitagent/polkitagent.h>
|
||||||
|
|
||||||
|
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__ */
|
17
configure.ac
17
configure.ac
@@ -498,6 +498,22 @@ else
|
|||||||
fi
|
fi
|
||||||
AC_SUBST(NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT)
|
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,
|
AC_ARG_ENABLE(modify-system,
|
||||||
AS_HELP_STRING([--enable-modify-system], [Allow users to modify system connections]))
|
AS_HELP_STRING([--enable-modify-system], [Allow users to modify system connections]))
|
||||||
if test "${enable_modify_system}" = "yes"; then
|
if test "${enable_modify_system}" = "yes"; then
|
||||||
@@ -1013,6 +1029,7 @@ if test "${enable_polkit}" = "yes"; then
|
|||||||
else
|
else
|
||||||
echo " policykit: no"
|
echo " policykit: no"
|
||||||
fi
|
fi
|
||||||
|
echo " polkit agent: ${enable_polkit_agent}"
|
||||||
echo " selinux: $have_selinux"
|
echo " selinux: $have_selinux"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
|
@@ -6,8 +6,10 @@ clients/cli/connections.c
|
|||||||
clients/cli/devices.c
|
clients/cli/devices.c
|
||||||
clients/cli/general.c
|
clients/cli/general.c
|
||||||
clients/cli/nmcli.c
|
clients/cli/nmcli.c
|
||||||
|
clients/cli/polkit-agent.c
|
||||||
clients/cli/settings.c
|
clients/cli/settings.c
|
||||||
clients/cli/utils.c
|
clients/cli/utils.c
|
||||||
|
clients/common/nm-polkit-listener.c
|
||||||
clients/common/nm-secret-agent-simple.c
|
clients/common/nm-secret-agent-simple.c
|
||||||
clients/nm-online.c
|
clients/nm-online.c
|
||||||
clients/tui/newt/nmt-newt-utils.c
|
clients/tui/newt/nmt-newt-utils.c
|
||||||
|
Reference in New Issue
Block a user