Blame src/nmcli/agent.c

Packit Service dff8e4
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit Service dff8e4
/*
Packit Service dff8e4
 * Copyright (C) 2014 Red Hat, Inc.
Packit Service dff8e4
 */
Packit Service dff8e4
Packit Service dff8e4
#include "libnm-client-aux-extern/nm-default-client.h"
Packit Service dff8e4
Packit Service dff8e4
#include <stdio.h>
Packit Service dff8e4
#include <stdlib.h>
Packit Service dff8e4
#include <readline/readline.h>
Packit Service dff8e4
#include <readline/history.h>
Packit Service dff8e4
Packit Service dff8e4
#include "common.h"
Packit Service dff8e4
#include "utils.h"
Packit Service dff8e4
#include "libnmc-base/nm-secret-agent-simple.h"
Packit Service dff8e4
#include "polkit-agent.h"
Packit Service dff8e4
#include "libnmc-base/nm-polkit-listener.h"
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
usage(void)
Packit Service dff8e4
{
Packit Service dff8e4
    g_printerr(_("Usage: nmcli agent { COMMAND | help }\n\n"
Packit Service dff8e4
                 "COMMAND := { secret | polkit | all }\n\n"));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
usage_agent_secret(void)
Packit Service dff8e4
{
Packit Service dff8e4
    g_printerr(_("Usage: nmcli agent secret { help }\n"
Packit Service dff8e4
                 "\n"
Packit Service dff8e4
                 "Runs nmcli as NetworkManager secret agent. When NetworkManager requires\n"
Packit Service dff8e4
                 "a password it asks registered agents for it. This command keeps nmcli running\n"
Packit Service dff8e4
                 "and if a password is required asks the user for it.\n\n"));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
usage_agent_polkit(void)
Packit Service dff8e4
{
Packit Service dff8e4
    g_printerr(_("Usage: nmcli agent polkit { help }\n"
Packit Service dff8e4
                 "\n"
Packit Service dff8e4
                 "Registers nmcli as a polkit action for the user session.\n"
Packit Service dff8e4
                 "When a polkit daemon requires an authorization, nmcli asks the user and gives\n"
Packit Service dff8e4
                 "the response back to polkit.\n\n"));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
usage_agent_all(void)
Packit Service dff8e4
{
Packit Service dff8e4
    g_printerr(_("Usage: nmcli agent all { help }\n"
Packit Service dff8e4
                 "\n"
Packit Service dff8e4
                 "Runs nmcli as both NetworkManager secret and a polkit agent.\n\n"));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
/* for pre-filling a string to readline prompt */
Packit Service dff8e4
static char *pre_input_deftext;
Packit Service dff8e4
static int
Packit Service dff8e4
set_deftext(void)
Packit Service dff8e4
{
Packit Service dff8e4
    if (pre_input_deftext && rl_startup_hook) {
Packit Service dff8e4
        rl_insert_text(pre_input_deftext);
Packit Service dff8e4
        g_free(pre_input_deftext);
Packit Service dff8e4
        pre_input_deftext = NULL;
Packit Service dff8e4
        rl_startup_hook   = NULL;
Packit Service dff8e4
    }
Packit Service dff8e4
    return 0;
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static gboolean
Packit Service dff8e4
get_secrets_from_user(const NmcConfig *nmc_config,
Packit Service dff8e4
                      const char *     request_id,
Packit Service dff8e4
                      const char *     title,
Packit Service dff8e4
                      const char *     msg,
Packit Service dff8e4
                      GPtrArray *      secrets)
Packit Service dff8e4
{
Packit Service dff8e4
    int i;
Packit Service dff8e4
Packit Service dff8e4
    for (i = 0; i < secrets->len; i++) {
Packit Service dff8e4
        NMSecretAgentSimpleSecret *secret = secrets->pdata[i];
Packit Service dff8e4
        char *                     pwd    = NULL;
Packit Service dff8e4
Packit Service dff8e4
        /* Ask user for the password */
Packit Service dff8e4
        if (msg)
Packit Service dff8e4
            g_print("%s\n", msg);
Packit Service dff8e4
        if (secret->value) {
Packit Service dff8e4
            /* Prefill the password if we have it. */
Packit Service dff8e4
            rl_startup_hook   = set_deftext;
Packit Service dff8e4
            pre_input_deftext = g_strdup(secret->value);
Packit Service dff8e4
        }
Packit Service dff8e4
        if (secret->no_prompt_entry_id)
Packit Service dff8e4
            pwd = nmc_readline(nmc_config, "%s: ", secret->pretty_name);
Packit Service dff8e4
        else
Packit Service dff8e4
            pwd = nmc_readline(nmc_config, "%s (%s): ", secret->pretty_name, secret->entry_id);
Packit Service dff8e4
Packit Service dff8e4
        /* No password provided, cancel the secrets. */
Packit Service dff8e4
        if (!pwd)
Packit Service dff8e4
            return FALSE;
Packit Service dff8e4
        g_free(secret->value);
Packit Service dff8e4
        secret->value = pwd;
Packit Service dff8e4
    }
Packit Service dff8e4
    return TRUE;
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
secrets_requested(NMSecretAgentSimple *agent,
Packit Service dff8e4
                  const char *         request_id,
Packit Service dff8e4
                  const char *         title,
Packit Service dff8e4
                  const char *         msg,
Packit Service dff8e4
                  GPtrArray *          secrets,
Packit Service dff8e4
                  gpointer             user_data)
Packit Service dff8e4
{
Packit Service dff8e4
    NmCli *  nmc = user_data;
Packit Service dff8e4
    gboolean success;
Packit Service dff8e4
Packit Service dff8e4
    if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
Packit Service dff8e4
        nmc_terminal_erase_line();
Packit Service dff8e4
Packit Service dff8e4
    success = get_secrets_from_user(&nmc->nmc_config, request_id, title, msg, secrets);
Packit Service dff8e4
    nm_secret_agent_simple_response(agent, request_id, success ? secrets : NULL);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
do_agent_secret(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
Packit Service dff8e4
{
Packit Service dff8e4
    next_arg(nmc, &argc, &argv, NULL);
Packit Service dff8e4
    if (nmc->complete)
Packit Service dff8e4
        return;
Packit Service dff8e4
Packit Service dff8e4
    /* Create secret agent */
Packit Service dff8e4
    nmc->secret_agent = nm_secret_agent_simple_new("nmcli-agent");
Packit Service dff8e4
    if (nmc->secret_agent) {
Packit Service dff8e4
        /* We keep running */
Packit Service dff8e4
        nmc->should_wait++;
Packit Service dff8e4
Packit Service dff8e4
        nm_secret_agent_simple_enable(nmc->secret_agent, NULL);
Packit Service dff8e4
        g_signal_connect(nmc->secret_agent,
Packit Service dff8e4
                         NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS,
Packit Service dff8e4
                         G_CALLBACK(secrets_requested),
Packit Service dff8e4
                         nmc);
Packit Service dff8e4
        g_print(_("nmcli successfully registered as a NetworkManager's secret agent.\n"));
Packit Service dff8e4
    } else {
Packit Service dff8e4
        g_string_printf(nmc->return_text, _("Error: secret agent initialization failed"));
Packit Service dff8e4
        nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
Packit Service dff8e4
    }
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
polkit_registered(gpointer instance, gpointer user_data)
Packit Service dff8e4
{
Packit Service dff8e4
    g_print(_("nmcli successfully registered as a polkit agent.\n"));
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
polkit_error(gpointer instance, const char *error, gpointer user_data)
Packit Service dff8e4
{
Packit Service dff8e4
    g_main_loop_quit(loop);
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
do_agent_polkit(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
Packit Service dff8e4
{
Packit Service dff8e4
    gs_free_error GError *error = NULL;
Packit Service dff8e4
Packit Service dff8e4
    next_arg(nmc, &argc, &argv, NULL);
Packit Service dff8e4
    if (nmc->complete)
Packit Service dff8e4
        return;
Packit Service dff8e4
Packit Service dff8e4
    if (!nmc_polkit_agent_init(nmc, TRUE, &error)) {
Packit Service dff8e4
        g_dbus_error_strip_remote_error(error);
Packit Service dff8e4
        g_string_printf(nmc->return_text,
Packit Service dff8e4
                        _("Error: polkit agent initialization failed: %s"),
Packit Service dff8e4
                        error->message);
Packit Service dff8e4
        nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
Packit Service dff8e4
    } else {
Packit Service dff8e4
        /* We keep running */
Packit Service dff8e4
        nmc->should_wait++;
Packit Service dff8e4
        g_signal_connect(nmc->pk_listener,
Packit Service dff8e4
                         NM_POLKIT_LISTENER_SIGNAL_ERROR,
Packit Service dff8e4
                         G_CALLBACK(polkit_error),
Packit Service dff8e4
                         NULL);
Packit Service dff8e4
        g_signal_connect(nmc->pk_listener,
Packit Service dff8e4
                         NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
Packit Service dff8e4
                         G_CALLBACK(polkit_registered),
Packit Service dff8e4
                         NULL);
Packit Service dff8e4
Packit Service dff8e4
        /* keep running */
Packit Service dff8e4
        nmc->should_wait++;
Packit Service dff8e4
    }
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
static void
Packit Service dff8e4
do_agent_all(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
Packit Service dff8e4
{
Packit Service dff8e4
    NMCResultCode r;
Packit Service dff8e4
Packit Service dff8e4
    next_arg(nmc, &argc, &argv, NULL);
Packit Service dff8e4
    if (nmc->complete)
Packit Service dff8e4
        return;
Packit Service dff8e4
Packit Service dff8e4
    /* Run both secret and polkit agent */
Packit Service dff8e4
    do_agent_secret(cmd, nmc, argc, argv);
Packit Service dff8e4
    r = nmc->return_value;
Packit Service dff8e4
    if (r != NMC_RESULT_SUCCESS) {
Packit Service dff8e4
        g_printerr("%s\n", nmc->return_text->str);
Packit Service dff8e4
        g_string_truncate(nmc->return_text, 0);
Packit Service dff8e4
        nmc->return_value = NMC_RESULT_SUCCESS;
Packit Service dff8e4
    }
Packit Service dff8e4
Packit Service dff8e4
    do_agent_polkit(cmd, nmc, argc, argv);
Packit Service dff8e4
    if (nmc->return_value != NMC_RESULT_SUCCESS) {
Packit Service dff8e4
        g_printerr("%s\n", nmc->return_text->str);
Packit Service dff8e4
        g_string_truncate(nmc->return_text, 0);
Packit Service dff8e4
    }
Packit Service dff8e4
Packit Service dff8e4
    if (r != NMC_RESULT_SUCCESS)
Packit Service dff8e4
        nmc->return_value = r;
Packit Service dff8e4
}
Packit Service dff8e4
Packit Service dff8e4
void
Packit Service dff8e4
nmc_command_func_agent(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
Packit Service dff8e4
{
Packit Service dff8e4
    static const NMCCommand cmds[] = {
Packit Service dff8e4
        {"secret", do_agent_secret, usage_agent_secret, TRUE, TRUE},
Packit Service dff8e4
        {"polkit", do_agent_polkit, usage_agent_polkit, TRUE, TRUE},
Packit Service dff8e4
        {"all", do_agent_all, usage_agent_all, TRUE, TRUE},
Packit Service dff8e4
        {NULL, do_agent_all, usage, TRUE, TRUE},
Packit Service dff8e4
    };
Packit Service dff8e4
Packit Service dff8e4
    next_arg(nmc, &argc, &argv, NULL);
Packit Service dff8e4
    nmc_do_cmd(nmc, cmds, *argv, argc, argv);
Packit Service dff8e4
}