xref: /freebsd/contrib/pam-krb5/tests/module/password-t.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
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
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
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