1 /*
2 * Authentication tests for the pam-krb5 module with ticket cache.
3 *
4 * This test case includes all tests that require Kerberos to be configured, a
5 * username and password available, and a ticket cache created, but with the
6 * PAM module running as the same user for which the ticket cache will be
7 * created (so without setuid and with chown doing nothing).
8 *
9 * Written by Russ Allbery <eagle@eyrie.org>
10 * Copyright 2020 Russ Allbery <eagle@eyrie.org>
11 * Copyright 2011-2012, 2014
12 * The Board of Trustees of the Leland Stanford Junior University
13 *
14 * SPDX-License-Identifier: BSD-3-clause or GPL-1+
15 */
16
17 #include <config.h>
18 #include <portable/krb5.h>
19 #include <portable/pam.h>
20 #include <portable/system.h>
21
22 #include <pwd.h>
23 #include <sys/stat.h>
24 #include <time.h>
25
26 #include <tests/fakepam/pam.h>
27 #include <tests/fakepam/script.h>
28 #include <tests/tap/basic.h>
29 #include <tests/tap/kerberos.h>
30 #include <tests/tap/macros.h>
31 #include <tests/tap/process.h>
32 #include <tests/tap/string.h>
33
34
35 static void
check_authtok(pam_handle_t * pamh,const struct script_config * config,void * data UNUSED)36 check_authtok(pam_handle_t *pamh, const struct script_config *config,
37 void *data UNUSED)
38 {
39 int retval;
40 const char *authtok;
41
42 retval = pam_get_item(pamh, PAM_AUTHTOK, (PAM_CONST void **) &authtok);
43 is_int(PAM_SUCCESS, retval, "Found PAM_AUTHTOK");
44 is_string(config->newpass, authtok, "...and it is correct");
45 }
46
47
48 int
main(void)49 main(void)
50 {
51 struct script_config config;
52 struct kerberos_config *krbconf;
53 char *newpass;
54
55 /* Load the Kerberos principal and password from a file. */
56 krbconf = kerberos_setup(TAP_KRB_NEEDS_PASSWORD);
57 memset(&config, 0, sizeof(config));
58 config.user = krbconf->username;
59 config.password = krbconf->password;
60 config.extra[0] = krbconf->userprinc;
61
62 /* Generate a testing krb5.conf file. */
63 kerberos_generate_conf(krbconf->realm);
64
65 plan_lazy();
66
67 /*
68 * First test trying to change the password to something that's
69 * excessively long.
70 */
71 newpass = bcalloc_type(PAM_MAX_RESP_SIZE + 1, char);
72 memset(newpass, 'a', PAM_MAX_RESP_SIZE);
73 config.newpass = newpass;
74 run_script("data/scripts/password/too-long", &config);
75 run_script("data/scripts/password/too-long-debug", &config);
76
77 /* Test use_authtok with an excessively long password. */
78 config.newpass = NULL;
79 config.authtok = newpass;
80 run_script("data/scripts/password/authtok-too-long", &config);
81 run_script("data/scripts/password/authtok-too-long-debug", &config);
82
83 /*
84 * Change the password to something new. This needs to be sufficiently
85 * random that it's unlikely to fall afoul of password strength checking.
86 */
87 free(newpass);
88 config.authtok = NULL;
89 basprintf(&newpass, "ngh1,a%lu nn9af6%lu", (unsigned long) getpid(),
90 (unsigned long) time(NULL));
91 config.newpass = newpass;
92 run_script("data/scripts/password/basic", &config);
93 config.password = newpass;
94 config.newpass = krbconf->password;
95 run_script("data/scripts/password/basic-debug", &config);
96
97 /* Test prompt_principal with password change. */
98 config.password = krbconf->password;
99 config.newpass = newpass;
100 run_script("data/scripts/password/prompt-principal", &config);
101
102 /* Change the password back and test expose-account. */
103 config.password = newpass;
104 config.newpass = krbconf->password;
105 run_script("data/scripts/password/expose", &config);
106
107 /*
108 * Test two banner settings by changing the password and then changing it
109 * back again.
110 */
111 config.password = krbconf->password;
112 config.newpass = newpass;
113 run_script("data/scripts/password/banner", &config);
114 config.password = newpass;
115 config.newpass = krbconf->password;
116 run_script("data/scripts/password/no-banner", &config);
117
118 /* Do the same, but with expose_account set as well. */
119 config.password = krbconf->password;
120 config.newpass = newpass;
121 run_script("data/scripts/password/banner-expose", &config);
122 config.password = newpass;
123 config.newpass = krbconf->password;
124 run_script("data/scripts/password/no-banner-expose", &config);
125
126 /* Test use_authtok. */
127 config.password = krbconf->password;
128 config.newpass = NULL;
129 config.authtok = newpass;
130 run_script("data/scripts/password/authtok", &config);
131
132 /* Test use_authtok with force_first_pass. */
133 config.password = NULL;
134 config.authtok = krbconf->password;
135 config.oldauthtok = newpass;
136 run_script("data/scripts/password/authtok-force", &config);
137
138 /*
139 * Ensure PAM_AUTHTOK and PAM_OLDAUTHTOK are set even if the user is
140 * ignored.
141 */
142 config.user = "root";
143 config.authtok = NULL;
144 config.oldauthtok = NULL;
145 config.password = "old-password";
146 config.newpass = "new-password";
147 config.callback = check_authtok;
148 run_script("data/scripts/password/ignore", &config);
149
150 free(newpass);
151 return 0;
152 }
153