1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/os/localauth_k5login.c - k5login localauth module */
3 /*
4 * Copyright (C) 1990,1993,2007,2013 by the Massachusetts Institute
5 * of Technology. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "k5-int.h"
34 #include "os-proto.h"
35 #include <krb5/localauth_plugin.h>
36
37 #if !defined(_WIN32) /* Not yet for Windows */
38 #include <pwd.h>
39
40 #if defined(__APPLE__) && defined(__MACH__)
41 #include <hfs/hfs_mount.h>
42 #define FILE_OWNER_OK(UID) ((UID) == 0 || (UID) == UNKNOWNUID)
43 #else
44 #define FILE_OWNER_OK(UID) ((UID) == 0)
45 #endif
46
47 /*
48 * Find the k5login filename for luser, either in the user's homedir or in a
49 * configured directory under the username.
50 */
51 static krb5_error_code
get_k5login_filename(krb5_context context,const char * lname,const char * homedir,char ** filename_out)52 get_k5login_filename(krb5_context context, const char *lname,
53 const char *homedir, char **filename_out)
54 {
55 krb5_error_code ret;
56 char *dir, *filename;
57
58 *filename_out = NULL;
59 ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
60 KRB5_CONF_K5LOGIN_DIRECTORY, NULL, NULL, &dir);
61 if (ret != 0)
62 return ret;
63
64 if (dir == NULL) {
65 /* Look in the user's homedir. */
66 if (asprintf(&filename, "%s/.k5login", homedir) < 0)
67 return ENOMEM;
68 } else {
69 /* Look in the configured directory. */
70 if (asprintf(&filename, "%s/%s", dir, lname) < 0)
71 ret = ENOMEM;
72 profile_release_string(dir);
73 if (ret)
74 return ret;
75 }
76 *filename_out = filename;
77 return 0;
78 }
79
80 /* Determine whether aname is authorized to log in as lname according to the
81 * user's k5login file. */
82 static krb5_error_code
userok_k5login(krb5_context context,krb5_localauth_moddata data,krb5_const_principal aname,const char * lname)83 userok_k5login(krb5_context context, krb5_localauth_moddata data,
84 krb5_const_principal aname, const char *lname)
85 {
86 krb5_error_code ret;
87 int authoritative = TRUE, gobble;
88 char *filename = NULL, *princname = NULL;
89 char *newline, linebuf[BUFSIZ], pwbuf[BUFSIZ];
90 struct stat sbuf;
91 struct passwd pwx, *pwd;
92 FILE *fp = NULL;
93
94 ret = profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
95 KRB5_CONF_K5LOGIN_AUTHORITATIVE, NULL, TRUE,
96 &authoritative);
97 if (ret)
98 goto cleanup;
99
100 /* Get the local user's .k5login filename. */
101 ret = k5_getpwnam_r(lname, &pwx, pwbuf, sizeof(pwbuf), &pwd);
102 if (ret) {
103 ret = EPERM;
104 goto cleanup;
105 }
106 ret = get_k5login_filename(context, lname, pwd->pw_dir, &filename);
107 if (ret)
108 goto cleanup;
109
110 if (access(filename, F_OK) != 0) {
111 ret = KRB5_PLUGIN_NO_HANDLE;
112 goto cleanup;
113 }
114
115 ret = krb5_unparse_name(context, aname, &princname);
116 if (ret)
117 goto cleanup;
118
119 fp = fopen(filename, "r");
120 if (fp == NULL) {
121 ret = errno;
122 goto cleanup;
123 }
124 set_cloexec_file(fp);
125
126 /* For security reasons, the .k5login file must be owned either by
127 * the user or by root. */
128 if (fstat(fileno(fp), &sbuf)) {
129 ret = errno;
130 goto cleanup;
131 }
132 if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) {
133 ret = EPERM;
134 goto cleanup;
135 }
136
137 /* Check each line. */
138 while (fgets(linebuf, sizeof(linebuf), fp) != NULL) {
139 newline = strrchr(linebuf, '\n');
140 if (newline != NULL)
141 *newline = '\0';
142 if (strcmp(linebuf, princname) == 0) {
143 ret = 0;
144 goto cleanup;
145 }
146 /* Clean up the rest of the line if necessary. */
147 if (newline == NULL)
148 while ((gobble = getc(fp)) != EOF && gobble != '\n');
149 }
150
151 /* We didn't find it. */
152 ret = EPERM;
153
154 cleanup:
155 free(princname);
156 free(filename);
157 if (fp != NULL)
158 fclose(fp);
159 /* If k5login files are non-authoritative, never reject. */
160 return (!authoritative && ret) ? KRB5_PLUGIN_NO_HANDLE : ret;
161 }
162
163 #else /* _WIN32 */
164
165 static krb5_error_code
userok_k5login(krb5_context context,krb5_localauth_moddata data,krb5_const_principal aname,const char * lname)166 userok_k5login(krb5_context context, krb5_localauth_moddata data,
167 krb5_const_principal aname, const char *lname)
168 {
169 return KRB5_PLUGIN_NO_HANDLE;
170 }
171
172 #endif
173
174 krb5_error_code
localauth_k5login_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)175 localauth_k5login_initvt(krb5_context context, int maj_ver, int min_ver,
176 krb5_plugin_vtable vtable)
177 {
178 krb5_localauth_vtable vt = (krb5_localauth_vtable)vtable;
179
180 vt->name = "k5login";
181 vt->userok = userok_k5login;
182 return 0;
183 }
184