Blame clients/cli/agent.c

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