1 /*
2 * Kerberos test setup requiring the kadmin API.
3 *
4 * This file collects Kerberos test setup functions that use the kadmin API to
5 * put principals into particular configurations for testing. Currently, the
6 * only implemented functionality is to mark a password as expired.
7 *
8 * The canonical version of this file is maintained in the rra-c-util package,
9 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
10 *
11 * Written by Russ Allbery <eagle@eyrie.org>
12 * Copyright 2017 Russ Allbery <eagle@eyrie.org>
13 * Copyright 2011
14 * The Board of Trustees of the Leland Stanford Junior University
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice shall be included in
24 * all copies or substantial portions of the Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 * DEALINGS IN THE SOFTWARE.
33 *
34 * SPDX-License-Identifier: MIT
35 */
36
37 #include <config.h>
38 #ifdef HAVE_KADM5CLNT
39 # include <portable/kadmin.h>
40 # include <portable/krb5.h>
41 #endif
42 #include <portable/system.h>
43
44 #include <time.h>
45
46 #include <tests/tap/basic.h>
47 #include <tests/tap/kadmin.h>
48 #include <tests/tap/kerberos.h>
49
50 /* Used for unused parameters to silence gcc warnings. */
51 #define UNUSED __attribute__((__unused__))
52
53
54 /*
55 * Given the principal to set an expiration on, set that principal to have an
56 * expired password. This requires that the realm admin server be configured
57 * either in DNS (with SRV records) or in krb5.conf (possibly the one
58 * KRB5_CONFIG is pointing to). Authentication is done using the keytab
59 * stored in config/admin-keytab.
60 *
61 * Returns true on success. Returns false if necessary configuration is
62 * missing so that the caller can choose whether to call bail or skip_all. If
63 * the configuration is present but the operation fails, bails.
64 */
65 #ifdef HAVE_KADM5CLNT
66 bool
kerberos_expire_password(const char * principal,time_t expires)67 kerberos_expire_password(const char *principal, time_t expires)
68 {
69 char *path, *user;
70 const char *realm;
71 krb5_context ctx;
72 krb5_principal admin = NULL;
73 krb5_principal princ = NULL;
74 kadm5_ret_t code;
75 kadm5_config_params params;
76 kadm5_principal_ent_rec ent;
77 void *handle;
78 bool okay = false;
79
80 /* Set up for making our call. */
81 path = test_file_path("config/admin-keytab");
82 if (path == NULL)
83 return false;
84 code = krb5_init_context(&ctx);
85 if (code != 0)
86 bail_krb5(ctx, code, "error initializing Kerberos");
87 admin = kerberos_keytab_principal(ctx, path);
88 realm = krb5_principal_get_realm(ctx, admin);
89 code = krb5_set_default_realm(ctx, realm);
90 if (code != 0)
91 bail_krb5(ctx, code, "cannot set default realm");
92 code = krb5_unparse_name(ctx, admin, &user);
93 if (code != 0)
94 bail_krb5(ctx, code, "cannot unparse admin principal");
95 code = krb5_parse_name(ctx, principal, &princ);
96 if (code != 0)
97 bail_krb5(ctx, code, "cannot parse principal %s", principal);
98
99 /*
100 * If the actual kadmin calls fail, we may be built with MIT Kerberos
101 * against a Heimdal server or vice versa. Return false to skip the
102 * tests.
103 */
104 memset(¶ms, 0, sizeof(params));
105 params.realm = (char *) realm;
106 params.mask = KADM5_CONFIG_REALM;
107 code = kadm5_init_with_skey_ctx(ctx, user, path, KADM5_ADMIN_SERVICE,
108 ¶ms, KADM5_STRUCT_VERSION,
109 KADM5_API_VERSION, &handle);
110 if (code != 0) {
111 diag_krb5(ctx, code, "error initializing kadmin");
112 goto done;
113 }
114 memset(&ent, 0, sizeof(ent));
115 ent.principal = princ;
116 ent.pw_expiration = (krb5_timestamp) expires;
117 code = kadm5_modify_principal(handle, &ent, KADM5_PW_EXPIRATION);
118 if (code == 0)
119 okay = true;
120 else
121 diag_krb5(ctx, code, "error setting password expiration");
122
123 done:
124 kadm5_destroy(handle);
125 krb5_free_unparsed_name(ctx, user);
126 krb5_free_principal(ctx, admin);
127 krb5_free_principal(ctx, princ);
128 krb5_free_context(ctx);
129 test_file_path_free(path);
130 return okay;
131 }
132 #else /* !HAVE_KADM5CLNT */
133 bool
kerberos_expire_password(const char * principal UNUSED,time_t expires UNUSED)134 kerberos_expire_password(const char *principal UNUSED, time_t expires UNUSED)
135 {
136 return false;
137 }
138 #endif /* !HAVE_KADM5CLNT */
139