• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/openvpn/src/openvpn/
1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#elif defined(_MSC_VER)
28#include "config-msvc.h"
29#endif
30
31#include "syshead.h"
32#include "console.h"
33#include "error.h"
34#include "buffer.h"
35#include "misc.h"
36
37#ifdef WIN32
38
39#include "win32.h"
40
41/*
42 * Get input from console.
43 *
44 * Return false on input error, or if service
45 * exit event is signaled.
46 */
47
48static bool
49get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
50{
51  HANDLE in = INVALID_HANDLE_VALUE;
52  HANDLE err = INVALID_HANDLE_VALUE;
53  DWORD len = 0;
54
55  ASSERT (prompt);
56  ASSERT (input);
57  ASSERT (capacity > 0);
58
59  input[0] = '\0';
60
61  in = GetStdHandle (STD_INPUT_HANDLE);
62  err = get_orig_stderr ();
63
64  if (in != INVALID_HANDLE_VALUE
65      && err != INVALID_HANDLE_VALUE
66      && !win32_service_interrupt (&win32_signal)
67      && WriteFile (err, prompt, strlen (prompt), &len, NULL))
68    {
69      bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
70      DWORD flags_save = 0;
71      int status = 0;
72      WCHAR *winput;
73
74      if (is_console)
75	{
76	  if (GetConsoleMode (in, &flags_save))
77	    {
78	      DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
79	      if (echo)
80		flags |= ENABLE_ECHO_INPUT;
81	      SetConsoleMode (in, flags);
82	    }
83	  else
84	    is_console = 0;
85	}
86
87      if (is_console)
88        {
89          winput = malloc (capacity * sizeof (WCHAR));
90          if (winput == NULL)
91            return false;
92
93          status = ReadConsoleW (in, winput, capacity, &len, NULL);
94          WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL);
95          free (winput);
96        }
97      else
98        status = ReadFile (in, input, capacity, &len, NULL);
99
100      string_null_terminate (input, (int)len, capacity);
101      chomp (input);
102
103      if (!echo)
104	WriteFile (err, "\r\n", 2, &len, NULL);
105      if (is_console)
106	SetConsoleMode (in, flags_save);
107      if (status && !win32_service_interrupt (&win32_signal))
108	return true;
109    }
110
111  return false;
112}
113
114#endif
115
116#ifdef HAVE_GETPASS
117
118static FILE *
119open_tty (const bool write)
120{
121  FILE *ret;
122  ret = fopen ("/dev/tty", write ? "w" : "r");
123  if (!ret)
124    ret = write ? stderr : stdin;
125  return ret;
126}
127
128static void
129close_tty (FILE *fp)
130{
131  if (fp != stderr && fp != stdin)
132    fclose (fp);
133}
134
135#endif
136
137#ifdef ENABLE_SYSTEMD
138
139/*
140 * is systemd running
141 */
142
143static bool
144check_systemd_running ()
145{
146  struct stat a, b;
147
148  /* We simply test whether the systemd cgroup hierarchy is
149   * mounted */
150
151  return (lstat("/sys/fs/cgroup", &a) == 0)
152	  && (lstat("/sys/fs/cgroup/systemd", &b) == 0)
153	  && (a.st_dev != b.st_dev);
154
155}
156
157static bool
158get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity)
159{
160  int std_out;
161  bool ret = false;
162  struct argv argv;
163
164  argv_init (&argv);
165  argv_printf (&argv, "/bin/systemd-ask-password");
166  argv_printf_cat (&argv, "%s", prompt);
167
168  if ((std_out = openvpn_popen (&argv, NULL)) < 0) {
169	  return false;
170  }
171  CLEAR (*input);
172  if (read (std_out, input, capacity) != 0)
173    {
174       chomp (input);
175       ret = true;
176    }
177  close (std_out);
178
179  argv_reset (&argv);
180
181  return ret;
182}
183
184
185#endif
186
187/*
188 * Get input from console
189 */
190bool
191get_console_input (const char *prompt, const bool echo, char *input, const int capacity)
192{
193  bool ret = false;
194  ASSERT (prompt);
195  ASSERT (input);
196  ASSERT (capacity > 0);
197  input[0] = '\0';
198
199#ifdef ENABLE_SYSTEMD
200  if (check_systemd_running ())
201    return get_console_input_systemd (prompt, echo, input, capacity);
202#endif
203
204#if defined(WIN32)
205  return get_console_input_win32 (prompt, echo, input, capacity);
206#elif defined(HAVE_GETPASS)
207  if (echo)
208    {
209      FILE *fp;
210
211      fp = open_tty (true);
212      fprintf (fp, "%s", prompt);
213      fflush (fp);
214      close_tty (fp);
215
216      fp = open_tty (false);
217      if (fgets (input, capacity, fp) != NULL)
218	{
219	  chomp (input);
220	  ret = true;
221	}
222      close_tty (fp);
223    }
224  else
225    {
226      char *gp = getpass (prompt);
227      if (gp)
228	{
229	  strncpynt (input, gp, capacity);
230	  memset (gp, 0, strlen (gp));
231	  ret = true;
232	}
233    }
234#else
235  msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt);
236#endif
237  return ret;
238}
239