]>
Commit | Line | Data |
---|---|---|
9d8fd3ad SS |
1 | diff -up openssh-5.8p2/gss-serv-krb5.c.force_krb openssh-5.8p2/gss-serv-krb5.c |
2 | --- openssh-5.8p2/gss-serv-krb5.c.force_krb 2006-09-01 07:38:36.000000000 +0200 | |
3 | +++ openssh-5.8p2/gss-serv-krb5.c 2011-05-19 03:41:45.801109545 +0200 | |
4 | @@ -32,7 +32,9 @@ | |
5 | #include <sys/types.h> | |
6 | ||
7 | #include <stdarg.h> | |
8 | +#include <stdio.h> | |
9 | #include <string.h> | |
10 | +#include <unistd.h> | |
11 | ||
12 | #include "xmalloc.h" | |
13 | #include "key.h" | |
14 | @@ -40,12 +42,11 @@ | |
15 | #include "auth.h" | |
16 | #include "log.h" | |
17 | #include "servconf.h" | |
18 | +#include "misc.h" | |
19 | ||
20 | #include "buffer.h" | |
21 | #include "ssh-gss.h" | |
22 | ||
23 | -extern ServerOptions options; | |
24 | - | |
25 | #ifdef HEIMDAL | |
26 | # include <krb5.h> | |
27 | #else | |
28 | @@ -56,6 +57,16 @@ extern ServerOptions options; | |
29 | # endif | |
30 | #endif | |
31 | ||
32 | +extern Authctxt *the_authctxt; | |
33 | +extern ServerOptions options; | |
34 | + | |
35 | +/* all commands are allowed by default */ | |
36 | +char **k5users_allowed_cmds = NULL; | |
37 | + | |
38 | +static int ssh_gssapi_k5login_exists(); | |
39 | +static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, | |
40 | + int); | |
41 | + | |
42 | static krb5_context krb_context = NULL; | |
43 | ||
44 | /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ | |
45 | @@ -83,10 +94,11 @@ ssh_gssapi_krb5_init(void) | |
46 | */ | |
47 | ||
48 | static int | |
49 | -ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) | |
50 | +ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *luser) | |
51 | { | |
52 | krb5_principal princ; | |
53 | int retval; | |
54 | + int k5login_exists; | |
55 | ||
56 | if (ssh_gssapi_krb5_init() == 0) | |
57 | return 0; | |
58 | @@ -97,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client | |
59 | krb5_get_err_text(krb_context, retval)); | |
60 | return 0; | |
61 | } | |
62 | - if (krb5_kuserok(krb_context, princ, name)) { | |
63 | + /* krb5_kuserok() returns 1 if .k5login DNE and this is self-login. | |
64 | + * We have to make sure to check .k5users in that case. */ | |
65 | + k5login_exists = ssh_gssapi_k5login_exists(); | |
66 | + /* NOTE: .k5login and .k5users must opened as root, not the user, | |
67 | + * because if they are on a krb5-protected filesystem, user credentials | |
68 | + * to access these files aren't available yet. */ | |
69 | + if (krb5_kuserok(krb_context, princ, luser) && k5login_exists) { | |
70 | retval = 1; | |
71 | logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", | |
72 | - name, (char *)client->displayname.value); | |
73 | + luser, (char *)client->displayname.value); | |
74 | + } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value, | |
75 | + luser, k5login_exists)) { | |
76 | + retval = 1; | |
77 | + logit("Authorized to %s, krb5 principal %s " | |
78 | + "(ssh_gssapi_krb5_cmdok)", | |
79 | + luser, (char *)client->displayname.value); | |
80 | } else | |
81 | retval = 0; | |
82 | ||
83 | @@ -108,6 +132,134 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client | |
84 | return retval; | |
85 | } | |
86 | ||
87 | +/* Test for existence of .k5login. | |
88 | + * We need this as part of our .k5users check, because krb5_kuserok() | |
89 | + * returns success if .k5login DNE and user is logging in as himself. | |
90 | + * With .k5login absent and .k5users present, we don't want absence | |
91 | + * of .k5login to authorize self-login. (absence of both is required) | |
92 | + * Returns 1 if .k5login is available, 0 otherwise. | |
93 | + */ | |
94 | +static int | |
95 | +ssh_gssapi_k5login_exists() | |
96 | +{ | |
97 | + char file[MAXPATHLEN]; | |
98 | + struct passwd *pw = the_authctxt->pw; | |
99 | + | |
100 | + snprintf(file, sizeof(file), "%s/.k5login", pw->pw_dir); | |
101 | + return access(file, F_OK) == 0; | |
102 | +} | |
103 | + | |
104 | +/* check .k5users for login or command authorization | |
105 | + * Returns 1 if principal is authorized, 0 otherwise. | |
106 | + * If principal is authorized, (global) k5users_allowed_cmds may be populated. | |
107 | + */ | |
108 | +static int | |
109 | +ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, | |
110 | + const char *luser, int k5login_exists) | |
111 | +{ | |
112 | + FILE *fp; | |
113 | + char file[MAXPATHLEN]; | |
114 | + char line[BUFSIZ]; | |
115 | + char kuser[65]; /* match krb5_kuserok() */ | |
116 | + struct stat st; | |
117 | + struct passwd *pw = the_authctxt->pw; | |
118 | + int found_principal = 0; | |
119 | + int ncommands = 0, allcommands = 0; | |
120 | + u_long linenum; | |
121 | + | |
122 | + snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); | |
123 | + /* If both .k5login and .k5users DNE, self-login is ok. */ | |
124 | + if (!k5login_exists && (access(file, F_OK) == -1)) { | |
125 | + return (krb5_aname_to_localname(krb_context, principal, | |
126 | + sizeof(kuser), kuser) == 0) && | |
127 | + (strcmp(kuser, luser) == 0); | |
128 | + } | |
129 | + if ((fp = fopen(file, "r")) == NULL) { | |
130 | + int saved_errno = errno; | |
131 | + /* 2nd access check to ease debugging if file perms are wrong. | |
132 | + * But we don't want to report this if .k5users simply DNE. */ | |
133 | + if (access(file, F_OK) == 0) { | |
134 | + logit("User %s fopen %s failed: %s", | |
135 | + pw->pw_name, file, strerror(saved_errno)); | |
136 | + } | |
137 | + return 0; | |
138 | + } | |
139 | + /* .k5users must be owned either by the user or by root */ | |
140 | + if (fstat(fileno(fp), &st) == -1) { | |
141 | + /* can happen, but very wierd error so report it */ | |
142 | + logit("User %s fstat %s failed: %s", | |
143 | + pw->pw_name, file, strerror(errno)); | |
144 | + fclose(fp); | |
145 | + return 0; | |
146 | + } | |
147 | + if (!(st.st_uid == pw->pw_uid || st.st_uid == 0)) { | |
148 | + logit("User %s %s is not owned by root or user", | |
149 | + pw->pw_name, file); | |
150 | + fclose(fp); | |
151 | + return 0; | |
152 | + } | |
153 | + /* .k5users must be a regular file. krb5_kuserok() doesn't do this | |
154 | + * check, but we don't want to be deficient if they add a check. */ | |
155 | + if (!S_ISREG(st.st_mode)) { | |
156 | + logit("User %s %s is not a regular file", pw->pw_name, file); | |
157 | + fclose(fp); | |
158 | + return 0; | |
159 | + } | |
160 | + /* file exists; initialize k5users_allowed_cmds (to none!) */ | |
161 | + k5users_allowed_cmds = xcalloc(++ncommands, | |
162 | + sizeof(*k5users_allowed_cmds)); | |
163 | + | |
164 | + /* Check each line. ksu allows unlimited length lines. We don't. */ | |
165 | + while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line), | |
166 | + &linenum) != -1) { | |
167 | + char *token; | |
168 | + | |
169 | + /* we parse just like ksu, even though we could do better */ | |
170 | + token = strtok(line, " \t\n"); | |
171 | + if (strcmp(name, token) == 0) { | |
172 | + /* we matched on client principal */ | |
173 | + found_principal = 1; | |
174 | + if ((token = strtok(NULL, " \t\n")) == NULL) { | |
175 | + /* only shell is allowed */ | |
176 | + k5users_allowed_cmds[ncommands-1] = | |
177 | + xstrdup(pw->pw_shell); | |
178 | + k5users_allowed_cmds = | |
179 | + xrealloc(k5users_allowed_cmds, ++ncommands, | |
180 | + sizeof(*k5users_allowed_cmds)); | |
181 | + break; | |
182 | + } | |
183 | + /* process the allowed commands */ | |
184 | + while (token) { | |
185 | + if (strcmp(token, "*") == 0) { | |
186 | + allcommands = 1; | |
187 | + break; | |
188 | + } | |
189 | + k5users_allowed_cmds[ncommands-1] = | |
190 | + xstrdup(token); | |
191 | + k5users_allowed_cmds = | |
192 | + xrealloc(k5users_allowed_cmds, ++ncommands, | |
193 | + sizeof(*k5users_allowed_cmds)); | |
194 | + token = strtok(NULL, " \t\n"); | |
195 | + } | |
196 | + } | |
197 | + } | |
198 | + if (k5users_allowed_cmds) { | |
199 | + /* terminate vector */ | |
200 | + k5users_allowed_cmds[ncommands-1] = NULL; | |
201 | + /* if all commands are allowed, free vector */ | |
202 | + if (allcommands) { | |
203 | + int i; | |
204 | + for (i = 0; i < ncommands; i++) { | |
205 | + free(k5users_allowed_cmds[i]); | |
206 | + } | |
207 | + free(k5users_allowed_cmds); | |
208 | + k5users_allowed_cmds = NULL; | |
209 | + } | |
210 | + } | |
211 | + fclose(fp); | |
212 | + return found_principal; | |
213 | +} | |
214 | + | |
215 | ||
216 | /* This writes out any forwarded credentials from the structure populated | |
217 | * during userauth. Called after we have setuid to the user */ | |
218 | diff -up openssh-5.8p2/session.c.force_krb openssh-5.8p2/session.c | |
219 | --- openssh-5.8p2/session.c.force_krb 2011-05-19 03:41:41.000000000 +0200 | |
220 | +++ openssh-5.8p2/session.c 2011-05-19 03:43:32.437173662 +0200 | |
221 | @@ -816,6 +816,29 @@ do_exec(Session *s, const char *command) | |
222 | debug("Forced command (key option) '%.900s'", command); | |
223 | } | |
224 | ||
225 | +#ifdef GSSAPI | |
226 | +#ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */ | |
227 | + else if (k5users_allowed_cmds) { | |
228 | + const char *match = command; | |
229 | + int allowed = 0, i = 0; | |
230 | + | |
231 | + if (!match) | |
232 | + match = s->pw->pw_shell; | |
233 | + while (k5users_allowed_cmds[i]) { | |
234 | + if (strcmp(match, k5users_allowed_cmds[i++]) == 0) { | |
235 | + debug("Allowed command '%.900s'", match); | |
236 | + allowed = 1; | |
237 | + break; | |
238 | + } | |
239 | + } | |
240 | + if (!allowed) { | |
241 | + debug("command '%.900s' not allowed", match); | |
242 | + return 1; | |
243 | + } | |
244 | + } | |
245 | +#endif | |
246 | +#endif | |
247 | + | |
248 | #ifdef SSH_AUDIT_EVENTS | |
249 | if (s->command != NULL || s->command_handle != -1) | |
250 | fatal("do_exec: command already set"); | |
251 | diff -up openssh-5.8p2/sshd.8.force_krb openssh-5.8p2/sshd.8 | |
252 | --- openssh-5.8p2/sshd.8.force_krb 2011-05-19 03:41:30.582114401 +0200 | |
253 | +++ openssh-5.8p2/sshd.8 2011-05-19 03:41:46.159106308 +0200 | |
254 | @@ -320,6 +320,7 @@ Finally, the server and the client enter | |
255 | The client tries to authenticate itself using | |
256 | host-based authentication, | |
257 | public key authentication, | |
258 | +GSSAPI authentication, | |
259 | challenge-response authentication, | |
260 | or password authentication. | |
261 | .Pp | |
262 | @@ -788,6 +789,12 @@ This file is used in exactly the same wa | |
263 | but allows host-based authentication without permitting login with | |
264 | rlogin/rsh. | |
265 | .Pp | |
266 | +.It Pa ~/.k5login | |
267 | +.It Pa ~/.k5users | |
268 | +These files enforce GSSAPI/Kerberos authentication access control. | |
269 | +Further details are described in | |
270 | +.Xr ksu 1 . | |
271 | +.Pp | |
272 | .It Pa ~/.ssh/ | |
273 | This directory is the default location for all user-specific configuration | |
274 | and authentication information. | |
275 | diff -up openssh-5.8p2/ssh-gss.h.force_krb openssh-5.8p2/ssh-gss.h | |
276 | --- openssh-5.8p2/ssh-gss.h.force_krb 2007-06-12 15:40:39.000000000 +0200 | |
277 | +++ openssh-5.8p2/ssh-gss.h 2011-05-19 03:41:46.302234118 +0200 | |
278 | @@ -48,6 +48,10 @@ | |
279 | #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name | |
280 | #endif /* GSS_C_NT_... */ | |
281 | #endif /* !HEIMDAL */ | |
282 | + | |
283 | +/* .k5users support */ | |
284 | +extern char **k5users_allowed_cmds; | |
285 | + | |
286 | #endif /* KRB5 */ | |
287 | ||
288 | /* draft-ietf-secsh-gsskeyex-06 */ |