Lines 32-38
Link Here
|
32 |
#include <sys/types.h> |
32 |
#include <sys/types.h> |
33 |
|
33 |
|
34 |
#include <stdarg.h> |
34 |
#include <stdarg.h> |
|
|
35 |
#include <stdio.h> |
35 |
#include <string.h> |
36 |
#include <string.h> |
|
|
37 |
#include <unistd.h> |
36 |
|
38 |
|
37 |
#include "xmalloc.h" |
39 |
#include "xmalloc.h" |
38 |
#include "key.h" |
40 |
#include "key.h" |
Lines 40-45
Link Here
|
40 |
#include "buffer.h" |
42 |
#include "buffer.h" |
41 |
#include "ssh-gss.h" |
43 |
#include "ssh-gss.h" |
42 |
|
44 |
|
|
|
45 |
extern Authctxt *the_authctxt; |
43 |
extern ServerOptions options; |
46 |
extern ServerOptions options; |
44 |
|
47 |
|
45 |
#ifdef HEIMDAL |
48 |
#ifdef HEIMDAL |
Lines 55-60
extern ServerOptions options;
Link Here
|
55 |
# include <gssapi/gssapi_krb5.h> |
59 |
# include <gssapi/gssapi_krb5.h> |
56 |
#endif |
60 |
#endif |
57 |
|
61 |
|
|
|
62 |
/* all commands are allowed by default */ |
63 |
char **k5users_allowed_cmds = NULL; |
64 |
|
65 |
static int ssh_gssapi_k5login_exists(); |
66 |
static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, |
67 |
int); |
68 |
|
58 |
static krb5_context krb_context = NULL; |
69 |
static krb5_context krb_context = NULL; |
59 |
|
70 |
|
60 |
/* Initialise the krb5 library, for the stuff that GSSAPI won't do */ |
71 |
/* Initialise the krb5 library, for the stuff that GSSAPI won't do */ |
Lines 87-92
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
Link Here
|
87 |
krb5_principal princ; |
98 |
krb5_principal princ; |
88 |
int retval; |
99 |
int retval; |
89 |
const char *errmsg; |
100 |
const char *errmsg; |
|
|
101 |
int k5login_exists; |
90 |
|
102 |
|
91 |
if (ssh_gssapi_krb5_init() == 0) |
103 |
if (ssh_gssapi_krb5_init() == 0) |
92 |
return 0; |
104 |
return 0; |
Lines 98-107
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
Link Here
|
98 |
krb5_free_error_message(krb_context, errmsg); |
110 |
krb5_free_error_message(krb_context, errmsg); |
99 |
return 0; |
111 |
return 0; |
100 |
} |
112 |
} |
101 |
if (krb5_kuserok(krb_context, princ, name)) { |
113 |
/* krb5_kuserok() returns 1 if .k5login DNE and this is self-login. |
|
|
114 |
* We have to make sure to check .k5users in that case. */ |
115 |
k5login_exists = ssh_gssapi_k5login_exists(); |
116 |
/* NOTE: .k5login and .k5users must opened as root, not the user, |
117 |
* because if they are on a krb5-protected filesystem, user credentials |
118 |
* to access these files aren't available yet. */ |
119 |
if (krb5_kuserok(krb_context, princ, name) && k5login_exists) { |
102 |
retval = 1; |
120 |
retval = 1; |
103 |
logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", |
121 |
logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", |
104 |
name, (char *)client->displayname.value); |
122 |
name, (char *)client->displayname.value); |
|
|
123 |
} else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value, |
124 |
name, k5login_exists)) { |
125 |
retval = 1; |
126 |
logit("Authorized to %s, krb5 principal %s " |
127 |
"(ssh_gssapi_krb5_cmdok)", |
128 |
name, (char *)client->displayname.value); |
105 |
} else |
129 |
} else |
106 |
retval = 0; |
130 |
retval = 0; |
107 |
|
131 |
|
Lines 109-114
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
Link Here
|
109 |
return retval; |
133 |
return retval; |
110 |
} |
134 |
} |
111 |
|
135 |
|
|
|
136 |
/* Test for existence of .k5login. |
137 |
* We need this as part of our .k5users check, because krb5_kuserok() |
138 |
* returns success if .k5login DNE and user is logging in as himself. |
139 |
* With .k5login absent and .k5users present, we don't want absence |
140 |
* of .k5login to authorize self-login. (absence of both is required) |
141 |
* Returns 1 if .k5login is available, 0 otherwise. |
142 |
*/ |
143 |
static int |
144 |
ssh_gssapi_k5login_exists() |
145 |
{ |
146 |
char file[MAXPATHLEN]; |
147 |
struct passwd *pw = the_authctxt->pw; |
148 |
|
149 |
snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir); |
150 |
return access(file, F_OK) == 0; |
151 |
} |
152 |
|
153 |
/* check .k5users for login or command authorization |
154 |
* Returns 1 if principal is authorized, 0 otherwise. |
155 |
* If principal is authorized, (global) k5users_allowed_cmds may be populated. |
156 |
*/ |
157 |
static int |
158 |
ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, |
159 |
const char *luser, int k5login_exists) |
160 |
{ |
161 |
FILE *fp; |
162 |
char file[MAXPATHLEN]; |
163 |
char line[BUFSIZ]; |
164 |
char kuser[65]; /* match krb5_kuserok() */ |
165 |
struct stat st; |
166 |
struct passwd *pw = the_authctxt->pw; |
167 |
int found_principal = 0; |
168 |
int ncommands = 0, allcommands = 0; |
169 |
u_long linenum; |
170 |
|
171 |
snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); |
172 |
/* If both .k5login and .k5users DNE, self-login is ok. */ |
173 |
if (!k5login_exists && (access(file, F_OK) == -1)) { |
174 |
return (krb5_aname_to_localname(krb_context, principal, |
175 |
sizeof(kuser), kuser) == 0) && |
176 |
(strcmp(kuser, luser) == 0); |
177 |
} |
178 |
if ((fp = fopen(file, "r")) == NULL) { |
179 |
int saved_errno = errno; |
180 |
/* 2nd access check to ease debugging if file perms are wrong. |
181 |
* But we don't want to report this if .k5users simply DNE. */ |
182 |
if (access(file, F_OK) == 0) { |
183 |
logit("User %s fopen %s failed: %s", |
184 |
pw->pw_name, file, strerror(saved_errno)); |
185 |
} |
186 |
return 0; |
187 |
} |
188 |
/* .k5users must be owned either by the user or by root */ |
189 |
if (fstat(fileno(fp), &st) == -1) { |
190 |
/* can happen, but very wierd error so report it */ |
191 |
logit("User %s fstat %s failed: %s", |
192 |
pw->pw_name, file, strerror(errno)); |
193 |
fclose(fp); |
194 |
return 0; |
195 |
} |
196 |
if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) { |
197 |
logit("User %s %s is not owned by root or user", |
198 |
pw->pw_name, file); |
199 |
fclose(fp); |
200 |
return 0; |
201 |
} |
202 |
/* .k5users must be a regular file. krb5_kuserok() doesn't do this |
203 |
* check, but we don't want to be deficient if they add a check. */ |
204 |
if (!S_ISREG(st.st_mode)) { |
205 |
logit("User %s %s is not a regular file", pw->pw_name, file); |
206 |
fclose(fp); |
207 |
return 0; |
208 |
} |
209 |
/* file exists; initialize k5users_allowed_cmds (to none!) */ |
210 |
k5users_allowed_cmds = xcalloc(++ncommands, |
211 |
sizeof(*k5users_allowed_cmds)); |
212 |
|
213 |
/* Check each line. ksu allows unlimited length lines. We don't. */ |
214 |
while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line), |
215 |
&linenum) != -1) { |
216 |
char *token; |
217 |
|
218 |
/* we parse just like ksu, even though we could do better */ |
219 |
if ((token = strtok(line, " \t\n")) == NULL) |
220 |
continue; |
221 |
if (strcmp(name, token) == 0) { |
222 |
/* we matched on client principal */ |
223 |
found_principal = 1; |
224 |
if ((token = strtok(NULL, " \t\n")) == NULL) { |
225 |
/* only shell is allowed */ |
226 |
k5users_allowed_cmds[ncommands-1] = |
227 |
xstrdup(pw->pw_shell); |
228 |
k5users_allowed_cmds = |
229 |
xreallocarray(k5users_allowed_cmds, ++ncommands, |
230 |
sizeof(*k5users_allowed_cmds)); |
231 |
break; |
232 |
} |
233 |
/* process the allowed commands */ |
234 |
while (token) { |
235 |
if (strcmp(token, "*") == 0) { |
236 |
allcommands = 1; |
237 |
break; |
238 |
} |
239 |
k5users_allowed_cmds[ncommands-1] = |
240 |
xstrdup(token); |
241 |
k5users_allowed_cmds = |
242 |
xreallocarray(k5users_allowed_cmds, ++ncommands, |
243 |
sizeof(*k5users_allowed_cmds)); |
244 |
token = strtok(NULL, " \t\n"); |
245 |
} |
246 |
} |
247 |
} |
248 |
if (k5users_allowed_cmds) { |
249 |
/* terminate vector */ |
250 |
k5users_allowed_cmds[ncommands-1] = NULL; |
251 |
/* if all commands are allowed, free vector */ |
252 |
if (allcommands) { |
253 |
int i; |
254 |
for (i = 0; i < ncommands; i++) { |
255 |
free(k5users_allowed_cmds[i]); |
256 |
} |
257 |
free(k5users_allowed_cmds); |
258 |
k5users_allowed_cmds = NULL; |
259 |
} |
260 |
} |
261 |
fclose(fp); |
262 |
return found_principal; |
263 |
} |
264 |
|
112 |
|
265 |
|
113 |
/* This writes out any forwarded credentials from the structure populated |
266 |
/* This writes out any forwarded credentials from the structure populated |
114 |
* during userauth. Called after we have setuid to the user */ |
267 |
* during userauth. Called after we have setuid to the user */ |