summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2014-10-30 15:45:43 +0100
committerJiří Klimeš <jklimes@redhat.com>2014-11-07 11:21:35 +0100
commit0d9c9208026a8c5c14b657bceb477931fd35375d (patch)
tree084650b6126059806a8a4c76bc2b8ee94cbf2f17
parent9e6e6344cb114c5d79eae52594547112d6f800e9 (diff)
downloadNetworkManager-jk/nmcli-agent-command.tar.gz
cli: add 'nmcli agent' commandjk/nmcli-agent-command
Synopsis: nmcli agent { secret | polkit | all } The command runs separate NetworkManager secret agent or session polkit agent, or both. It is useful when - no other secret agent is available (such as GUI nm-applet, gnome-shell, KDE applet) - no other polkit agent is available (such as polkit-gnome-authentication-agent-1, polkit-kde-authentication-agent-1 or lxpolkit)
-rw-r--r--clients/cli/Makefile.am2
-rw-r--r--clients/cli/agent.c251
-rw-r--r--clients/cli/agent.h29
-rw-r--r--clients/cli/connections.c4
-rw-r--r--clients/cli/devices.c4
-rw-r--r--clients/cli/general.c10
-rw-r--r--clients/cli/nmcli-completion7
-rw-r--r--clients/cli/nmcli.c11
-rw-r--r--clients/cli/polkit-agent.c28
-rw-r--r--clients/cli/polkit-agent.h2
-rw-r--r--man/nmcli.1.in34
-rw-r--r--po/POTFILES.in1
12 files changed, 368 insertions, 15 deletions
diff --git a/clients/cli/Makefile.am b/clients/cli/Makefile.am
index 2060c4bfff..0820aab045 100644
--- a/clients/cli/Makefile.am
+++ b/clients/cli/Makefile.am
@@ -16,6 +16,8 @@ AM_CPPFLAGS = \
-DNMCLI_LOCALEDIR=\"$(datadir)/locale\"
nmcli_SOURCES = \
+ agent.c \
+ agent.h \
common.c \
common.h \
connections.c \
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
new file mode 100644
index 0000000000..9d4869b11e
--- /dev/null
+++ b/clients/cli/agent.c
@@ -0,0 +1,251 @@
+/*
+ * nmcli - command-line tool for controlling NetworkManager
+ * Functions for running NM secret agent.
+ *
+ * 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"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "common.h"
+#include "utils.h"
+#include "nm-secret-agent-simple.h"
+#include "polkit-agent.h"
+#include "agent.h"
+
+static void
+usage (void)
+{
+ g_printerr (_("Usage: nmcli agent { COMMAND | help }\n\n"
+ "COMMAND := { secret | polkit | all }\n\n"
+ ));
+}
+
+static void
+usage_agent_secret (void)
+{
+ g_printerr (_("Usage: nmcli agent secret { help }\n"
+ "\n"
+ "Runs nmcli as NetworkManager secret agent. When NetworkManager requires\n"
+ "a password it asks registered agents for it. This command keeps nmcli running\n"
+ "and if a password is required asks the user for it.\n\n"));
+}
+
+static void
+usage_agent_polkit (void)
+{
+ g_printerr (_("Usage: nmcli agent polkit { help }\n"
+ "\n"
+ "Registers nmcli as a polkit action for the user session.\n"
+ "When a polkit daemon requires an authorization, nmcli asks the user and gives\n"
+ "the reponse back to polkit.\n\n"));
+}
+
+static void
+usage_agent_all (void)
+{
+ g_printerr (_("Usage: nmcli agent all { help }\n"
+ "\n"
+ "Runs nmcli as both NetworkManager secret and a polkit agent.\n\n"));
+}
+
+/* for pre-filling a string to readline prompt */
+static char *pre_input_deftext;
+static int
+set_deftext (void)
+{
+ if (pre_input_deftext && rl_startup_hook) {
+ rl_insert_text (pre_input_deftext);
+ g_free (pre_input_deftext);
+ pre_input_deftext = NULL;
+ rl_startup_hook = NULL;
+ }
+ return 0;
+}
+
+static gboolean
+get_secrets_from_user (const char *request_id,
+ const char *title,
+ const char *msg,
+ GPtrArray *secrets)
+{
+ int i;
+
+ for (i = 0; i < secrets->len; i++) {
+ NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
+ char *pwd = NULL;
+
+ /* Ask user for the password */
+ g_print ("%s\n", msg);
+ if (secret->value) {
+ /* Prefill the password if we have it. */
+ rl_startup_hook = set_deftext;
+ pre_input_deftext = g_strdup (secret->value);
+ }
+ pwd = nmc_readline ("%s (%s): ", secret->name, secret->prop_name);
+
+ /* No password provided, cancel the secrets. */
+ if (!pwd)
+ return FALSE;
+ g_free (secret->value);
+ secret->value = pwd;
+ }
+ return TRUE;
+}
+
+static void
+secrets_requested (NMSecretAgentSimple *agent,
+ const char *request_id,
+ const char *title,
+ const char *msg,
+ GPtrArray *secrets,
+ gpointer user_data)
+{
+ NmCli *nmc = (NmCli *) user_data;
+ gboolean success = FALSE;
+
+ if (nmc->print_output == NMC_PRINT_PRETTY)
+ nmc_terminal_erase_line ();
+
+ success = get_secrets_from_user (request_id, title, msg, secrets);
+ if (success)
+ nm_secret_agent_simple_response (agent, request_id, secrets);
+ else
+ nm_secret_agent_simple_response (agent, request_id, NULL);
+}
+
+
+static NMCResultCode
+do_agent_secret (NmCli *nmc, int argc, char **argv)
+{
+ /* Create secret agent */
+ nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
+ if (nmc->secret_agent) {
+ /* We keep running */
+ nmc->should_wait = TRUE;
+
+ g_signal_connect (nmc->secret_agent, "request-secrets", G_CALLBACK (secrets_requested), nmc);
+ g_print (_("nmcli successfully registered as a NetworkManager's secret agent.\n"));
+ } else {
+ g_string_printf (nmc->return_text, _("Error: secret agent initialization failed"));
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ }
+
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_agent_polkit (NmCli *nmc, int argc, char **argv)
+{
+ GError *error = NULL;
+
+ /* 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"),
+ error->message);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ g_error_free (error);
+ } else {
+ /* We keep running */
+ nmc->should_wait = TRUE;
+
+ g_print (_("nmcli successfully registered as a polkit agent.\n"));
+ }
+
+ return nmc->return_value;
+}
+
+static NMCResultCode
+do_agent_all (NmCli *nmc, int argc, char **argv)
+{
+ NMCResultCode secret_res;
+
+ /* Run both secret and polkit agent */
+ secret_res = do_agent_secret (nmc, argc, argv);
+ if (secret_res != NMC_RESULT_SUCCESS)
+ g_printerr ("%s\n", nmc->return_text->str);
+
+ nmc->return_value = do_agent_polkit (nmc, argc, argv);
+
+ if (nmc->return_value == NMC_RESULT_SUCCESS && secret_res != NMC_RESULT_SUCCESS)
+ nmc->return_value = secret_res;
+
+ return nmc->return_value;
+}
+
+NMCResultCode
+do_agent (NmCli *nmc, int argc, char **argv)
+{
+ /* Get NMClient object */
+ nmc->get_client (nmc);
+
+ /* Check whether NetworkManager is running */
+ if (!nm_client_get_nm_running (nmc->client)) {
+ g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
+ nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
+ return nmc->return_value;
+ }
+ /* Compare NM and nmcli versions */
+ if (!nmc_versions_match (nmc))
+ return nmc->return_value;
+
+ if (argc == 0) {
+ nmc->return_value = do_agent_all (nmc, 0, NULL);
+ }
+
+ if (argc > 0) {
+ if (nmc_arg_is_help (*argv)) {
+ usage ();
+ goto usage_exit;
+ } else if (matches (*argv, "secret") == 0) {
+ if (nmc_arg_is_help (*(argv+1))) {
+ usage_agent_secret ();
+ goto usage_exit;
+ }
+ nmc->return_value = do_agent_secret (nmc, argc-1, argv+1);
+ } else if (matches (*argv, "polkit") == 0) {
+ if (nmc_arg_is_help (*(argv+1))) {
+ usage_agent_polkit ();
+ goto usage_exit;
+ }
+ nmc->return_value = do_agent_polkit (nmc, argc-1, argv+1);
+ } else if (matches (*argv, "all") == 0) {
+ if (nmc_arg_is_help (*(argv+1))) {
+ usage_agent_all ();
+ goto usage_exit;
+ }
+ nmc->return_value = do_agent_all (nmc, argc-1, argv+1);
+ } else {
+ usage ();
+ g_string_printf (nmc->return_text, _("Error: 'agent' command '%s' is not valid."), *argv);
+ nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ }
+ }
+
+usage_exit:
+ return nmc->return_value;
+}
diff --git a/clients/cli/agent.h b/clients/cli/agent.h
new file mode 100644
index 0000000000..70ea0d9b23
--- /dev/null
+++ b/clients/cli/agent.h
@@ -0,0 +1,29 @@
+/*
+ * nmcli - command-line tool for controlling NetworkManager
+ * Functions for running NM secret agent.
+ *
+ * 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_AGENT_H__
+#define __NMC_AGENT_H__
+
+#include "nmcli.h"
+
+NMCResultCode do_agent (NmCli *nmc, int argc, char **argv);
+
+#endif /* __NMC_AGENT_H__ */
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 717945b33d..554e2107e6 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -36,6 +36,7 @@
#include "settings.h"
#include "connections.h"
#include "nm-secret-agent-simple.h"
+#include "polkit-agent.h"
/* define some prompts for connection editor */
#define EDITOR_PROMPT_SETTING _("Setting name? ")
@@ -8796,6 +8797,9 @@ do_connections (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
/* Set completion function for 'nmcli con' */
rl_attempted_completion_function = (rl_completion_func_t *) nmcli_con_tab_completion;
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index 3d9598fb41..c073ec252b 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -28,6 +28,7 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include "polkit-agent.h"
#include "utils.h"
#include "common.h"
#include "devices.h"
@@ -2776,6 +2777,9 @@ do_devices (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
rl_attempted_completion_function = (rl_completion_func_t *) nmcli_device_tab_completion;
/* Get NMClient object early */
diff --git a/clients/cli/general.c b/clients/cli/general.c
index 531d4f7acd..44c63c356c 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -25,6 +25,7 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include "polkit-agent.h"
#include "utils.h"
#include "general.h"
@@ -558,6 +559,9 @@ do_general (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
if (argc == 0) {
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
@@ -726,6 +730,9 @@ do_networking (NmCli *nmc, int argc, char **argv)
{
gboolean enable_flag;
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
if (argc == 0)
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, _("Networking"));
else if (argc > 0) {
@@ -787,6 +794,9 @@ do_radio (NmCli *nmc, int argc, char **argv)
GError *error = NULL;
gboolean enable_flag;
+ /* Register polkit agent */
+ nmc_start_polkit_agent_start_try (nmc);
+
if (argc == 0) {
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
diff --git a/clients/cli/nmcli-completion b/clients/cli/nmcli-completion
index 1e087f7419..72648d43cb 100644
--- a/clients/cli/nmcli-completion
+++ b/clients/cli/nmcli-completion
@@ -701,7 +701,7 @@ _nmcli()
# (if the current word starts with a dash) or the OBJECT list
# otherwise.
if [[ "${words[0]:0:1}" != '-' ]]; then
- OPTIONS=(help general networking radio connection device)
+ OPTIONS=(help general networking radio connection device agent)
elif [[ "${words[0]:1:1}" == '-' || "${words[0]}" == "-" ]]; then
OPTIONS=("${LONG_OPTIONS[@]/#/--}")
else
@@ -1268,6 +1268,11 @@ _nmcli()
esac
fi
;;
+ a|ag|age|agen|agent)
+ if [[ ${#words[@]} -eq 2 ]]; then
+ _nmcli_compl_COMMAND "$command" secret polkit all
+ fi
+ ;;
esac
return 0
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 76033417ee..ade0a6bd4d 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -43,6 +43,7 @@
#include "connections.h"
#include "devices.h"
#include "general.h"
+#include "agent.h"
#if defined(NM_DIST_VERSION)
# define NMCLI_VERSION NM_DIST_VERSION
@@ -102,6 +103,7 @@ usage (const char *prog_name)
" r[adio] NetworkManager radio switches\n"
" c[onnection] NetworkManager's connections\n"
" d[evice] devices managed by NetworkManager\n"
+ " a[gent] NetworkManager secret agent or polkit agent\n"
"\n"),
prog_name);
}
@@ -122,6 +124,7 @@ static const struct cmd {
{ "radio", do_radio },
{ "connection", do_connections },
{ "device", do_devices },
+ { "agent", do_agent },
{ "help", do_help },
{ 0 }
};
@@ -266,14 +269,6 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
}
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);
}
diff --git a/clients/cli/polkit-agent.c b/clients/cli/polkit-agent.c
index e8502884e4..a163b824fa 100644
--- a/clients/cli/polkit-agent.c
+++ b/clients/cli/polkit-agent.c
@@ -102,10 +102,6 @@ nmc_polkit_agent_init (NmCli* nmc, gboolean for_session, GError **error)
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;
@@ -125,6 +121,24 @@ nmc_polkit_agent_fini (NmCli* nmc)
g_clear_object (&nmc->pk_listener);
}
+gboolean
+nmc_start_polkit_agent_start_try (NmCli *nmc)
+{
+ GError *error = NULL;
+
+ /* We don't register polkit agent at all when running non-interactively */
+ if (!nmc->ask)
+ return TRUE;
+
+ 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;
+ }
+ return TRUE;
+}
+
#else
/* polkit agent is not avalable; implement stub functions. */
@@ -143,4 +157,10 @@ nmc_polkit_agent_fini (NmCli* nmc)
{
}
+gboolean
+nmc_start_polkit_agent_start_try (NmCli *nmc)
+{
+ return TRUE;
+}
+
#endif /* #if WITH_POLKIT_AGENT */
diff --git a/clients/cli/polkit-agent.h b/clients/cli/polkit-agent.h
index 2e0326bc97..e2902dc0b1 100644
--- a/clients/cli/polkit-agent.h
+++ b/clients/cli/polkit-agent.h
@@ -25,4 +25,6 @@
gboolean nmc_polkit_agent_init (NmCli *nmc, gboolean for_session, GError **error);
void nmc_polkit_agent_fini (NmCli* nmc);
+gboolean nmc_start_polkit_agent_start_try (NmCli *nmc);
+
#endif /* __NMC_POLKIT_AGENT_H__ */
diff --git a/man/nmcli.1.in b/man/nmcli.1.in
index 2d142f4eaa..65ac956ded 100644
--- a/man/nmcli.1.in
+++ b/man/nmcli.1.in
@@ -21,7 +21,7 @@
.\"
.\" Copyright 2010 - 2014 Red Hat, Inc.
.\"
-.TH NMCLI "1" "11 September 2014"
+.TH NMCLI "1" "4 November 2014"
.SH NAME
nmcli \- command\(hyline tool for controlling NetworkManager
@@ -33,7 +33,7 @@ nmcli \- command\(hyline tool for controlling NetworkManager
.sp
.IR OBJECT " := { "
-.BR general " | " networking " | " radio " | " connection " | " device
+.BR general " | " networking " | " radio " | " connection " | " device " | " agent
.RI " }"
.sp
@@ -793,6 +793,36 @@ This command does not show the APs, use 'nmcli device wifi list' for that.
List available WiMAX NSP. The \fIifname\fP and \fInsp\fP options
can be used to list networks for a particular interface or with a specific
NSP, respectively.
+.RE
+
+.TP
+.B agent \- run nmcli as a NetworkManager secret agent, or polkit agent
+.br
+.TP
+.SS \fICOMMAND\fP := { secret | polkit | all }
+.sp
+.RS
+.TP
+.B secret
+.br
+Register nmcli as a NetworkManager secret agent and listen for secret requests.
+You do usually not need this command, because nmcli can handle secrets when
+connecting to networks. However, you may find the command useful when you use
+another tool for activating connections and you do not have a secret agent
+available (like nm-applet).
+.TP
+.B polkit
+.br
+Register nmcli as a polkit agent for the user session and listen for
+authorization requests. You do not usually need this command, because nmcli can
+handle polkit actions related to NetworkManager operations (when run with
+--ask). However, you may find the command useful when you want to run a simple
+text based polkit agent and you do not have an agent of a desktop environment.
+.TP
+.B all
+.br
+Runs nmcli as both NetworkManager secret and a polkit agent.
+.RE
.SH ENVIRONMENT VARIABLES
\fInmcli\fP's behavior is affected by the following environment variables.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5417b07dc3..6d23a67b77 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,7 @@
[encoding: UTF-8]
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
+clients/cli/agent.c
clients/cli/common.c
clients/cli/connections.c
clients/cli/devices.c