Line data Source code
1 : /*
2 : Copyright (C) 2015 Red Hat
3 :
4 : SSSD tests: PAM tests
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <popt.h>
21 : #include <libpamtest.h>
22 :
23 : #include "util/util.h"
24 : #include "tests/cmocka/common_mock.h"
25 :
26 14 : static void assert_pam_test(enum pamtest_err perr,
27 : const enum pamtest_err perr_exp,
28 : struct pamtest_case *tests)
29 : {
30 : const struct pamtest_case *tc;
31 :
32 14 : if (perr != perr_exp) {
33 0 : tc = pamtest_failed_case(tests);
34 0 : if (tc == NULL) {
35 : /* Probably pam_start/pam_end failed..*/
36 0 : fail_msg("PAM test with pamtest err %d\n", perr);
37 : }
38 :
39 : /* FIXME - would be nice to print index..*/
40 0 : fail_msg("PAM test expected %d returned %d\n",
41 : tc->expected_rv, tc->op_rv);
42 : }
43 14 : }
44 :
45 6 : static char *service_arg(TALLOC_CTX *mem_ctx,
46 : const char *src_file,
47 : const char *dst_file,
48 : const char *arg)
49 : {
50 : TALLOC_CTX *tmp_ctx;
51 : const char *dir;
52 : char *dst;
53 : char *src;
54 : errno_t ret;
55 : struct stat sb;
56 : char *svc;
57 6 : int src_fd = -1;
58 6 : FILE *dst_f = NULL;
59 : ssize_t nb;
60 : char *line;
61 6 : size_t nlines = 0;
62 : size_t i;
63 :
64 6 : dir = getenv("PWRAP_TEST_CONF_DIR");
65 6 : if (dir == NULL) {
66 0 : return NULL;
67 : }
68 :
69 6 : tmp_ctx = talloc_new(NULL);
70 6 : if (tmp_ctx == NULL) {
71 0 : return NULL;
72 : }
73 :
74 6 : src = talloc_asprintf(tmp_ctx, "%s/%s", dir, src_file);
75 6 : dst = talloc_asprintf(tmp_ctx, "%s/%s", dir, dst_file);
76 6 : if (dst == NULL || src == NULL) {
77 : goto fail;
78 : }
79 :
80 6 : ret = stat(src, &sb);
81 6 : if (ret == -1) {
82 0 : goto fail;
83 : }
84 :
85 6 : svc = talloc_size(tmp_ctx, sb.st_size); /* This is OK, the file is small..*/
86 6 : if (svc == NULL) {
87 0 : goto fail;
88 : }
89 :
90 6 : src_fd = open(src, O_RDONLY);
91 6 : if (src_fd == -1) {
92 0 : goto fail;
93 : }
94 :
95 6 : dst_f = fopen(dst, "w");
96 6 : if (dst_f == NULL) {
97 0 : goto fail;
98 : }
99 :
100 6 : nb = sss_atomic_read_s(src_fd, svc, sb.st_size);
101 6 : if (nb < sb.st_size) {
102 0 : goto fail;
103 : }
104 :
105 6 : line = strchr(svc, '\n');
106 33 : while (line != NULL) {
107 21 : *line = '\0';
108 21 : line++;
109 21 : nlines++;
110 :
111 21 : line = strchr(line, '\n');
112 : }
113 :
114 6 : line = svc;
115 27 : for (i = 0; i < nlines; i++) {
116 21 : nb = fprintf(dst_f, "%s %s\n", line, arg);
117 21 : if (nb < 0) {
118 0 : goto fail;
119 : }
120 21 : line += strlen(line) + 1;
121 : }
122 :
123 6 : ret = EOK;
124 6 : fflush(dst_f);
125 6 : fclose(dst_f);
126 6 : talloc_steal(mem_ctx, dst);
127 6 : return dst;
128 : fail:
129 0 : if (dst_f) {
130 0 : fclose(dst_f);
131 : }
132 0 : talloc_free(tmp_ctx);
133 0 : return NULL;
134 : }
135 :
136 : struct test_svc {
137 : const char *svc_file;
138 : };
139 :
140 6 : static const char *find_string_in_list(char **list, const char *key)
141 6 : {
142 6 : char key_eq[strlen(key)+1+1]; /* trailing NULL and '=' */
143 :
144 6 : if (list == NULL || key == NULL) {
145 2 : return NULL;
146 : }
147 :
148 4 : snprintf(key_eq, sizeof(key_eq), "%s=", key);
149 6 : for (size_t i = 0; list[i] != NULL; i++) {
150 5 : if (strncmp(list[i], key_eq, sizeof(key_eq)-1) == 0) {
151 3 : return list[i] + sizeof(key_eq)-1;
152 : }
153 : }
154 :
155 1 : return NULL;
156 : }
157 :
158 3 : static void assert_in_env(struct pamtest_case *test,
159 : const char *key,
160 : const char *val)
161 : {
162 : const char *v;
163 :
164 3 : v = find_string_in_list(test->case_out.envlist, key);
165 3 : assert_non_null(v);
166 3 : assert_string_equal(v, val);
167 3 : }
168 :
169 3 : static void assert_not_in_env(struct pamtest_case *test,
170 : const char *key)
171 : {
172 : const char *v;
173 :
174 3 : v = find_string_in_list(test->case_out.envlist, key);
175 3 : assert_null(v);
176 3 : }
177 :
178 6 : static int setup_svc(void **state)
179 : {
180 : struct test_svc *svc;
181 :
182 6 : svc = talloc_zero(NULL, struct test_svc);
183 6 : if (svc == NULL) {
184 0 : return 1;
185 : }
186 :
187 6 : *state = svc;
188 6 : return 0;
189 : }
190 :
191 6 : static int teardown_svc(void **state)
192 : {
193 6 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
194 :
195 6 : if (svc != NULL && svc->svc_file != NULL) {
196 6 : unlink(svc->svc_file);
197 : }
198 6 : return 0;
199 : }
200 :
201 2 : static void test_pam_authenticate(void **state)
202 : {
203 : enum pamtest_err perr;
204 : const char *v;
205 2 : const char *testuser_authtoks[] = {
206 : "secret",
207 : NULL,
208 : };
209 2 : struct pamtest_case tests[] = {
210 : { PAMTEST_AUTHENTICATE, PAM_SUCCESS, 0, 0 },
211 : { PAMTEST_SETCRED, PAM_SUCCESS, 0, 0 },
212 : { PAMTEST_GETENVLIST, PAM_SUCCESS, 0, 0 },
213 : { PAMTEST_OPEN_SESSION, PAM_SUCCESS, 0, 0 },
214 : { PAMTEST_GETENVLIST, PAM_SUCCESS, 0, 0 },
215 : { PAMTEST_CLOSE_SESSION, PAM_SUCCESS, 0, 0 },
216 : { PAMTEST_GETENVLIST, PAM_SUCCESS, 0, 0 },
217 : { PAMTEST_SENTINEL, 0, 0, 0 },
218 : };
219 :
220 : (void) state; /* unused */
221 :
222 2 : perr = pamtest("test_pam_sss", "testuser", testuser_authtoks, tests);
223 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
224 :
225 1 : assert_not_in_env(&tests[0], "CREDS");
226 1 : assert_not_in_env(&tests[0], "SESSION");
227 :
228 1 : assert_in_env(&tests[2], "CREDS", "set");
229 1 : assert_not_in_env(&tests[2], "SESSION");
230 :
231 1 : assert_in_env(&tests[4], "CREDS", "set");
232 1 : assert_in_env(&tests[4], "SESSION", "open");
233 1 : }
234 :
235 1 : static void test_pam_authenticate_err(void **state)
236 : {
237 : enum pamtest_err perr;
238 1 : const char *testuser_authtoks[] = {
239 : "wrong_secret",
240 : NULL,
241 : };
242 1 : struct pamtest_case tests[] = {
243 : { PAMTEST_AUTHENTICATE, PAM_AUTH_ERR, 0, 0 },
244 : { PAMTEST_SENTINEL, 0, 0, 0 },
245 : };
246 :
247 : (void) state; /* unused */
248 :
249 1 : perr = pamtest("test_pam_sss", "testuser", testuser_authtoks, tests);
250 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
251 1 : }
252 :
253 1 : static void test_pam_acct(void **state)
254 : {
255 : enum pamtest_err perr;
256 1 : struct pamtest_case tests[] = {
257 : { PAMTEST_ACCOUNT, PAM_SUCCESS, 0, 0 },
258 : { PAMTEST_SENTINEL, 0, 0, 0 },
259 : };
260 :
261 : (void) state; /* unused */
262 :
263 1 : perr = pamtest("test_pam_sss", "allowed_user", NULL, tests);
264 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
265 1 : }
266 :
267 1 : static void test_pam_acct_err(void **state)
268 : {
269 : enum pamtest_err perr;
270 1 : struct pamtest_case tests[] = {
271 : { PAMTEST_ACCOUNT, PAM_PERM_DENIED, 0, 0 },
272 : { PAMTEST_SENTINEL, 0, 0, 0 },
273 : };
274 :
275 : (void) state; /* unused */
276 :
277 1 : perr = pamtest("test_pam_sss", "denied_user", NULL, tests);
278 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
279 1 : }
280 :
281 1 : static void test_pam_chauthtok(void **state)
282 : {
283 : enum pamtest_err perr;
284 1 : const char *testuser_authtoks[] = {
285 : "secret",
286 : "new_secret",
287 : "new_secret",
288 : NULL,
289 : };
290 1 : struct pamtest_case tests[] = {
291 : { PAMTEST_CHAUTHTOK, PAM_SUCCESS, 0, 0 },
292 : { PAMTEST_SENTINEL, 0, 0, 0 },
293 : };
294 :
295 : (void) state; /* unused */
296 :
297 1 : perr = pamtest("test_pam_sss", "testuser", testuser_authtoks, tests);
298 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
299 1 : }
300 :
301 1 : static void test_pam_chauthtok_prelim_fail(void **state)
302 : {
303 : enum pamtest_err perr;
304 1 : const char *testuser_authtoks[] = {
305 : "wrong_secret",
306 : NULL,
307 : };
308 1 : struct pamtest_case tests[] = {
309 : { PAMTEST_CHAUTHTOK, PAM_AUTH_ERR, 0, 0 },
310 : { PAMTEST_SENTINEL, 0, 0, 0 },
311 : };
312 :
313 : (void) state; /* unused */
314 :
315 1 : perr = pamtest("test_pam_sss", "testuser", testuser_authtoks, tests);
316 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
317 1 : }
318 :
319 1 : static void test_pam_chauthtok_diff_authtoks(void **state)
320 : {
321 : enum pamtest_err perr;
322 1 : const char *testuser_authtoks[] = {
323 : "secret",
324 : "new_secret",
325 : "different_secret",
326 : NULL,
327 : };
328 1 : struct pamtest_case tests[] = {
329 : { PAMTEST_CHAUTHTOK, PAM_CRED_ERR, 0, 0 },
330 : { PAMTEST_SENTINEL, 0, 0, 0 },
331 : };
332 :
333 : (void) state; /* unused */
334 :
335 1 : perr = pamtest("test_pam_sss", "testuser", testuser_authtoks, tests);
336 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
337 1 : }
338 :
339 1 : static void test_pam_authenticate_root(void **state)
340 : {
341 : enum pamtest_err perr;
342 1 : struct pamtest_case tests[] = {
343 : { PAMTEST_AUTHENTICATE, PAM_USER_UNKNOWN, 0, 0 },
344 : { PAMTEST_SENTINEL, 0, 0, 0 },
345 : };
346 :
347 : (void) state; /* unused */
348 :
349 1 : perr = pamtest("test_pam_sss_ignore", "root", NULL, tests);
350 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
351 1 : }
352 :
353 1 : static void test_pam_authenticate_root_ignore(void **state)
354 : {
355 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
356 : enum pamtest_err perr;
357 1 : struct pamtest_case tests[] = {
358 : { PAMTEST_AUTHENTICATE, PAM_IGNORE, 0, 0 },
359 : { PAMTEST_SENTINEL, 0, 0, 0 },
360 : };
361 1 : const char *svcname = "test_pam_sss_ignore_arg";
362 :
363 : /* Copy file from the previous test and just add an argument. The retval
364 : * will be different this time
365 : */
366 1 : svc->svc_file = service_arg(svc, "test_pam_sss_ignore",
367 : svcname, "ignore_unknown_user");
368 1 : assert_non_null(svc->svc_file);
369 :
370 1 : perr = pamtest(svcname, "root", NULL, tests);
371 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
372 1 : }
373 :
374 1 : static void test_pam_authenticate_domains(void **state)
375 : {
376 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
377 : enum pamtest_err perr;
378 1 : const char *authtoks[] = {
379 : "secret",
380 : NULL,
381 : };
382 1 : struct pamtest_case tests[] = {
383 : { PAMTEST_AUTHENTICATE, PAM_SUCCESS, 0, 0 },
384 : { PAMTEST_SENTINEL, 0, 0, 0 },
385 : };
386 1 : const char *svcname = "test_pam_sss_domains";
387 :
388 : /* Copy file from the previous test and just add an argument. The retval
389 : * will be different this time
390 : */
391 1 : svc->svc_file = service_arg(svc, "test_pam_sss",
392 : svcname, "domains=mydomain");
393 1 : assert_non_null(svc->svc_file);
394 :
395 1 : perr = pamtest(svcname, "domtest", authtoks, tests);
396 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
397 1 : }
398 :
399 1 : static void test_pam_authenticate_domains_err(void **state)
400 : {
401 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
402 : enum pamtest_err perr;
403 1 : struct pamtest_case tests[] = {
404 : { PAMTEST_AUTHENTICATE, PAM_SYSTEM_ERR, 0, 0 },
405 : { PAMTEST_SENTINEL, 0, 0, 0 },
406 : };
407 1 : const char *svcname = "test_pam_sss_domains_err";
408 :
409 : /* Copy file from the previous test and just add an argument. The retval
410 : * will be different this time
411 : */
412 1 : svc->svc_file = service_arg(svc, "test_pam_sss",
413 : svcname, "domains=");
414 1 : assert_non_null(svc->svc_file);
415 :
416 1 : perr = pamtest(svcname, "domtest", NULL, tests);
417 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
418 1 : }
419 :
420 1 : static void test_pam_authenticate_retry(void **state)
421 : {
422 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
423 : enum pamtest_err perr;
424 1 : const char *authtoks[] = {
425 : "wrong_secret",
426 : "retried_secret",
427 : NULL,
428 : };
429 1 : struct pamtest_case tests[] = {
430 : { PAMTEST_AUTHENTICATE, PAM_SUCCESS, 0, 0 },
431 : { PAMTEST_SENTINEL, 0, 0, 0 },
432 : };
433 1 : const char *svcname = "test_pam_sss_retry";
434 :
435 : /* Copy file from the previous test and just add an argument. The retval
436 : * will be different this time
437 : */
438 1 : svc->svc_file = service_arg(svc, "test_pam_sss",
439 : svcname, "retry=1");
440 1 : assert_non_null(svc->svc_file);
441 :
442 1 : perr = pamtest(svcname, "retrytest", authtoks, tests);
443 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
444 1 : }
445 :
446 1 : static void test_pam_authenticate_retry_neg(void **state)
447 : {
448 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
449 : enum pamtest_err perr;
450 1 : const char *authtoks[] = {
451 : "wrong_secret",
452 : "retried_secret",
453 : NULL,
454 : };
455 1 : struct pamtest_case tests[] = {
456 : { PAMTEST_AUTHENTICATE, PAM_AUTH_ERR, 0, 0 },
457 : { PAMTEST_SENTINEL, 0, 0, 0 },
458 : };
459 1 : const char *svcname = "test_pam_sss_retry";
460 :
461 : /* Copy file from the previous test and just add an argument. The retval
462 : * will be different this time
463 : */
464 1 : svc->svc_file = service_arg(svc, "test_pam_sss",
465 : svcname, "retry=-1");
466 1 : assert_non_null(svc->svc_file);
467 :
468 1 : perr = pamtest(svcname, "retrytest", authtoks, tests);
469 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
470 1 : }
471 :
472 1 : static void test_pam_authenticate_retry_eparse(void **state)
473 : {
474 1 : struct test_svc *svc = talloc_get_type(*state, struct test_svc);
475 : enum pamtest_err perr;
476 1 : const char *authtoks[] = {
477 : "wrong_secret",
478 : "retried_secret",
479 : NULL,
480 : };
481 1 : struct pamtest_case tests[] = {
482 : { PAMTEST_AUTHENTICATE, PAM_AUTH_ERR, 0, 0 },
483 : { PAMTEST_SENTINEL, 0, 0, 0 },
484 : };
485 1 : const char *svcname = "test_pam_sss_retry";
486 :
487 : /* Copy file from the previous test and just add an argument. The retval
488 : * will be different this time
489 : */
490 1 : svc->svc_file = service_arg(svc, "test_pam_sss",
491 : svcname, "retry=");
492 1 : assert_non_null(svc->svc_file);
493 :
494 1 : perr = pamtest(svcname, "retrytest", authtoks, tests);
495 1 : assert_pam_test(perr, PAMTEST_ERR_OK, tests);
496 1 : }
497 :
498 2 : int main(int argc, const char *argv[])
499 : {
500 : poptContext pc;
501 : int opt;
502 12 : struct poptOption long_options[] = {
503 : POPT_AUTOHELP
504 10 : SSSD_DEBUG_OPTS
505 : POPT_TABLEEND
506 : };
507 :
508 2 : const struct CMUnitTest tests[] = {
509 : cmocka_unit_test(test_pam_authenticate),
510 : cmocka_unit_test(test_pam_authenticate_err),
511 : cmocka_unit_test(test_pam_acct),
512 : cmocka_unit_test(test_pam_acct_err),
513 : cmocka_unit_test(test_pam_chauthtok),
514 : cmocka_unit_test(test_pam_chauthtok_prelim_fail),
515 : cmocka_unit_test(test_pam_chauthtok_diff_authtoks),
516 : cmocka_unit_test(test_pam_authenticate_root),
517 : cmocka_unit_test_setup_teardown(test_pam_authenticate_root_ignore,
518 : setup_svc,
519 : teardown_svc),
520 : cmocka_unit_test_setup_teardown(test_pam_authenticate_domains,
521 : setup_svc,
522 : teardown_svc),
523 : cmocka_unit_test_setup_teardown(test_pam_authenticate_domains_err,
524 : setup_svc,
525 : teardown_svc),
526 : cmocka_unit_test_setup_teardown(test_pam_authenticate_retry,
527 : setup_svc,
528 : teardown_svc),
529 : cmocka_unit_test_setup_teardown(test_pam_authenticate_retry_neg,
530 : setup_svc,
531 : teardown_svc),
532 : cmocka_unit_test_setup_teardown(test_pam_authenticate_retry_eparse,
533 : setup_svc,
534 : teardown_svc),
535 : };
536 :
537 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
538 2 : debug_level = SSSDBG_INVALID;
539 :
540 2 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
541 2 : while((opt = poptGetNextOpt(pc)) != -1) {
542 : switch(opt) {
543 : default:
544 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
545 : poptBadOption(pc, 0), poptStrerror(opt));
546 0 : poptPrintUsage(pc, stderr, 0);
547 0 : return 1;
548 : }
549 : }
550 2 : poptFreeContext(pc);
551 :
552 2 : DEBUG_CLI_INIT(debug_level);
553 2 : tests_set_cwd();
554 :
555 2 : setenv("PAM_WRAPPER", "1", 1);
556 2 : return cmocka_run_group_tests(tests, NULL, NULL);
557 : }
|