xref: /freebsd/contrib/pam-krb5/tests/fakepam/kuserok.c (revision df21a004be237a1dccd03c7b47254625eea62fa9)
1 /*
2  * Replacement for krb5_kuserok for testing.
3  *
4  * This is a reimplementation of krb5_kuserok that uses the replacement
5  * getpwnam function and the special passwd struct internal to the fake PAM
6  * module to locate .k5login.  The default Kerberos krb5_kuserok always calls
7  * the system getpwnam, which we may not be able to intercept, and will
8  * therefore fail because it can't locate the .k5login file for the test user
9  * (or succeed oddly because it finds some random file on the testing system).
10  *
11  * This implementation is drastically simplified from the Kerberos library
12  * version, and much less secure (which shouldn't matter since it's only
13  * acting on test data).
14  *
15  * This is an optional part of the fake PAM library and can be omitted when
16  * testing modules that don't use Kerberos.
17  *
18  * The canonical version of this file is maintained in the rra-c-util package,
19  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
20  *
21  * Written by Russ Allbery <eagle@eyrie.org>
22  * Copyright 2011
23  *     The Board of Trustees of the Leland Stanford Junior University
24  *
25  * Permission is hereby granted, free of charge, to any person obtaining a
26  * copy of this software and associated documentation files (the "Software"),
27  * to deal in the Software without restriction, including without limitation
28  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29  * and/or sell copies of the Software, and to permit persons to whom the
30  * Software is furnished to do so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice shall be included in
33  * all copies or substantial portions of the Software.
34  *
35  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
38  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
40  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
41  * DEALINGS IN THE SOFTWARE.
42  *
43  * SPDX-License-Identifier: MIT
44  */
45 
46 #include <config.h>
47 #include <portable/krb5.h>
48 #include <portable/pam.h>
49 #include <portable/system.h>
50 
51 #include <pwd.h>
52 
53 #include <tests/fakepam/pam.h>
54 #include <tests/tap/string.h>
55 
56 
57 /*
58  * Given a Kerberos principal representing the authenticated identity and the
59  * username of the local account, return true if that principal is authorized
60  * to log on to that account.  The principal is authorized if the .k5login
61  * file does not exist and the user matches the localname form of the
62  * principal, or if the file does exist and the principal is listed in it.
63  *
64  * This version retrieves the home directory from the internal fake PAM
65  * library path.
66  */
67 krb5_boolean
68 krb5_kuserok(krb5_context ctx, krb5_principal princ, const char *user)
69 {
70     char *principal, *path;
71     struct passwd *pwd;
72     FILE *file;
73     krb5_error_code code;
74     char buffer[BUFSIZ];
75     bool found = false;
76 #ifdef HAVE_PAM_MODUTIL_GETPWNAM
77     struct pam_handle pamh;
78 #endif
79 
80     /*
81      * Find .k5login and confirm if it exists.  If it doesn't, fall back on
82      * krb5_aname_to_localname.
83      */
84 #ifdef HAVE_PAM_MODUTIL_GETPWNAM
85     memset(&pamh, 0, sizeof(pamh));
86     pwd = pam_modutil_getpwnam(&pamh, user);
87 #else
88     pwd = getpwnam(user);
89 #endif
90     if (pwd == NULL)
91         return false;
92     basprintf(&path, "%s/.k5login", pwd->pw_dir);
93     if (access(path, R_OK) < 0) {
94         free(path);
95         code = krb5_aname_to_localname(ctx, princ, sizeof(buffer), buffer);
96         return (code == 0 && strcmp(buffer, user) == 0);
97     }
98     file = fopen(path, "r");
99     if (file == NULL) {
100         free(path);
101         return false;
102     }
103     free(path);
104 
105     /* .k5login exists.  Scan it for the principal. */
106     if (krb5_unparse_name(ctx, princ, &principal) != 0) {
107         fclose(file);
108         return false;
109     }
110     while (!found && (fgets(buffer, sizeof(buffer), file) != NULL)) {
111         if (buffer[strlen(buffer) - 1] == '\n')
112             buffer[strlen(buffer) - 1] = '\0';
113         if (strcmp(buffer, principal) == 0)
114             found = true;
115     }
116     fclose(file);
117     krb5_free_unparsed_name(ctx, principal);
118     return found;
119 }
120