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#include "syshead.h"
30#include "manage.h"
31
32#include <stdlib.h>
33#include <string.h>
34#include <setjmp.h>
35#include <cmocka.h>
36#include "test_common.h"
37
38#include "misc.c"
39
40struct management *management; /* global */
41
42/* mocking */
43#if defined(ENABLE_SYSTEMD)
44bool
45query_user_exec_systemd(void)
46{
48}
49#endif
50bool
52{
53 /* Loop through configured query_user slots */
54 for (int i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
55 {
56 check_expected(query_user[i].prompt);
57 strncpy(query_user[i].response, mock_ptr_type(char *), query_user[i].response_len);
58 }
59
60 return mock();
61}
62void
63management_auth_failure(struct management *man, const char *type, const char *reason)
64{
65 assert_true(0);
66}
67bool
69 struct user_pass *up,
70 const char *type,
71 const unsigned int flags,
72 const char *static_challenge)
73{
74 assert_true(0);
75 return false;
76}
77/* stubs for some unused functions instead of pulling in too many dependencies */
78int
79parse_line(const char *line, char **p, const int n, const char *file,
80 const int line_num, int msglevel, struct gc_arena *gc)
81{
82 assert_true(0);
83 return 0;
84}
85
86bool
87protect_buffer_win32(char *buf, size_t len)
88{
89 return true;
90}
91
92bool
93unprotect_buffer_win32(char *buf, size_t len)
94{
95 return true;
96}
97
98/* tooling */
99static void
101{
102 up->defined = false;
103 up->token_defined = false;
104 up->nocache = false;
105 strcpy(up->username, "user");
106 strcpy(up->password, "password");
107}
108
109static void
111{
112 struct user_pass up = { 0 };
113 reset_user_pass(&up);
114 up.defined = true;
115 assert_true(get_user_pass_cr(&up, NULL, "UT", 0, NULL));
116}
117
118static void
120{
121 struct user_pass up = { 0 };
122 reset_user_pass(&up);
123 unsigned int flags = GET_USER_PASS_NEED_OK;
124
125 expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:");
126 will_return(query_user_exec_builtin, "");
127 will_return(query_user_exec_builtin, true);
128 /*FIXME: query_user_exec() called even though nothing queued */
129 will_return(query_user_exec_builtin, true);
130 assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL));
131 assert_true(up.defined);
132 assert_string_equal(up.password, "ok");
133
134 reset_user_pass(&up);
135
136 expect_string(query_user_exec_builtin, query_user[i].prompt, "NEED-OK|UT|user:");
137 will_return(query_user_exec_builtin, "cancel");
138 will_return(query_user_exec_builtin, true);
139 /*FIXME: query_user_exec() called even though nothing queued */
140 will_return(query_user_exec_builtin, true);
141 assert_true(get_user_pass_cr(&up, NULL, "UT", flags, NULL));
142 assert_true(up.defined);
143 assert_string_equal(up.password, "cancel");
144}
145
146static void
148{
149 struct user_pass up = { 0 };
150 reset_user_pass(&up);
151 unsigned int flags = GET_USER_PASS_INLINE_CREDS;
152
153 /*FIXME: query_user_exec() called even though nothing queued */
154 will_return(query_user_exec_builtin, true);
155 assert_true(get_user_pass_cr(&up, "iuser\nipassword", "UT", flags, NULL));
156 assert_true(up.defined);
157 assert_string_equal(up.username, "iuser");
158 assert_string_equal(up.password, "ipassword");
159
160 reset_user_pass(&up);
161
162 /* Test various valid characters */
163 /*FIXME: query_user_exec() called even though nothing queued */
164 will_return(query_user_exec_builtin, true);
165 /* FIXME? content after first two lines just ignored */
166 assert_true(get_user_pass_cr(&up, "#iuser and 커뮤니티\n//ipasswörd!\nsome other content\nnot relevant", "UT", flags, NULL));
167 assert_true(up.defined);
168 assert_string_equal(up.username, "#iuser and 커뮤니티");
169 assert_string_equal(up.password, "//ipasswörd!");
170
171 reset_user_pass(&up);
172
173 /* Test various invalid characters */
174 /*FIXME: query_user_exec() called even though nothing queued */
175 will_return(query_user_exec_builtin, true);
176 /*FIXME? allows arbitrary crap if c > 127 */
177 /*FIXME? silently removes control characters */
178 assert_true(get_user_pass_cr(&up, "\tiuser\r\nipass\xffwo\x1erd", "UT", flags, NULL));
179 assert_true(up.defined);
180 assert_string_equal(up.username, "iuser");
181 assert_string_equal(up.password, "ipass\xffword");
182
183 reset_user_pass(&up);
184
185 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
186 will_return(query_user_exec_builtin, "cpassword");
187 will_return(query_user_exec_builtin, true);
188 /* will try to retrieve missing password from stdin */
189 assert_true(get_user_pass_cr(&up, "iuser", "UT", flags, NULL));
190 assert_true(up.defined);
191 assert_string_equal(up.username, "iuser");
192 assert_string_equal(up.password, "cpassword");
193
194 reset_user_pass(&up);
195
197 /*FIXME: query_user_exec() called even though nothing queued */
198 will_return(query_user_exec_builtin, true);
199 assert_true(get_user_pass_cr(&up, "ipassword\n", "UT", flags, NULL));
200 assert_true(up.defined);
201 assert_string_equal(up.username, "user");
202 assert_string_equal(up.password, "ipassword");
203
204 reset_user_pass(&up);
205
207 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
208 will_return(query_user_exec_builtin, "cpassword");
209 will_return(query_user_exec_builtin, true);
210 /* will try to retrieve missing password from stdin */
211 assert_true(get_user_pass_cr(&up, "", "UT", flags, NULL));
212 assert_true(up.defined);
213 assert_string_equal(up.username, "user");
214 assert_string_equal(up.password, "cpassword");
215}
216
217static void
219{
220 struct user_pass up = { 0 };
221 reset_user_pass(&up);
222 unsigned int flags = 0;
223
224 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:");
225 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
226 will_return(query_user_exec_builtin, "cuser");
227 will_return(query_user_exec_builtin, "cpassword");
228 will_return(query_user_exec_builtin, true);
229 assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL));
230 assert_true(up.defined);
231 assert_string_equal(up.username, "cuser");
232 assert_string_equal(up.password, "cpassword");
233
234 reset_user_pass(&up);
235
237 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
238 will_return(query_user_exec_builtin, "cpassword");
239 will_return(query_user_exec_builtin, true);
240 assert_true(get_user_pass_cr(&up, "stdin", "UT", flags, NULL));
241 assert_true(up.defined);
242 assert_string_equal(up.username, "user");
243 assert_string_equal(up.password, "cpassword");
244}
245
246static void
248{
249 struct user_pass up = { 0 };
250 reset_user_pass(&up);
251 unsigned int flags = 0;
252
253 char authfile[PATH_MAX] = { 0 };
254 openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_pass.txt" );
255
256 /*FIXME: query_user_exec() called even though nothing queued */
257 will_return(query_user_exec_builtin, true);
258 assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
259 assert_true(up.defined);
260 assert_string_equal(up.username, "fuser");
261 assert_string_equal(up.password, "fpassword");
262
263 reset_user_pass(&up);
264
265 openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_only.txt");
266 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
267 will_return(query_user_exec_builtin, "cpassword");
268 will_return(query_user_exec_builtin, true);
269 /* will try to retrieve missing password from stdin */
270 assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
271 assert_true(up.defined);
272 assert_string_equal(up.username, "fuser");
273 assert_string_equal(up.password, "cpassword");
274
275 reset_user_pass(&up);
276
278 openvpn_test_get_srcdir_dir(authfile, PATH_MAX, "input/user_only.txt");
279 /*FIXME: query_user_exec() called even though nothing queued */
280 will_return(query_user_exec_builtin, true);
281 assert_true(get_user_pass_cr(&up, authfile, "UT", flags, NULL));
282 assert_true(up.defined);
283 assert_string_equal(up.username, "user");
284 assert_string_equal(up.password, "fuser");
285}
286
287#ifdef ENABLE_MANAGEMENT
288static void
290{
291 struct user_pass up = { 0 };
292 reset_user_pass(&up);
293 const char *challenge = "CRV1:R,E:Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l:Y3Ix:Please enter token PIN";
294 unsigned int flags = GET_USER_PASS_DYNAMIC_CHALLENGE;
295
296 expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
297 will_return(query_user_exec_builtin, "challenge_response");
298 will_return(query_user_exec_builtin, true);
299 assert_true(get_user_pass_cr(&up, NULL, "UT", flags, challenge));
300 assert_true(up.defined);
301 assert_string_equal(up.username, "cr1");
302 assert_string_equal(up.password, "CRV1::Om01u7Fh4LrGBS7uh0SWmzwabUiGiW6l::challenge_response");
303}
304
305static void
307{
308 struct user_pass up = { 0 };
309 reset_user_pass(&up);
310 const char *challenge = "Please enter token PIN";
311 unsigned int flags = GET_USER_PASS_STATIC_CHALLENGE;
312
313 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:");
314 will_return(query_user_exec_builtin, "cuser");
315 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
316 will_return(query_user_exec_builtin, "cpassword");
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, NULL, "UT", flags, challenge));
322 assert_true(up.defined);
323 assert_string_equal(up.username, "cuser");
324 /* SCRV1:cpassword:challenge_response but base64-encoded */
325 assert_string_equal(up.password, "SCRV1:Y3Bhc3N3b3Jk:Y2hhbGxlbmdlX3Jlc3BvbnNl");
326
327 reset_user_pass(&up);
328
330
331 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Username:");
332 will_return(query_user_exec_builtin, "c1user");
333 expect_string(query_user_exec_builtin, query_user[i].prompt, "Enter UT Password:");
334 will_return(query_user_exec_builtin, "c1password");
335 will_return(query_user_exec_builtin, true);
336 expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
337 will_return(query_user_exec_builtin, "0123456");
338 will_return(query_user_exec_builtin, true);
339 assert_true(get_user_pass_cr(&up, NULL, "UT", flags, challenge));
340 assert_true(up.defined);
341 assert_string_equal(up.username, "c1user");
342 /* password and response concatenated */
343 assert_string_equal(up.password, "c1password0123456");
344
345 reset_user_pass(&up);
346
348
349 /*FIXME: query_user_exec() called even though nothing queued */
350 will_return(query_user_exec_builtin, true);
351 expect_string(query_user_exec_builtin, query_user[i].prompt, "CHALLENGE: Please enter token PIN");
352 will_return(query_user_exec_builtin, "challenge_response");
353 will_return(query_user_exec_builtin, true);
354 assert_true(get_user_pass_cr(&up, "iuser\nipassword", "UT", flags, challenge));
355 assert_true(up.defined);
356 assert_string_equal(up.username, "iuser");
357 /* SCRV1:ipassword:challenge_response but base64-encoded */
358 assert_string_equal(up.password, "SCRV1:aXBhc3N3b3Jk:Y2hhbGxlbmdlX3Jlc3BvbnNl");
359}
360#endif /* ENABLE_MANAGEMENT */
361
362const struct CMUnitTest user_pass_tests[] = {
363 cmocka_unit_test(test_get_user_pass_defined),
364 cmocka_unit_test(test_get_user_pass_needok),
365 cmocka_unit_test(test_get_user_pass_inline_creds),
366 cmocka_unit_test(test_get_user_pass_authfile_stdin),
367 cmocka_unit_test(test_get_user_pass_authfile_file),
368#ifdef ENABLE_MANAGEMENT
369 cmocka_unit_test(test_get_user_pass_dynamic_challenge),
370 cmocka_unit_test(test_get_user_pass_static_challenge),
371#endif /* ENABLE_MANAGEMENT */
372};
373
374int
375main(void)
376{
378 return cmocka_run_group_tests(user_pass_tests, NULL, NULL);
379}
struct _query_user query_user[QUERY_USER_NUMSLOTS]
Global variable, declared in console.c.
Definition console.c:41
#define QUERY_USER_NUMSLOTS
Definition console.h:42
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
#define GET_USER_PASS_STATIC_CHALLENGE_CONCAT
Definition misc.h:122
#define GET_USER_PASS_PASSWORD_ONLY
Definition misc.h:111
#define GET_USER_PASS_INLINE_CREDS
Definition misc.h:121
#define GET_USER_PASS_STATIC_CHALLENGE
Definition misc.h:118
#define GET_USER_PASS_NEED_OK
Definition misc.h:112
#define GET_USER_PASS_DYNAMIC_CHALLENGE
Definition misc.h:117
char * response
The user's response.
Definition console.h:37
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
bool token_defined
Definition misc.h:61
bool defined
Definition misc.h:58
char password[USER_PASS_LEN]
Definition misc.h:73
bool nocache
Definition misc.h:62
char username[USER_PASS_LEN]
Definition misc.h:72
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
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
struct gc_arena gc
Definition test_ssl.c:155
void management_auth_failure(struct management *man, const char *type, const char *reason)
struct management * management
static void reset_user_pass(struct user_pass *up)
const struct CMUnitTest user_pass_tests[]
bool query_user_exec_builtin(void)
Loop through configured query_user slots, using the built-in method for querying the user.
bool unprotect_buffer_win32(char *buf, size_t len)
Decrypt a previously encrypted region of memory using CryptUnProtectMemory() with access restricted t...
bool protect_buffer_win32(char *buf, size_t len)
Encrypt a region of memory using CryptProtectMemory() with access restricted to the current process.
static void test_get_user_pass_defined(void **state)
static void test_get_user_pass_static_challenge(void **state)
bool management_query_user_pass(struct management *man, struct user_pass *up, const char *type, const unsigned int flags, const char *static_challenge)
int main(void)
static void test_get_user_pass_authfile_stdin(void **state)
static void test_get_user_pass_needok(void **state)
static void test_get_user_pass_authfile_file(void **state)
static void test_get_user_pass_dynamic_challenge(void **state)
static void test_get_user_pass_inline_creds(void **state)
int parse_line(const char *line, char **p, const int n, const char *file, const int line_num, int msglevel, struct gc_arena *gc)