1*bf6873c5SCy Schubert /*
2*bf6873c5SCy Schubert * Tests for the pam-krb5 module with an expired password.
3*bf6873c5SCy Schubert *
4*bf6873c5SCy Schubert * This test case checks correct handling of an account whose password has
5*bf6873c5SCy Schubert * expired and the multiple different paths the module can take for handling
6*bf6873c5SCy Schubert * that case.
7*bf6873c5SCy Schubert *
8*bf6873c5SCy Schubert * Written by Russ Allbery <eagle@eyrie.org>
9*bf6873c5SCy Schubert * Copyright 2020 Russ Allbery <eagle@eyrie.org>
10*bf6873c5SCy Schubert * Copyright 2011-2012
11*bf6873c5SCy Schubert * The Board of Trustees of the Leland Stanford Junior University
12*bf6873c5SCy Schubert *
13*bf6873c5SCy Schubert * SPDX-License-Identifier: BSD-3-clause or GPL-1+
14*bf6873c5SCy Schubert */
15*bf6873c5SCy Schubert
16*bf6873c5SCy Schubert #include <config.h>
17*bf6873c5SCy Schubert #include <portable/system.h>
18*bf6873c5SCy Schubert
19*bf6873c5SCy Schubert #include <pwd.h>
20*bf6873c5SCy Schubert #include <time.h>
21*bf6873c5SCy Schubert
22*bf6873c5SCy Schubert #include <tests/fakepam/pam.h>
23*bf6873c5SCy Schubert #include <tests/fakepam/script.h>
24*bf6873c5SCy Schubert #include <tests/tap/basic.h>
25*bf6873c5SCy Schubert #include <tests/tap/kadmin.h>
26*bf6873c5SCy Schubert #include <tests/tap/kerberos.h>
27*bf6873c5SCy Schubert #include <tests/tap/process.h>
28*bf6873c5SCy Schubert #include <tests/tap/string.h>
29*bf6873c5SCy Schubert
30*bf6873c5SCy Schubert
31*bf6873c5SCy Schubert int
main(void)32*bf6873c5SCy Schubert main(void)
33*bf6873c5SCy Schubert {
34*bf6873c5SCy Schubert struct script_config config;
35*bf6873c5SCy Schubert struct kerberos_config *krbconf;
36*bf6873c5SCy Schubert char *newpass, *date;
37*bf6873c5SCy Schubert struct passwd pwd;
38*bf6873c5SCy Schubert time_t now;
39*bf6873c5SCy Schubert
40*bf6873c5SCy Schubert /* Load the Kerberos principal and password from a file. */
41*bf6873c5SCy Schubert krbconf = kerberos_setup(TAP_KRB_NEEDS_PASSWORD);
42*bf6873c5SCy Schubert memset(&config, 0, sizeof(config));
43*bf6873c5SCy Schubert config.user = krbconf->username;
44*bf6873c5SCy Schubert config.password = krbconf->password;
45*bf6873c5SCy Schubert config.extra[0] = krbconf->userprinc;
46*bf6873c5SCy Schubert
47*bf6873c5SCy Schubert /*
48*bf6873c5SCy Schubert * Ensure we can expire the password. Heimdal has a prompt for the
49*bf6873c5SCy Schubert * expiration time, so save that to use as a substitution in the script.
50*bf6873c5SCy Schubert */
51*bf6873c5SCy Schubert now = time(NULL) - 1;
52*bf6873c5SCy Schubert if (!kerberos_expire_password(krbconf->userprinc, now))
53*bf6873c5SCy Schubert skip_all("kadmin not configured or kadmin mismatch");
54*bf6873c5SCy Schubert date = bstrdup(ctime(&now));
55*bf6873c5SCy Schubert date[strlen(date) - 1] = '\0';
56*bf6873c5SCy Schubert config.extra[1] = date;
57*bf6873c5SCy Schubert
58*bf6873c5SCy Schubert /* Generate a testing krb5.conf file. */
59*bf6873c5SCy Schubert kerberos_generate_conf(krbconf->realm);
60*bf6873c5SCy Schubert
61*bf6873c5SCy Schubert /* Create a fake passwd struct for our user. */
62*bf6873c5SCy Schubert memset(&pwd, 0, sizeof(pwd));
63*bf6873c5SCy Schubert pwd.pw_name = krbconf->username;
64*bf6873c5SCy Schubert pwd.pw_uid = getuid();
65*bf6873c5SCy Schubert pwd.pw_gid = getgid();
66*bf6873c5SCy Schubert basprintf(&pwd.pw_dir, "%s/tmp", getenv("BUILD"));
67*bf6873c5SCy Schubert pam_set_pwd(&pwd);
68*bf6873c5SCy Schubert
69*bf6873c5SCy Schubert /*
70*bf6873c5SCy Schubert * We'll be changing the password to something new. This needs to be
71*bf6873c5SCy Schubert * sufficiently random that it's unlikely to fall afoul of password
72*bf6873c5SCy Schubert * strength checking.
73*bf6873c5SCy Schubert */
74*bf6873c5SCy Schubert basprintf(&newpass, "ngh1,a%lu nn9af6", (unsigned long) getpid());
75*bf6873c5SCy Schubert config.newpass = newpass;
76*bf6873c5SCy Schubert
77*bf6873c5SCy Schubert plan_lazy();
78*bf6873c5SCy Schubert
79*bf6873c5SCy Schubert /*
80*bf6873c5SCy Schubert * Default behavior. We have to distinguish between two versions of
81*bf6873c5SCy Schubert * Heimdal for testing because the prompts changed substantially. Use the
82*bf6873c5SCy Schubert * existence of krb5_principal_set_comp_string to distinguish because it
83*bf6873c5SCy Schubert * was introduced at the same time.
84*bf6873c5SCy Schubert */
85*bf6873c5SCy Schubert #ifdef HAVE_KRB5_HEIMDAL
86*bf6873c5SCy Schubert # ifdef HAVE_KRB5_PRINCIPAL_SET_COMP_STRING
87*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal", &config);
88*bf6873c5SCy Schubert config.newpass = krbconf->password;
89*bf6873c5SCy Schubert config.password = newpass;
90*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
91*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal-debug", &config);
92*bf6873c5SCy Schubert # else
93*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal-old", &config);
94*bf6873c5SCy Schubert config.newpass = krbconf->password;
95*bf6873c5SCy Schubert config.password = newpass;
96*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
97*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal-old-debug", &config);
98*bf6873c5SCy Schubert # endif
99*bf6873c5SCy Schubert #else
100*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-mit", &config);
101*bf6873c5SCy Schubert config.newpass = krbconf->password;
102*bf6873c5SCy Schubert config.password = newpass;
103*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
104*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-mit-debug", &config);
105*bf6873c5SCy Schubert #endif
106*bf6873c5SCy Schubert
107*bf6873c5SCy Schubert /* Test again with PAM_SILENT, specified two ways. */
108*bf6873c5SCy Schubert #ifdef HAVE_KRB5_HEIMDAL
109*bf6873c5SCy Schubert config.newpass = newpass;
110*bf6873c5SCy Schubert config.password = krbconf->password;
111*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
112*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal-silent", &config);
113*bf6873c5SCy Schubert config.newpass = krbconf->password;
114*bf6873c5SCy Schubert config.password = newpass;
115*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
116*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-heimdal-flag-silent", &config);
117*bf6873c5SCy Schubert #else
118*bf6873c5SCy Schubert config.newpass = newpass;
119*bf6873c5SCy Schubert config.password = krbconf->password;
120*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
121*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-mit-silent", &config);
122*bf6873c5SCy Schubert config.newpass = krbconf->password;
123*bf6873c5SCy Schubert config.password = newpass;
124*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
125*bf6873c5SCy Schubert run_script("data/scripts/expired/basic-mit-flag-silent", &config);
126*bf6873c5SCy Schubert #endif
127*bf6873c5SCy Schubert
128*bf6873c5SCy Schubert /*
129*bf6873c5SCy Schubert * We can only run the remaining checks if we can suppress the Kerberos
130*bf6873c5SCy Schubert * library behavior of prompting for a new password when the password has
131*bf6873c5SCy Schubert * expired.
132*bf6873c5SCy Schubert */
133*bf6873c5SCy Schubert #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT
134*bf6873c5SCy Schubert
135*bf6873c5SCy Schubert /* Check the forced failure behavior. */
136*bf6873c5SCy Schubert run_script("data/scripts/expired/fail", &config);
137*bf6873c5SCy Schubert run_script("data/scripts/expired/fail-debug", &config);
138*bf6873c5SCy Schubert
139*bf6873c5SCy Schubert /*
140*bf6873c5SCy Schubert * Defer the error to the account management check.
141*bf6873c5SCy Schubert *
142*bf6873c5SCy Schubert * Skip this check on Heimdal currently (Heimdal 7.4.0) because its
143*bf6873c5SCy Schubert * implementation of krb5_get_init_creds_opt_set_change_password_prompt is
144*bf6873c5SCy Schubert * incomplete. See <https://github.com/heimdal/heimdal/issues/322>.
145*bf6873c5SCy Schubert */
146*bf6873c5SCy Schubert # ifdef HAVE_KRB5_HEIMDAL
147*bf6873c5SCy Schubert skip_block(2, "deferring password changes broken in Heimdal");
148*bf6873c5SCy Schubert # else
149*bf6873c5SCy Schubert config.newpass = newpass;
150*bf6873c5SCy Schubert config.password = krbconf->password;
151*bf6873c5SCy Schubert config.authtok = krbconf->password;
152*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
153*bf6873c5SCy Schubert run_script("data/scripts/expired/defer-mit", &config);
154*bf6873c5SCy Schubert config.newpass = krbconf->password;
155*bf6873c5SCy Schubert config.password = newpass;
156*bf6873c5SCy Schubert config.authtok = newpass;
157*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, now);
158*bf6873c5SCy Schubert run_script("data/scripts/expired/defer-mit-debug", &config);
159*bf6873c5SCy Schubert # endif
160*bf6873c5SCy Schubert
161*bf6873c5SCy Schubert #else /* !HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT */
162*bf6873c5SCy Schubert
163*bf6873c5SCy Schubert /* Mention that we skipped something for the record. */
164*bf6873c5SCy Schubert skip_block(4, "cannot disable library password prompting");
165*bf6873c5SCy Schubert
166*bf6873c5SCy Schubert #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT */
167*bf6873c5SCy Schubert
168*bf6873c5SCy Schubert /* In case we ran into some error, try to unexpire the password. */
169*bf6873c5SCy Schubert kerberos_expire_password(krbconf->userprinc, 0);
170*bf6873c5SCy Schubert
171*bf6873c5SCy Schubert free(date);
172*bf6873c5SCy Schubert free(newpass);
173*bf6873c5SCy Schubert free(pwd.pw_dir);
174*bf6873c5SCy Schubert return 0;
175*bf6873c5SCy Schubert }
176