1 /*
2 * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
3 * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stddef.h>
23 #include <setjmp.h>
24 #include <cmocka.h>
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <limits.h>
32 #include <syslog.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #ifdef HAVE_SECURITY_PAM_APPL_H
37 #include <security/pam_appl.h>
38 #endif
39 #ifdef HAVE_SECURITY_PAM_MODULES_H
40 #include <security/pam_modules.h>
41 #endif
42 #ifdef HAVE_SECURITY_PAM_EXT_H
43 #include <security/pam_ext.h>
44 #endif
45
46 #include "pwrap_compat.h"
47 #include "libpamtest.h"
48
49 /* GCC have printf type attribute check. */
50 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
51 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
52 #else
53 #define PRINTF_ATTRIBUTE(a,b)
54 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
55
56 #ifndef ZERO_STRUCT
57 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
58 #endif
59
60 struct pwrap_test_ctx {
61 struct pam_conv conv;
62 pam_handle_t *ph;
63 };
64
65 struct pwrap_conv_data {
66 const char **authtoks;
67 size_t authtok_index;
68 };
69
pwrap_conv(int num_msg,const struct pam_message ** msgm,struct pam_response ** response,void * appdata_ptr)70 static int pwrap_conv(int num_msg, const struct pam_message **msgm,
71 struct pam_response **response,
72 void *appdata_ptr)
73 {
74 int i;
75 struct pam_response *reply;
76 const char *password;
77 size_t pwlen;
78 struct pwrap_conv_data *cdata = (struct pwrap_conv_data *) appdata_ptr;
79
80 if (cdata == NULL) {
81 return PAM_CONV_ERR;
82 }
83
84 reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response));
85 if (reply == NULL) {
86 return PAM_CONV_ERR;
87 }
88
89 for (i=0; i < num_msg; i++) {
90 switch (msgm[i]->msg_style) {
91 case PAM_PROMPT_ECHO_OFF:
92 password = (const char *) cdata->authtoks[cdata->authtok_index];
93 if (password == NULL) {
94 free(reply);
95 return PAM_CONV_ERR;
96 }
97
98 pwlen = strlen(password) + 1;
99
100 cdata->authtok_index++;
101
102 reply[i].resp = calloc(pwlen, sizeof(char));
103 if (reply[i].resp == NULL) {
104 free(reply);
105 return PAM_CONV_ERR;
106 }
107 memcpy(reply[i].resp, password, pwlen);
108 break;
109 default:
110 continue;
111 }
112 }
113
114 *response = reply;
115 return PAM_SUCCESS;
116 }
117
setup_passdb(void ** state)118 static int setup_passdb(void **state)
119 {
120 int rv;
121 const char *db;
122 FILE *fp = NULL;
123 char passdb_path[PATH_MAX];
124
125 (void) state; /* unused */
126
127 db = getcwd(passdb_path, PATH_MAX);
128 assert_non_null(db);
129 assert_true(strlen(passdb_path) + sizeof("/passdb") < PATH_MAX);
130 db = strncat(passdb_path, "/passdb", sizeof("/passdb"));
131
132 rv = setenv("PAM_MATRIX_PASSWD", passdb_path, 1);
133 assert_int_equal(rv, 0);
134
135 fp = fopen(db, "w");
136 assert_non_null(fp);
137
138 fprintf(fp, "trinity:secret:matrix\n");
139 fprintf(fp, "neo:secret:pwrap_wrong_svc");
140
141 fflush(fp);
142 fclose(fp);
143
144 return 0;
145 }
146
teardown_passdb(void ** state)147 static int teardown_passdb(void **state)
148 {
149 const char *db;
150
151 (void) state; /* unused */
152
153 db = getenv("PAM_MATRIX_PASSWD");
154 assert_non_null(db);
155 unlink(db);
156
157 /* Don't pollute environment for other tests */
158 unsetenv("PAM_MATRIX_PASSWD");
159
160 return 0;
161 }
162
setup_ctx_only(void ** state)163 static int setup_ctx_only(void **state)
164 {
165 struct pwrap_test_ctx *test_ctx;
166
167 setup_passdb(NULL);
168
169 test_ctx = malloc(sizeof(struct pwrap_test_ctx));
170 assert_non_null(test_ctx);
171
172 test_ctx->conv.conv = pwrap_conv;
173
174 *state = test_ctx;
175 return 0;
176 }
177
setup_noconv(void ** state)178 static int setup_noconv(void **state)
179 {
180 struct pwrap_test_ctx *test_ctx;
181 int rv;
182
183 setup_ctx_only(state);
184 test_ctx = *state;
185
186 /* We'll get an error if the test module talks to us */
187 test_ctx->conv.appdata_ptr = NULL;
188
189 rv = pam_start("matrix", "trinity",
190 &test_ctx->conv, &test_ctx->ph);
191 assert_int_equal(rv, PAM_SUCCESS);
192
193 *state = test_ctx;
194 return 0;
195 }
196
teardown_simple(void ** state)197 static int teardown_simple(void **state)
198 {
199 struct pwrap_test_ctx *test_ctx;
200 test_ctx = (struct pwrap_test_ctx *) *state;
201
202 free(test_ctx);
203 return 0;
204 }
205
test_env(void ** state)206 static void test_env(void **state)
207 {
208 const char *v;
209 struct stat sb;
210 int ret;
211
212 (void) state; /* unused */
213
214 v = getenv("PAM_WRAPPER_RUNTIME_DIR");
215 assert_non_null(v);
216
217 ret = stat(v, &sb);
218 assert_int_not_equal(ret, -1);
219 assert_true(S_ISDIR(sb.st_mode));
220 }
221
test_pam_start(void ** state)222 static void test_pam_start(void **state)
223 {
224 int rv;
225 pam_handle_t *ph;
226 struct pwrap_test_ctx *test_ctx;
227
228 test_ctx = (struct pwrap_test_ctx *) *state;
229 test_ctx->conv.appdata_ptr = (void *) "testpassword";
230
231 rv = pam_start("matrix", "trinity", &test_ctx->conv, &ph);
232 assert_int_equal(rv, PAM_SUCCESS);
233
234 rv = pam_end(ph, PAM_SUCCESS);
235 assert_int_equal(rv, PAM_SUCCESS);
236 }
237
teardown(void ** state)238 static int teardown(void **state)
239 {
240 struct pwrap_test_ctx *test_ctx;
241 int rv;
242
243 teardown_passdb(NULL);
244
245 test_ctx = (struct pwrap_test_ctx *) *state;
246
247 rv = pam_end(test_ctx->ph, PAM_SUCCESS);
248 assert_int_equal(rv, PAM_SUCCESS);
249
250 return teardown_simple(state);
251 }
252
test_pam_authenticate(void ** state)253 static void test_pam_authenticate(void **state)
254 {
255 enum pamtest_err perr;
256 struct pamtest_conv_data conv_data;
257 const char *trinity_authtoks[] = {
258 "secret",
259 NULL,
260 };
261 struct pam_testcase tests[] = {
262 pam_test(PAMTEST_AUTHENTICATE, PAM_SUCCESS),
263 };
264
265 (void) state; /* unused */
266
267 ZERO_STRUCT(conv_data);
268 conv_data.in_echo_off = trinity_authtoks;
269
270 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
271 assert_int_equal(perr, PAMTEST_ERR_OK);
272 }
273
test_pam_authenticate_null_password(void ** state)274 static void test_pam_authenticate_null_password(void **state)
275 {
276 enum pamtest_err perr;
277 struct pamtest_conv_data conv_data;
278 const char *empty_authtoks[] = {
279 NULL,
280 };
281 struct pam_testcase tests[] = {
282 pam_test(PAMTEST_AUTHENTICATE, PAM_CRED_ERR),
283 };
284
285 (void) state; /* unused */
286
287 ZERO_STRUCT(conv_data);
288 conv_data.in_echo_off = empty_authtoks;
289
290 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
291 assert_int_equal(perr, PAMTEST_ERR_OK);
292 }
293
test_pam_authenticate_err(void ** state)294 static void test_pam_authenticate_err(void **state)
295 {
296 enum pamtest_err perr;
297 struct pamtest_conv_data conv_data;
298 const char *trinity_authtoks[] = {
299 "wrong_password",
300 NULL,
301 };
302 struct pam_testcase tests[] = {
303 pam_test(PAMTEST_AUTHENTICATE, PAM_AUTH_ERR),
304 };
305
306 (void) state; /* unused */
307
308 ZERO_STRUCT(conv_data);
309 conv_data.in_echo_off = trinity_authtoks;
310
311 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
312 assert_int_equal(perr, PAMTEST_ERR_OK);
313 }
314
test_pam_acct(void ** state)315 static void test_pam_acct(void **state)
316 {
317 enum pamtest_err perr;
318 struct pam_testcase tests[] = {
319 pam_test(PAMTEST_ACCOUNT, PAM_SUCCESS),
320 };
321
322 (void) state; /* unused */
323
324 perr = run_pamtest("matrix", "trinity", NULL, tests);
325 assert_int_equal(perr, PAMTEST_ERR_OK);
326 }
327
test_pam_acct_err(void ** state)328 static void test_pam_acct_err(void **state)
329 {
330 enum pamtest_err perr;
331 struct pam_testcase tests[] = {
332 pam_test(PAMTEST_ACCOUNT, PAM_PERM_DENIED),
333 };
334
335 (void) state; /* unused */
336
337 perr = run_pamtest("matrix", "neo", NULL, tests);
338 assert_int_equal(perr, PAMTEST_ERR_OK);
339 }
340
free_vlist(char ** vlist)341 static inline void free_vlist(char **vlist)
342 {
343 free(vlist[0]);
344 free(vlist[1]);
345 free(vlist);
346 }
347
test_pam_env_functions(void ** state)348 static void test_pam_env_functions(void **state)
349 {
350 int rv;
351 const char *v;
352 char **vlist;
353 struct pwrap_test_ctx *test_ctx;
354
355 test_ctx = (struct pwrap_test_ctx *) *state;
356
357 rv = pam_putenv(test_ctx->ph, "KEY=value");
358 assert_int_equal(rv, PAM_SUCCESS);
359 rv = pam_putenv(test_ctx->ph, "KEY2=value2");
360 assert_int_equal(rv, PAM_SUCCESS);
361
362 v = pam_getenv(test_ctx->ph, "KEY");
363 assert_non_null(v);
364 assert_string_equal(v, "value");
365
366 v = pam_getenv(test_ctx->ph, "KEY2");
367 assert_non_null(v);
368 assert_string_equal(v, "value2");
369
370 vlist = pam_getenvlist(test_ctx->ph);
371 assert_non_null(vlist);
372 assert_non_null(vlist[0]);
373 assert_string_equal(vlist[0], "KEY=value");
374 assert_non_null(vlist[1]);
375 assert_string_equal(vlist[1], "KEY2=value2");
376 assert_null(vlist[2]);
377 free_vlist(vlist);
378
379 rv = pam_putenv(test_ctx->ph, "KEY2=");
380 assert_int_equal(rv, PAM_SUCCESS);
381
382 vlist = pam_getenvlist(test_ctx->ph);
383 assert_non_null(vlist);
384 assert_non_null(vlist[0]);
385 assert_string_equal(vlist[0], "KEY=value");
386 assert_non_null(vlist[1]);
387 assert_string_equal(vlist[1], "KEY2=");
388 assert_null(vlist[2]);
389 free_vlist(vlist);
390
391 #ifndef HAVE_OPENPAM
392 /* OpenPAM does not support this feature */
393 rv = pam_putenv(test_ctx->ph, "KEY2");
394 assert_int_equal(rv, PAM_SUCCESS);
395
396 vlist = pam_getenvlist(test_ctx->ph);
397 assert_non_null(vlist);
398 assert_non_null(vlist[0]);
399 assert_string_equal(vlist[0], "KEY=value");
400 assert_null(vlist[1]);
401 free_vlist(vlist);
402 #endif
403 }
404
string_in_list(char ** list,const char * key)405 static const char *string_in_list(char **list, const char *key)
406 {
407 if (list == NULL || key == NULL) {
408 return NULL;
409 }
410
411 if (strlen(key) > 0) {
412 char key_eq[strlen(key) + 1 + 1]; /* trailing = and '\0' */
413
414 snprintf(key_eq, sizeof(key_eq), "%s=", key);
415 for (size_t i = 0; list[i] != NULL; i++) {
416 if (strncmp(list[i], key_eq, sizeof(key_eq)-1) == 0) {
417 return list[i] + sizeof(key_eq)-1;
418 }
419 }
420 }
421
422 return NULL;
423 }
424
test_pam_session(void ** state)425 static void test_pam_session(void **state)
426 {
427 enum pamtest_err perr;
428 const char *v;
429 struct pam_testcase tests[] = {
430 pam_test(PAMTEST_OPEN_SESSION, PAM_SUCCESS),
431 pam_test(PAMTEST_GETENVLIST, PAM_SUCCESS),
432 pam_test(PAMTEST_CLOSE_SESSION, PAM_SUCCESS),
433 pam_test(PAMTEST_GETENVLIST, PAM_SUCCESS),
434 };
435
436 (void) state; /* unused */
437
438 perr = run_pamtest("matrix", "trinity", NULL, tests);
439 assert_int_equal(perr, PAMTEST_ERR_OK);
440
441 v = string_in_list(tests[1].case_out.envlist, "HOMEDIR");
442 assert_non_null(v);
443 assert_string_equal(v, "/home/trinity");
444
445 pamtest_free_env(tests[1].case_out.envlist);
446
447 /* environment is cleared after session close */
448 assert_non_null(tests[3].case_out.envlist);
449 #ifdef HAVE_OPENPAM
450 v = string_in_list(tests[3].case_out.envlist, "HOMEDIR");
451 assert_non_null(v);
452 assert_string_equal(v, "");
453 #else
454 assert_null(tests[3].case_out.envlist[0]);
455 #endif
456 pamtest_free_env(tests[3].case_out.envlist);
457 }
458
test_pam_chauthtok(void ** state)459 static void test_pam_chauthtok(void **state)
460 {
461 enum pamtest_err perr;
462 struct pamtest_conv_data conv_data;
463 const char *trinity_new_authtoks[] = {
464 "secret", /* old password */
465 "new_secret", /* new password */
466 "new_secret", /* verify new password */
467 "new_secret", /* login with the new password */
468 NULL,
469 };
470 struct pam_testcase tests[] = {
471 pam_test(PAMTEST_CHAUTHTOK, PAM_SUCCESS),
472 pam_test(PAMTEST_AUTHENTICATE, PAM_SUCCESS),
473 };
474
475 (void) state; /* unused */
476
477 ZERO_STRUCT(conv_data);
478 conv_data.in_echo_off = trinity_new_authtoks;
479
480 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
481 assert_int_equal(perr, PAMTEST_ERR_OK);
482 }
483
test_pam_chauthtok_prelim_failed(void ** state)484 static void test_pam_chauthtok_prelim_failed(void **state)
485 {
486 enum pamtest_err perr;
487 struct pamtest_conv_data conv_data;
488 const char *trinity_new_authtoks[] = {
489 "wrong_secret", /* old password */
490 "new_secret", /* new password */
491 "new_secret", /* verify new password */
492 NULL,
493 };
494 struct pam_testcase tests[] = {
495 pam_test(PAMTEST_CHAUTHTOK, PAM_AUTH_ERR),
496 };
497
498 (void) state; /* unused */
499
500 ZERO_STRUCT(conv_data);
501 conv_data.in_echo_off = trinity_new_authtoks;
502
503 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
504 assert_int_equal(perr, PAMTEST_ERR_OK);
505 }
506
test_pam_chauthtok_diff_passwords(void ** state)507 static void test_pam_chauthtok_diff_passwords(void **state)
508 {
509 enum pamtest_err perr;
510 struct pamtest_conv_data conv_data;
511 const char *trinity_new_authtoks[] = {
512 "wrong_secret", /* old password */
513 "new_secret", /* new password */
514 "different_new_secret", /* verify new password */
515 NULL,
516 };
517 struct pam_testcase tests[] = {
518 pam_test(PAMTEST_CHAUTHTOK, PAM_AUTH_ERR),
519 };
520
521 (void) state; /* unused */
522
523 ZERO_STRUCT(conv_data);
524 conv_data.in_echo_off = trinity_new_authtoks;
525
526 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
527 assert_int_equal(perr, PAMTEST_ERR_OK);
528 }
529
test_pam_setcred(void ** state)530 static void test_pam_setcred(void **state)
531 {
532 enum pamtest_err perr;
533 const char *v;
534 struct pam_testcase tests[] = {
535 pam_test(PAMTEST_GETENVLIST, PAM_SUCCESS),
536 pam_test(PAMTEST_SETCRED, PAM_SUCCESS),
537 pam_test(PAMTEST_GETENVLIST, PAM_SUCCESS),
538 };
539
540 (void) state; /* unused */
541
542 perr = run_pamtest("matrix", "trinity", NULL, tests);
543 assert_int_equal(perr, PAMTEST_ERR_OK);
544
545 /* environment is clean before setcred */
546 assert_non_null(tests[0].case_out.envlist);
547 assert_null(tests[0].case_out.envlist[0]);
548 pamtest_free_env(tests[0].case_out.envlist);
549
550 /* and has an item after setcred */
551 v = string_in_list(tests[2].case_out.envlist, "CRED");
552 assert_non_null(v);
553 assert_string_equal(v, "/tmp/trinity");
554 pamtest_free_env(tests[2].case_out.envlist);
555 }
556
test_pam_item_functions(void ** state)557 static void test_pam_item_functions(void **state)
558 {
559 struct pwrap_test_ctx *test_ctx;
560 const char *item;
561 int rv;
562
563 test_ctx = (struct pwrap_test_ctx *) *state;
564
565 rv = pam_get_item(test_ctx->ph, PAM_USER, (const void **) &item);
566 assert_int_equal(rv, PAM_SUCCESS);
567 assert_string_equal(item, "trinity");
568
569 rv = pam_set_item(test_ctx->ph, PAM_USER_PROMPT, "test_login");
570 assert_int_equal(rv, PAM_SUCCESS);
571 assert_string_equal(item, "trinity");
572
573 rv = pam_get_item(test_ctx->ph, PAM_USER_PROMPT, (const void **) &item);
574 assert_int_equal(rv, PAM_SUCCESS);
575 assert_string_equal(item, "test_login");
576
577 rv = pam_set_item(test_ctx->ph, PAM_AUTHTOK, "mysecret");
578 #ifdef HAVE_OPENPAM
579 /* OpenPAM allows PAM_AUTHTOK getset */
580 assert_int_equal(rv, PAM_SUCCESS);
581 #else
582 assert_int_equal(rv, PAM_BAD_ITEM);
583 #endif
584
585 rv = pam_get_item(test_ctx->ph, PAM_AUTHTOK, (const void **) &item);
586 #ifdef HAVE_OPENPAM
587 /* OpenPAM allows PAM_AUTHTOK getset */
588 assert_int_equal(rv, PAM_SUCCESS);
589 assert_string_equal(item, "mysecret");
590 #else
591 assert_int_equal(rv, PAM_BAD_ITEM);
592 #endif
593
594 }
595
add_to_reply(struct pam_response * res,const char * s1,const char * s2)596 static int add_to_reply(struct pam_response *res,
597 const char *s1,
598 const char *s2)
599 {
600 size_t res_len;
601 int rv;
602
603 res_len = strlen(s1) + strlen(s2) + 1;
604
605 res->resp = calloc(res_len, sizeof(char));
606 if (res->resp == NULL) {
607 return ENOMEM;
608 }
609
610 rv = snprintf(res->resp, res_len, "%s%s", s1, s2);
611 if (rv < 0) {
612 return EIO;
613 }
614
615 return 0;
616 }
617
pwrap_echo_conv(int num_msg,const struct pam_message ** msgm,struct pam_response ** response,void * appdata_ptr)618 static int pwrap_echo_conv(int num_msg,
619 const struct pam_message **msgm,
620 struct pam_response **response,
621 void *appdata_ptr)
622 {
623 int i;
624 struct pam_response *reply;
625 int *resp_array = appdata_ptr;
626
627 reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response));
628 if (reply == NULL) {
629 return PAM_CONV_ERR;
630 }
631
632 for (i=0; i < num_msg; i++) {
633 switch (msgm[i]->msg_style) {
634 case PAM_PROMPT_ECHO_OFF:
635 add_to_reply(&reply[i], "echo off: ", msgm[i]->msg);
636 break;
637 case PAM_PROMPT_ECHO_ON:
638 add_to_reply(&reply[i], "echo on: ", msgm[i]->msg);
639 break;
640 case PAM_TEXT_INFO:
641 resp_array[0] = 1;
642 break;
643 case PAM_ERROR_MSG:
644 resp_array[1] = 1;
645 break;
646 default:
647 break;
648 }
649 }
650
651 *response = reply;
652 return PAM_SUCCESS;
653 }
654
655 static int vprompt_test_fn(pam_handle_t *pamh, int style,
656 char **response, const char *fmt, ...) PRINTF_ATTRIBUTE(4, 5);
657
vprompt_test_fn(pam_handle_t * pamh,int style,char ** response,const char * fmt,...)658 static int vprompt_test_fn(pam_handle_t *pamh, int style,
659 char **response, const char *fmt, ...)
660 {
661 va_list args;
662 int rv;
663
664 va_start(args, fmt);
665 rv = pam_vprompt(pamh, style, response, fmt, args);
666 va_end(args);
667
668 return rv;
669 }
670
test_pam_prompt(void ** state)671 static void test_pam_prompt(void **state)
672 {
673 struct pwrap_test_ctx *test_ctx;
674 int rv;
675 char *response;
676 int resp_array[2];
677
678 test_ctx = (struct pwrap_test_ctx *) *state;
679
680 memset(resp_array, 0, sizeof(resp_array));
681
682 test_ctx->conv.conv = pwrap_echo_conv;
683 test_ctx->conv.appdata_ptr = resp_array;
684
685 rv = pam_start("matrix", "trinity",
686 &test_ctx->conv, &test_ctx->ph);
687 assert_int_equal(rv, PAM_SUCCESS);
688
689 rv = pam_prompt(test_ctx->ph, PAM_PROMPT_ECHO_OFF, &response, "no echo");
690 assert_int_equal(rv, PAM_SUCCESS);
691 assert_string_equal(response, "echo off: no echo");
692 free(response);
693
694 rv = vprompt_test_fn(test_ctx->ph, PAM_PROMPT_ECHO_OFF, &response, "no echo");
695 assert_int_equal(rv, PAM_SUCCESS);
696 assert_string_equal(response, "echo off: no echo");
697 free(response);
698
699 rv = pam_prompt(test_ctx->ph, PAM_PROMPT_ECHO_ON, &response, "echo");
700 assert_int_equal(rv, PAM_SUCCESS);
701 assert_string_equal(response, "echo on: echo");
702 free(response);
703
704 rv = vprompt_test_fn(test_ctx->ph, PAM_PROMPT_ECHO_ON, &response, "echo");
705 assert_int_equal(rv, PAM_SUCCESS);
706 assert_string_equal(response, "echo on: echo");
707 free(response);
708
709 assert_int_equal(resp_array[0], 0);
710 pam_info(test_ctx->ph, "info");
711 assert_int_equal(resp_array[0], 1);
712
713 assert_int_equal(resp_array[1], 0);
714 pam_error(test_ctx->ph, "error");
715 assert_int_equal(resp_array[1], 1);
716 }
717
test_pam_strerror(void ** state)718 static void test_pam_strerror(void **state)
719 {
720 struct pwrap_test_ctx *test_ctx;
721 const char *s = NULL;
722
723 test_ctx = (struct pwrap_test_ctx *) *state;
724
725 s = pam_strerror(test_ctx->ph, PAM_AUTH_ERR);
726 assert_non_null(s);
727 }
728
test_pam_authenticate_db_opt(void ** state)729 static void test_pam_authenticate_db_opt(void **state)
730 {
731 enum pamtest_err perr;
732 struct pamtest_conv_data conv_data;
733 char auth_info_msg[PAM_MAX_MSG_SIZE] = { '\0' };
734 char *info_arr[] = {
735 auth_info_msg,
736 NULL,
737 };
738 const char *trinity_authtoks[] = {
739 "secret_ro",
740 NULL,
741 };
742 struct pam_testcase tests[] = {
743 pam_test(PAMTEST_AUTHENTICATE, PAM_SUCCESS),
744 };
745
746 (void) state; /* unused */
747
748 ZERO_STRUCT(conv_data);
749
750 conv_data.in_echo_on = trinity_authtoks;
751 conv_data.out_info = info_arr;
752
753 perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests);
754 assert_int_equal(perr, PAMTEST_ERR_OK);
755
756 assert_string_equal(auth_info_msg, "Authentication succeeded");
757 }
758
test_pam_authenticate_db_opt_err(void ** state)759 static void test_pam_authenticate_db_opt_err(void **state)
760 {
761 enum pamtest_err perr;
762 struct pamtest_conv_data conv_data;
763 char auth_err_msg[PAM_MAX_MSG_SIZE] = { '\0' };
764 char *err_arr[] = {
765 auth_err_msg,
766 NULL,
767 };
768 const char *trinity_authtoks[] = {
769 "wrong_secret",
770 NULL,
771 };
772 struct pam_testcase tests[] = {
773 pam_test(PAMTEST_AUTHENTICATE, PAM_AUTH_ERR),
774 };
775
776 (void) state; /* unused */
777
778 ZERO_STRUCT(conv_data);
779 conv_data.in_echo_on = trinity_authtoks;
780 conv_data.out_err = err_arr;
781
782 perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests);
783 assert_int_equal(perr, PAMTEST_ERR_OK);
784
785 assert_string_equal(auth_err_msg, "Authentication failed");
786 }
787
788
789 #ifdef HAVE_PAM_VSYSLOG
790 static void vsyslog_test_fn(const pam_handle_t *pamh,
791 int priority,
792 const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
793
vsyslog_test_fn(const pam_handle_t * pamh,int priority,const char * fmt,...)794 static void vsyslog_test_fn(const pam_handle_t *pamh,
795 int priority,
796 const char *fmt, ...)
797 {
798 va_list args;
799
800 va_start(args, fmt);
801 pam_vsyslog(pamh, priority, fmt, args);
802 va_end(args);
803 }
804
test_pam_vsyslog(void ** state)805 static void test_pam_vsyslog(void **state)
806 {
807 struct pwrap_test_ctx *test_ctx;
808
809 test_ctx = (struct pwrap_test_ctx *) *state;
810
811 pam_syslog(test_ctx->ph, LOG_INFO, "This is pam_wrapper test\n");
812 vsyslog_test_fn(test_ctx->ph, LOG_INFO, "This is pam_wrapper test\n");
813 }
814 #endif /* HAVE_PAM_VSYSLOG */
815
test_libpamtest_strerror(void ** state)816 static void test_libpamtest_strerror(void **state)
817 {
818 const char *s;
819
820 (void) state; /* unused */
821
822 s = pamtest_strerror(PAMTEST_ERR_OK);
823 assert_non_null(s);
824
825 s = pamtest_strerror(PAMTEST_ERR_START);
826 assert_non_null(s);
827
828 s = pamtest_strerror(PAMTEST_ERR_CASE);
829 assert_non_null(s);
830
831 s = pamtest_strerror(PAMTEST_ERR_OP);
832 assert_non_null(s);
833
834 s = pamtest_strerror(PAMTEST_ERR_END);
835 assert_non_null(s);
836
837 s = pamtest_strerror(PAMTEST_ERR_KEEPHANDLE);
838 assert_non_null(s);
839
840 s = pamtest_strerror(PAMTEST_ERR_INTERNAL);
841 assert_non_null(s);
842 }
843
844 #define test_setenv(env) setenv(env, "test_"env, 1)
845
846 #define test_getenv(envlist, key) do { \
847 const char *__v; \
848 __v = string_in_list(envlist, key); \
849 assert_non_null(__v); \
850 assert_string_equal(__v, "test_"key); \
851 } while(0);
852
test_get_set(void ** state)853 static void test_get_set(void **state)
854 {
855 #ifndef HAVE_OPENPAM
856 const char *svc;
857 #endif
858 enum pamtest_err perr;
859 struct pam_testcase tests[] = {
860 pam_test(PAMTEST_OPEN_SESSION, PAM_SUCCESS),
861 pam_test(PAMTEST_GETENVLIST, PAM_SUCCESS),
862 };
863
864 (void) state; /* unused */
865
866 #ifndef HAVE_OPENPAM
867 test_setenv("PAM_SERVICE");
868 #endif
869 test_setenv("PAM_USER");
870 test_setenv("PAM_USER_PROMPT");
871 test_setenv("PAM_TTY");
872 test_setenv("PAM_RUSER");
873 test_setenv("PAM_RHOST");
874 test_setenv("PAM_AUTHTOK");
875 test_setenv("PAM_OLDAUTHTOK");
876 #ifdef PAM_XDISPLAY
877 test_setenv("PAM_XDISPLAY");
878 #endif
879 #ifdef PAM_AUTHTOK_TYPE
880 test_setenv("PAM_AUTHTOK_TYPE");
881 #endif
882
883 perr = run_pamtest("pwrap_get_set", "trinity", NULL, tests);
884 assert_int_equal(perr, PAMTEST_ERR_OK);
885
886 /* PAM_SERVICE is a special case, Linux's libpam lowercases it.
887 * OpenPAM only allows PAM_SERVICE to be set by pam_start()
888 */
889 #ifndef HAVE_OPENPAM
890 svc = string_in_list(tests[1].case_out.envlist, "PAM_SERVICE");
891 assert_non_null(svc);
892 assert_string_equal(svc, "test_pam_service");
893 #endif
894
895 test_getenv(tests[1].case_out.envlist, "PAM_USER");
896 test_getenv(tests[1].case_out.envlist, "PAM_USER_PROMPT");
897 test_getenv(tests[1].case_out.envlist, "PAM_TTY");
898 test_getenv(tests[1].case_out.envlist, "PAM_RUSER");
899 test_getenv(tests[1].case_out.envlist, "PAM_RHOST");
900 test_getenv(tests[1].case_out.envlist, "PAM_AUTHTOK");
901 test_getenv(tests[1].case_out.envlist, "PAM_OLDAUTHTOK");
902 #ifdef PAM_XDISPLAY
903 test_getenv(tests[1].case_out.envlist, "PAM_XDISPLAY");
904 #endif
905 #ifdef PAM_AUTHTOK_TYPE
906 test_getenv(tests[1].case_out.envlist, "PAM_AUTHTOK_TYPE");
907 #endif
908
909 pamtest_free_env(tests[1].case_out.envlist);
910 }
911
test_libpamtest_keepopen(void ** state)912 static void test_libpamtest_keepopen(void **state)
913 {
914 int rv;
915 enum pamtest_err perr;
916 struct pamtest_conv_data conv_data;
917 const char *trinity_authtoks[] = {
918 "secret",
919 NULL,
920 };
921 struct pam_testcase tests[] = {
922 pam_test(PAMTEST_AUTHENTICATE, PAM_SUCCESS),
923 pam_test(PAMTEST_KEEPHANDLE, PAM_SUCCESS),
924 };
925
926 (void) state; /* unused */
927
928 ZERO_STRUCT(conv_data);
929 conv_data.in_echo_off = trinity_authtoks;
930
931 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
932 assert_int_equal(perr, PAMTEST_ERR_OK);
933
934 assert_non_null(tests[1].case_out.ph);
935
936 rv = pam_end(tests[1].case_out.ph, PAM_SUCCESS);
937 assert_int_equal(rv, PAM_SUCCESS);
938 }
939
test_libpamtest_get_failed_test(void ** state)940 static void test_libpamtest_get_failed_test(void **state)
941 {
942 enum pamtest_err perr;
943 struct pamtest_conv_data conv_data;
944 const char *trinity_authtoks[] = {
945 "secret",
946 NULL,
947 };
948 struct pam_testcase tests[] = {
949 pam_test(PAMTEST_AUTHENTICATE, PAM_AUTH_ERR),
950 };
951 const struct pam_testcase *failed_tc;
952
953 (void) state; /* unused */
954
955 ZERO_STRUCT(conv_data);
956 conv_data.in_echo_off = trinity_authtoks;
957
958 perr = run_pamtest("matrix", "trinity", &conv_data, tests);
959 assert_int_not_equal(perr, PAMTEST_ERR_OK);
960
961 failed_tc = pamtest_failed_case(tests);
962 assert_ptr_equal(failed_tc, &tests[0]);
963 }
964
main(void)965 int main(void) {
966 int rc;
967
968 const struct CMUnitTest init_tests[] = {
969 cmocka_unit_test(test_env),
970 cmocka_unit_test_setup_teardown(test_pam_start,
971 setup_ctx_only,
972 teardown_simple),
973 cmocka_unit_test_setup_teardown(test_pam_authenticate,
974 setup_passdb,
975 teardown_passdb),
976 cmocka_unit_test_setup_teardown(test_pam_authenticate_null_password,
977 setup_passdb,
978 teardown_passdb),
979 cmocka_unit_test_setup_teardown(test_pam_authenticate_err,
980 setup_passdb,
981 teardown_passdb),
982 cmocka_unit_test_setup_teardown(test_pam_acct,
983 setup_passdb,
984 teardown_passdb),
985 cmocka_unit_test_setup_teardown(test_pam_acct_err,
986 setup_passdb,
987 teardown_passdb),
988 cmocka_unit_test_setup_teardown(test_pam_env_functions,
989 setup_noconv,
990 teardown),
991 cmocka_unit_test_setup_teardown(test_pam_session,
992 setup_passdb,
993 teardown_passdb),
994 cmocka_unit_test_setup_teardown(test_pam_chauthtok,
995 setup_passdb,
996 teardown_passdb),
997 cmocka_unit_test_setup_teardown(test_pam_chauthtok_prelim_failed,
998 setup_passdb,
999 teardown_passdb),
1000 cmocka_unit_test_setup_teardown(test_pam_chauthtok_diff_passwords,
1001 setup_passdb,
1002 teardown_passdb),
1003 cmocka_unit_test_setup_teardown(test_pam_setcred,
1004 setup_passdb,
1005 teardown_passdb),
1006 cmocka_unit_test_setup_teardown(test_pam_item_functions,
1007 setup_noconv,
1008 teardown),
1009 cmocka_unit_test_setup_teardown(test_pam_prompt,
1010 setup_ctx_only,
1011 teardown),
1012 cmocka_unit_test_setup_teardown(test_pam_strerror,
1013 setup_noconv,
1014 teardown),
1015 cmocka_unit_test_setup_teardown(test_pam_authenticate_db_opt,
1016 setup_ctx_only,
1017 teardown_simple),
1018 cmocka_unit_test_setup_teardown(test_pam_authenticate_db_opt_err,
1019 setup_ctx_only,
1020 teardown_simple),
1021 #ifdef HAVE_PAM_VSYSLOG
1022 cmocka_unit_test_setup_teardown(test_pam_vsyslog,
1023 setup_noconv,
1024 teardown),
1025 #endif
1026 cmocka_unit_test_setup_teardown(test_libpamtest_keepopen,
1027 setup_passdb,
1028 teardown_passdb),
1029 cmocka_unit_test_setup_teardown(test_libpamtest_get_failed_test,
1030 setup_passdb,
1031 teardown_passdb),
1032 cmocka_unit_test(test_libpamtest_strerror),
1033 cmocka_unit_test(test_get_set),
1034 };
1035
1036 rc = cmocka_run_group_tests(init_tests, NULL, NULL);
1037
1038 return rc;
1039 }
1040
1041