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