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(&params, 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                                     &params, 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