/*
 *  OpenVPN -- An application to securely tunnel IP networks
 *             over a single UDP port, with support for SSL/TLS-based
 *             session authentication and key exchange,
 *             packet encryption, packet authentication, and
 *             packet compression.
 *
 *  Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
 *  Copyright (C) 2016      David Sommerseth <dazo@privateinternetaccess.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  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.
 */

/**
 * @file Alternative method to query for user input, using systemd
 *
 */

#include "config.h"

#ifdef ENABLE_SYSTEMD
#include "syshead.h"
#include "console.h"
#include "misc.h"

#include <systemd/sd-daemon.h>

/*
 * is systemd running
 */

static bool
check_systemd_running(void)
{
    struct stat c;

    /* We simply test whether the systemd cgroup hierarchy is
     * mounted, as well as the systemd-ask-password executable
     * being available */

    return (sd_booted() > 0)
           && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0);

}

static bool
get_console_input_systemd(const char *prompt, const bool echo, char *input, const int capacity)
{
    int std_out;
    bool ret = false;
    struct argv argv = argv_new();

    argv_printf(&argv, SYSTEMD_ASK_PASSWORD_PATH);
#ifdef SYSTEMD_NEWER_THAN_216
    /* the --echo support arrived in upstream systemd 217 */
    if (echo)
    {
        argv_printf_cat(&argv, "--echo");
    }
#endif
    argv_printf_cat(&argv, "--icon network-vpn");
    argv_printf_cat(&argv, "%s", prompt);

    if ((std_out = openvpn_popen(&argv, NULL)) < 0)
    {
        return false;
    }
    memset(input, 0, capacity);
    if (read(std_out, input, capacity-1) != 0)
    {
        chomp(input);
        ret = true;
    }
    close(std_out);

    argv_reset(&argv);

    return ret;
}

/**
 *  Systemd aware implementation of query_user_exec().  If systemd is not running
 *  it will fall back to use query_user_exec_builtin() instead.
 *
 */
bool
query_user_exec(void)
{
    bool ret = true;  /* Presume everything goes okay */
    int i;

    /* If systemd is not available, use the default built-in mechanism */
    if (!check_systemd_running())
    {
        return query_user_exec_builtin();
    }

    /* Loop through the complete query setup and when needed, collect the information */
    for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
    {
        if (!get_console_input_systemd(query_user[i].prompt, query_user[i].echo,
                                       query_user[i].response, query_user[i].response_len) )
        {
            /* Force the final result state to failed on failure */
            ret = false;
        }
    }

    return ret;
}

#endif /* ENABLE_SYSTEMD */
