src/openvpn/console_systemd.c
3280d8c8
 /*
  *  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.
  *
caa54ac3
  *  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.
3280d8c8
  */
 
 /**
  * @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"
02b392a2
 #include "run_command.h"
3280d8c8
 
 #include <systemd/sd-daemon.h>
 
 /*
  * is systemd running
  */
 
 static bool
e2a0cad4
 check_systemd_running(void)
3280d8c8
 {
     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)
81d882d5
            && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0);
3280d8c8
 
 }
 
 static bool
81d882d5
 get_console_input_systemd(const char *prompt, const bool echo, char *input, const int capacity)
3280d8c8
 {
     int std_out;
     bool ret = false;
81d882d5
     struct argv argv = argv_new();
3280d8c8
 
81d882d5
     argv_printf(&argv, SYSTEMD_ASK_PASSWORD_PATH);
8ba3e258
 #ifdef SYSTEMD_NEWER_THAN_216
     /* the --echo support arrived in upstream systemd 217 */
81d882d5
     if (echo)
8ba3e258
     {
81d882d5
         argv_printf_cat(&argv, "--echo");
8ba3e258
     }
 #endif
81d882d5
     argv_printf_cat(&argv, "--icon network-vpn");
     argv_printf_cat(&argv, "%s", prompt);
3280d8c8
 
81d882d5
     if ((std_out = openvpn_popen(&argv, NULL)) < 0)
     {
         return false;
3280d8c8
     }
81d882d5
     memset(input, 0, capacity);
     if (read(std_out, input, capacity-1) != 0)
3280d8c8
     {
81d882d5
         chomp(input);
         ret = true;
3280d8c8
     }
81d882d5
     close(std_out);
3280d8c8
 
81d882d5
     argv_reset(&argv);
3280d8c8
 
     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.
  *
  */
81d882d5
 bool
e2a0cad4
 query_user_exec(void)
3280d8c8
 {
     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++)
     {
81d882d5
         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;
         }
3280d8c8
     }
 
     return ret;
 }
 
 #endif /* ENABLE_SYSTEMD */