mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-03 20:40:34 +01:00
cli: add 'nmcli agent' command (bgo #739568)
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)
https://bugzilla.gnome.org/show_bug.cgi?id=739568
This commit is contained in:
parent
cc7dc01691
commit
3a551664df
12 changed files with 371 additions and 15 deletions
|
|
@ -16,6 +16,8 @@ AM_CPPFLAGS = \
|
|||
-DNMCLI_LOCALEDIR=\"$(datadir)/locale\"
|
||||
|
||||
nmcli_SOURCES = \
|
||||
agent.c \
|
||||
agent.h \
|
||||
common.c \
|
||||
common.h \
|
||||
connections.c \
|
||||
|
|
|
|||
251
clients/cli/agent.c
Normal file
251
clients/cli/agent.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
29
clients/cli/agent.h
Normal file
29
clients/cli/agent.h
Normal file
|
|
@ -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__ */
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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,39 @@ 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.
|
||||
Note that running this command makes nmcli handle all polkit requests, not only
|
||||
NetworkManager related ones, because only one polkit agent can run for the
|
||||
session.
|
||||
.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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue