OpenVPN
test_user_pass.c
Go to the documentation of this file.
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) 2023-2024 OpenVPN 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 as published by the
12  * Free Software Foundation, either version 2 of the License,
13  * or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #undef ENABLE_SYSTEMD
30 /* avoid redefining ENABLE_SYSTEMD in misc.c */
31 #undef HAVE_CONFIG_H
32 
33 #include "syshead.h"
34 #include "manage.h"
35 
36 #include <stdlib.h>
37 #include <string.h>
38 #include <setjmp.h>
39 #include <cmocka.h>
40 #include "test_common.h"
41 
42 #include "misc.c"
43 
44 struct management *management; /* global */
45 
46 /* mocking */
47 bool
49 {
50  /* Loop through configured query_user slots */
51  for (int i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
52  {
53  check_expected(query_user[i].prompt);
54  strncpy(query_user[i].response, mock_ptr_type(char *), query_user[i].response_len);
55  }
56 
57  return mock();
58 }
59 void
60 management_auth_failure(struct management *man, const char *type, const char *reason)
61 {
62  assert_true(0);
63 }
64 bool
66  struct user_pass *up,
67  const char *type,
68  const unsigned int flags,
69  const char *static_challenge)
70 {
71  assert_true(0);
72  return false;
73 }
74 /* stubs for some unused functions instead of pulling in too many dependencies */
75 int
76 parse_line(const char *line, char **p, const int n, const char *file,
77  const int line_num, int msglevel, struct gc_arena *gc)
78 {
79  assert_true(0);
80  return 0;
81 }
82 
83 /* tooling */
84 static void
86 {
87  up->defined = false;
88  up->token_defined = false;
89  up->nocache = false;
90  strcpy(up->username, "user");
91  strcpy(up->password, "password");
92 }
93 
94 static void
96 {
97  struct user_pass up = { 0 };
98  reset_user_pass(&up);
99  up.defined = true;
100  assert_true(get_user_pass_cr(&up, NULL, "UT", 0, NULL));
101 }
102 
103 static void
105 {
106  struct user_pass up = { 0 };
107  reset_user_pass(&up);
108  unsigned int flags = GET_USER_PASS_NEED_OK;
109 
110  expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:");
111  will_return(query_user_exec_builtin, "");
112  will_return(query_user_exec_builtin, true);
113  /*FIXME: query_user_exec() called even though nothing queued */
114  will_return(query_user_exec_builtin, true);
115  assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL));
116  assert_true(up.defined);
117  assert_string_equal(up.password, "ok");
118 
119  reset_user_pass(&up);
120 
121  expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:");
122  will_return(query_user_exec_builtin, "cancel");
123  will_return(query_user_exec_builtin, true);
124  /*FIXME: query_user_exec() called even though nothing queued */
125  will_return(query_user_exec_builtin, true);
126  assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL));
127  assert_true(up.defined);
128  assert_string_equal(up.password, "cancel");
129 }
130 
131 static void
133 {
134  struct user_pass up = { 0 };
135  reset_user_pass(&up);
136  unsigned int flags = GET_USER_PASS_INLINE_CREDS;
137 
138  /*FIXME: query_user_exec() called even though nothing queued */
139  will_return(query_user_exec_builtin, true);
140  assert_true(get_user_pass_cr(&up, "iuser\nipassword", "UT", flags, NULL));
141  assert_true(up.defined);
142  assert_string_equal(up.username, "iuser");
143  assert_string_equal(up.password, "ipassword");
144 
145  reset_user_pass(&up);
146 
147  /* Test various valid characters */
148  /*FIXME: query_user_exec() called even though nothing queued */
149  will_return(query_user_exec_builtin, true);
150  /* FIXME? content after first two lines just ignored */
151  assert_true(get_user_pass_cr(&up, "#iuser and 커뮤니티\n//ipasswörd!\nsome other content\nnot relevant", "UT", flags, NULL));
152  assert_true(up.defined);
153  assert_string_equal(up.username, "#iuser and 커뮤니티");
154  assert_string_equal(up.password, "//ipasswörd!");
155 
156  reset_user_pass(&up);
157 
158  /* Test various invalid characters */
159  /*FIXME: query_user_exec() called even though nothing queued */
160  will_return(query_user_exec_builtin, true);
161  /*FIXME? allows arbitrary crap if c > 127 */
162  /*FIXME? silently removes control characters */
163  assert_true(get_user_pass_cr(&up, "\tiuser\r\nipass\xffwo\x1erd", "UT", flags, NULL));
164  assert_true(up.defined);
165  assert_string_equal(up.username, "iuser");
166  assert_string_equal(up.password, "ipass\xffword");
167 
168  reset_user_pass(&up);
169 
170  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
171  will_return(query_user_exec_builtin, "cpassword");
172  will_return(query_user_exec_builtin, true);
173  /* will try to retrieve missing password from stdin */
174  assert_true(get_user_pass_cr(&up, "iuser", "UT", flags, NULL));
175  assert_true(up.defined);
176  assert_string_equal(up.username, "iuser");
177  assert_string_equal(up.password, "cpassword");
178 
179  reset_user_pass(&up);
180 
182  /*FIXME: query_user_exec() called even though nothing queued */
183  will_return(query_user_exec_builtin, true);
184  assert_true(get_user_pass_cr(&up, "ipassword\n", "UT", flags, NULL));
185  assert_true(up.defined);
186  assert_string_equal(up.username, "user");
187  assert_string_equal(up.password, "ipassword");
188 
189  reset_user_pass(&up);
190 
192  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
193  will_return(query_user_exec_builtin, "cpassword");
194  will_return(query_user_exec_builtin, true);
195  /* will try to retrieve missing password from stdin */
196  assert_true(get_user_pass_cr(&up, "", "UT", flags, NULL));
197  assert_true(up.defined);
198  assert_string_equal(up.username, "user");
199  assert_string_equal(up.password, "cpassword");
200 }
201 
202 static void
204 {
205  struct user_pass up = { 0 };
206  reset_user_pass(&up);
207  unsigned int flags = 0;
208 
209  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:");
210  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
211  will_return(query_user_exec_builtin, "cuser");
212  will_return(query_user_exec_builtin, "cpassword");
213  will_return(query_user_exec_builtin, true);
214  assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL));
215  assert_true(up.defined);
216  assert_string_equal(up.username, "cuser");
217  assert_string_equal(up.password, "cpassword");
218 
219  reset_user_pass(&up);
220 
222  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
223  will_return(query_user_exec_builtin, "cpassword");
224  will_return(query_user_exec_builtin, true);
225  assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL));
226  assert_true(up.defined);
227  assert_string_equal(up.username, "user");
228  assert_string_equal(up.password, "cpassword");
229 }
230 
231 static void
233 {
234  struct user_pass up = { 0 };
235  reset_user_pass(&up);
236  unsigned int flags = 0;
237 
238  char authfile[PATH_MAX] = { 0 };
239  openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_pass.txt" );
240 
241  /*FIXME: query_user_exec() called even though nothing queued */
242  will_return(query_user_exec_builtin, true);
243  assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
244  assert_true(up.defined);
245  assert_string_equal(up.username, "fuser");
246  assert_string_equal(up.password, "fpassword");
247 
248  reset_user_pass(&up);
249 
250  openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_only.txt");
251  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
252  will_return(query_user_exec_builtin, "cpassword");
253  will_return(query_user_exec_builtin, true);
254  /* will try to retrieve missing password from stdin */
255  assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
256  assert_true(up.defined);
257  assert_string_equal(up.username, "fuser");
258  assert_string_equal(up.password, "cpassword");
259 
260  reset_user_pass(&up);
261 
263  openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_only.txt");
264  /*FIXME: query_user_exec() called even though nothing queued */
265  will_return(query_user_exec_builtin, true);
266  assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
267  assert_true(up.defined);
268  assert_string_equal(up.username, "user");
269  assert_string_equal(up.password, "fuser");
270 }
271 
272 #ifdef ENABLE_MANAGEMENT
273 static void
275 {
276  struct user_pass up = { 0 };
277  reset_user_pass(&up);
278  const char *challenge = "CRV1:R,E:Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l:Y3Ix:Please enter token PIN";
279  unsigned int flags = GET_USER_PASS_DYNAMIC_CHALLENGE;
280 
281  expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
282  will_return(query_user_exec_builtin, "challenge_response");
283  will_return(query_user_exec_builtin, true);
284  assert_true(get_user_pass_cr(&up, NULL, "UT", flags, challenge));
285  assert_true(up.defined);
286  assert_string_equal(up.username, "cr1");
287  assert_string_equal(up.password, "CRV1::Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l::challenge_response");
288 }
289 
290 static void
292 {
293  struct user_pass up = { 0 };
294  reset_user_pass(&up);
295  const char *challenge = "Please enter token PIN";
296  unsigned int flags = GET_USER_PASS_STATIC_CHALLENGE;
297 
298  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:");
299  will_return(query_user_exec_builtin, "cuser");
300  expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
301  will_return(query_user_exec_builtin, "cpassword");
302  will_return(query_user_exec_builtin, true);
303  expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
304  will_return(query_user_exec_builtin, "challenge_response");
305  will_return(query_user_exec_builtin, true);
306  assert_true(get_user_pass_cr(&up, NULL, "UT", flags, challenge));
307  assert_true(up.defined);
308  assert_string_equal(up.username, "cuser");
309  /* SCRV1:cpassword:challenge_response but base64-encoded */
310  assert_string_equal(up.password, "SCRV1:Y3Bhc3N3b3Jk:Y2hhbGxlbmdlX3Jlc3BvbnNl");
311 
312  reset_user_pass(&up);
313 
315 
316  /*FIXME: query_user_exec() called even though nothing queued */
317  will_return(query_user_exec_builtin, true);
318  expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
319  will_return(query_user_exec_builtin, "challenge_response");
320  will_return(query_user_exec_builtin, true);
321  assert_true(get_user_pass_cr(&up, "iuser\nipassword", "UT", flags, challenge));
322  assert_true(up.defined);
323  assert_string_equal(up.username, "iuser");
324  /* SCRV1:ipassword:challenge_response but base64-encoded */
325  assert_string_equal(up.password, "SCRV1:aXBhc3N3b3Jk:Y2hhbGxlbmdlX3Jlc3BvbnNl");
326 }
327 #endif /* ENABLE_MANAGEMENT */
328 
329 const struct CMUnitTest user_pass_tests[] = {
330  cmocka_unit_test(test_get_user_pass_defined),
331  cmocka_unit_test(test_get_user_pass_needok),
332  cmocka_unit_test(test_get_user_pass_inline_creds),
333  cmocka_unit_test(test_get_user_pass_authfile_stdin),
334  cmocka_unit_test(test_get_user_pass_authfile_file),
335 #ifdef ENABLE_MANAGEMENT
336  cmocka_unit_test(test_get_user_pass_dynamic_challenge),
337  cmocka_unit_test(test_get_user_pass_static_challenge),
338 #endif /* ENABLE_MANAGEMENT */
339 };
340 
341 int
342 main(void)
343 {
345  return cmocka_run_group_tests(user_pass_tests, NULL, NULL);
346 }
user_pass_tests
const struct CMUnitTest user_pass_tests[]
Definition: test_user_pass.c:329
main
int main(void)
Definition: test_user_pass.c:342
test_get_user_pass_defined
static void test_get_user_pass_defined(void **state)
Definition: test_user_pass.c:95
get_user_pass_cr
bool get_user_pass_cr(struct user_pass *up, const char *auth_file, const char *prefix, const unsigned int flags, const char *auth_challenge)
Retrieves the user credentials from various sources depending on the flags.
Definition: misc.c:211
test_get_user_pass_inline_creds
static void test_get_user_pass_inline_creds(void **state)
Definition: test_user_pass.c:132
manage.h
test_common.h
user_pass::username
char username[USER_PASS_LEN]
Definition: misc.h:71
query_user
struct _query_user query_user[QUERY_USER_NUMSLOTS]
Global variable, declared in console.c.
Definition: console.c:41
user_pass::defined
bool defined
Definition: misc.h:58
test_get_user_pass_dynamic_challenge
static void test_get_user_pass_dynamic_challenge(void **state)
Definition: test_user_pass.c:274
GET_USER_PASS_DYNAMIC_CHALLENGE
#define GET_USER_PASS_DYNAMIC_CHALLENGE
Definition: misc.h:115
user_pass::nocache
bool nocache
Definition: misc.h:62
QUERY_USER_NUMSLOTS
#define QUERY_USER_NUMSLOTS
Definition: console.h:42
test_get_user_pass_authfile_stdin
static void test_get_user_pass_authfile_stdin(void **state)
Definition: test_user_pass.c:203
syshead.h
test_get_user_pass_needok
static void test_get_user_pass_needok(void **state)
Definition: test_user_pass.c:104
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
parse_line
int parse_line(const char *line, char **p, const int n, const char *file, const int line_num, int msglevel, struct gc_arena *gc)
Definition: test_user_pass.c:76
openvpn_unit_test_setup
static void openvpn_unit_test_setup(void)
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
Definition: test_common.h:36
reset_user_pass
static void reset_user_pass(struct user_pass *up)
Definition: test_user_pass.c:85
management
struct management * management
Definition: test_user_pass.c:44
_query_user::response
char * response
The user's response.
Definition: console.h:37
user_pass::token_defined
bool token_defined
Definition: misc.h:61
management_auth_failure
void management_auth_failure(struct management *man, const char *type, const char *reason)
Definition: test_user_pass.c:60
management
Definition: manage.h:335
GET_USER_PASS_PASSWORD_ONLY
#define GET_USER_PASS_PASSWORD_ONLY
Definition: misc.h:109
GET_USER_PASS_NEED_OK
#define GET_USER_PASS_NEED_OK
Definition: misc.h:110
misc.c
query_user_exec_builtin
bool query_user_exec_builtin(void)
Executes a configured setup, using the built-in method for querying the user.
Definition: test_user_pass.c:48
test_get_user_pass_authfile_file
static void test_get_user_pass_authfile_file(void **state)
Definition: test_user_pass.c:232
config.h
user_pass::password
char password[USER_PASS_LEN]
Definition: misc.h:72
GET_USER_PASS_INLINE_CREDS
#define GET_USER_PASS_INLINE_CREDS
Definition: misc.h:119
test_get_user_pass_static_challenge
static void test_get_user_pass_static_challenge(void **state)
Definition: test_user_pass.c:291
user_pass
Definition: misc.h:56
management_query_user_pass
bool management_query_user_pass(struct management *man, struct user_pass *up, const char *type, const unsigned int flags, const char *static_challenge)
Definition: test_user_pass.c:65
GET_USER_PASS_STATIC_CHALLENGE
#define GET_USER_PASS_STATIC_CHALLENGE
Definition: misc.h:116
openvpn_test_get_srcdir_dir
void openvpn_test_get_srcdir_dir(char *buf, size_t bufsize, const char *filename)
Helper function to get a file path from the unit test directory to open it or pass its path to anothe...
Definition: test_common.h:54