diff options
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r-- | auth2-pubkey.c | 580 |
1 files changed, 128 insertions, 452 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 6dc5076ef..43f880b6b 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.62 2017/01/30 01:03:00 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
30 | #include <sys/wait.h> | ||
31 | 30 | ||
32 | #include <errno.h> | 31 | #include <errno.h> |
33 | #include <fcntl.h> | 32 | #include <fcntl.h> |
@@ -52,7 +51,7 @@ | |||
52 | #include "misc.h" | 51 | #include "misc.h" |
53 | #include "servconf.h" | 52 | #include "servconf.h" |
54 | #include "compat.h" | 53 | #include "compat.h" |
55 | #include "key.h" | 54 | #include "sshkey.h" |
56 | #include "hostfile.h" | 55 | #include "hostfile.h" |
57 | #include "auth.h" | 56 | #include "auth.h" |
58 | #include "pathnames.h" | 57 | #include "pathnames.h" |
@@ -75,42 +74,52 @@ extern u_char *session_id2; | |||
75 | extern u_int session_id2_len; | 74 | extern u_int session_id2_len; |
76 | 75 | ||
77 | static int | 76 | static int |
78 | userauth_pubkey(Authctxt *authctxt) | 77 | userauth_pubkey(struct ssh *ssh) |
79 | { | 78 | { |
80 | Buffer b; | 79 | Authctxt *authctxt = ssh->authctxt; |
81 | Key *key = NULL; | 80 | struct sshbuf *b; |
82 | char *pkalg, *userstyle, *fp = NULL; | 81 | struct sshkey *key = NULL; |
83 | u_char *pkblob, *sig; | 82 | char *pkalg, *userstyle = NULL, *fp = NULL; |
84 | u_int alen, blen, slen; | 83 | u_char *pkblob, *sig, have_sig; |
85 | int have_sig, pktype; | 84 | size_t blen, slen; |
85 | int r, pktype; | ||
86 | int authenticated = 0; | 86 | int authenticated = 0; |
87 | 87 | ||
88 | if (!authctxt->valid) { | 88 | if (!authctxt->valid) { |
89 | debug2("%s: disabled because of invalid user", __func__); | 89 | debug2("%s: disabled because of invalid user", __func__); |
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | have_sig = packet_get_char(); | 92 | if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0) |
93 | if (datafellows & SSH_BUG_PKAUTH) { | 93 | fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r)); |
94 | if (ssh->compat & SSH_BUG_PKAUTH) { | ||
94 | debug2("%s: SSH_BUG_PKAUTH", __func__); | 95 | debug2("%s: SSH_BUG_PKAUTH", __func__); |
96 | if ((b = sshbuf_new()) == NULL) | ||
97 | fatal("%s: sshbuf_new failed", __func__); | ||
95 | /* no explicit pkalg given */ | 98 | /* no explicit pkalg given */ |
96 | pkblob = packet_get_string(&blen); | ||
97 | buffer_init(&b); | ||
98 | buffer_append(&b, pkblob, blen); | ||
99 | /* so we have to extract the pkalg from the pkblob */ | 99 | /* so we have to extract the pkalg from the pkblob */ |
100 | pkalg = buffer_get_string(&b, &alen); | 100 | /* XXX use sshbuf_from() */ |
101 | buffer_free(&b); | 101 | if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || |
102 | (r = sshbuf_put(b, pkblob, blen)) != 0 || | ||
103 | (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0) | ||
104 | fatal("%s: failed: %s", __func__, ssh_err(r)); | ||
105 | sshbuf_free(b); | ||
102 | } else { | 106 | } else { |
103 | pkalg = packet_get_string(&alen); | 107 | if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || |
104 | pkblob = packet_get_string(&blen); | 108 | (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0) |
109 | fatal("%s: sshpkt_get_cstring failed: %s", | ||
110 | __func__, ssh_err(r)); | ||
105 | } | 111 | } |
106 | pktype = key_type_from_name(pkalg); | 112 | pktype = sshkey_type_from_name(pkalg); |
107 | if (pktype == KEY_UNSPEC) { | 113 | if (pktype == KEY_UNSPEC) { |
108 | /* this is perfectly legal */ | 114 | /* this is perfectly legal */ |
109 | logit("%s: unsupported public key algorithm: %s", | 115 | logit("%s: unsupported public key algorithm: %s", |
110 | __func__, pkalg); | 116 | __func__, pkalg); |
111 | goto done; | 117 | goto done; |
112 | } | 118 | } |
113 | key = key_from_blob(pkblob, blen); | 119 | if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { |
120 | error("%s: could not parse key: %s", __func__, ssh_err(r)); | ||
121 | goto done; | ||
122 | } | ||
114 | if (key == NULL) { | 123 | if (key == NULL) { |
115 | error("%s: cannot decode key: %s", __func__, pkalg); | 124 | error("%s: cannot decode key: %s", __func__, pkalg); |
116 | goto done; | 125 | goto done; |
@@ -120,15 +129,15 @@ userauth_pubkey(Authctxt *authctxt) | |||
120 | "(received %d, expected %d)", __func__, key->type, pktype); | 129 | "(received %d, expected %d)", __func__, key->type, pktype); |
121 | goto done; | 130 | goto done; |
122 | } | 131 | } |
123 | if (key_type_plain(key->type) == KEY_RSA && | 132 | if (sshkey_type_plain(key->type) == KEY_RSA && |
124 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | 133 | (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { |
125 | logit("Refusing RSA key because client uses unsafe " | 134 | logit("Refusing RSA key because client uses unsafe " |
126 | "signature scheme"); | 135 | "signature scheme"); |
127 | goto done; | 136 | goto done; |
128 | } | 137 | } |
129 | fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); | 138 | fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); |
130 | if (auth2_userkey_already_used(authctxt, key)) { | 139 | if (auth2_key_already_used(authctxt, key)) { |
131 | logit("refusing previously-used %s key", key_type(key)); | 140 | logit("refusing previously-used %s key", sshkey_type(key)); |
132 | goto done; | 141 | goto done; |
133 | } | 142 | } |
134 | if (match_pattern_list(sshkey_ssh_name(key), | 143 | if (match_pattern_list(sshkey_ssh_name(key), |
@@ -141,54 +150,65 @@ userauth_pubkey(Authctxt *authctxt) | |||
141 | if (have_sig) { | 150 | if (have_sig) { |
142 | debug3("%s: have signature for %s %s", | 151 | debug3("%s: have signature for %s %s", |
143 | __func__, sshkey_type(key), fp); | 152 | __func__, sshkey_type(key), fp); |
144 | sig = packet_get_string(&slen); | 153 | if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 || |
145 | packet_check_eom(); | 154 | (r = sshpkt_get_end(ssh)) != 0) |
146 | buffer_init(&b); | 155 | fatal("%s: %s", __func__, ssh_err(r)); |
147 | if (datafellows & SSH_OLD_SESSIONID) { | 156 | if ((b = sshbuf_new()) == NULL) |
148 | buffer_append(&b, session_id2, session_id2_len); | 157 | fatal("%s: sshbuf_new failed", __func__); |
158 | if (ssh->compat & SSH_OLD_SESSIONID) { | ||
159 | if ((r = sshbuf_put(b, session_id2, | ||
160 | session_id2_len)) != 0) | ||
161 | fatal("%s: sshbuf_put session id: %s", | ||
162 | __func__, ssh_err(r)); | ||
149 | } else { | 163 | } else { |
150 | buffer_put_string(&b, session_id2, session_id2_len); | 164 | if ((r = sshbuf_put_string(b, session_id2, |
165 | session_id2_len)) != 0) | ||
166 | fatal("%s: sshbuf_put_string session id: %s", | ||
167 | __func__, ssh_err(r)); | ||
151 | } | 168 | } |
152 | /* reconstruct packet */ | 169 | /* reconstruct packet */ |
153 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | ||
154 | xasprintf(&userstyle, "%s%s%s", authctxt->user, | 170 | xasprintf(&userstyle, "%s%s%s", authctxt->user, |
155 | authctxt->style ? ":" : "", | 171 | authctxt->style ? ":" : "", |
156 | authctxt->style ? authctxt->style : ""); | 172 | authctxt->style ? authctxt->style : ""); |
157 | buffer_put_cstring(&b, userstyle); | 173 | if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
158 | free(userstyle); | 174 | (r = sshbuf_put_cstring(b, userstyle)) != 0 || |
159 | buffer_put_cstring(&b, | 175 | (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ? |
160 | datafellows & SSH_BUG_PKSERVICE ? | 176 | "ssh-userauth" : authctxt->service)) != 0) |
161 | "ssh-userauth" : | 177 | fatal("%s: build packet failed: %s", |
162 | authctxt->service); | 178 | __func__, ssh_err(r)); |
163 | if (datafellows & SSH_BUG_PKAUTH) { | 179 | if (ssh->compat & SSH_BUG_PKAUTH) { |
164 | buffer_put_char(&b, have_sig); | 180 | if ((r = sshbuf_put_u8(b, have_sig)) != 0) |
181 | fatal("%s: build packet failed: %s", | ||
182 | __func__, ssh_err(r)); | ||
165 | } else { | 183 | } else { |
166 | buffer_put_cstring(&b, "publickey"); | 184 | if ((r = sshbuf_put_cstring(b, "publickey")) != 0 || |
167 | buffer_put_char(&b, have_sig); | 185 | (r = sshbuf_put_u8(b, have_sig)) != 0 || |
168 | buffer_put_cstring(&b, pkalg); | 186 | (r = sshbuf_put_cstring(b, pkalg) != 0)) |
187 | fatal("%s: build packet failed: %s", | ||
188 | __func__, ssh_err(r)); | ||
169 | } | 189 | } |
170 | buffer_put_string(&b, pkblob, blen); | 190 | if ((r = sshbuf_put_string(b, pkblob, blen)) != 0) |
191 | fatal("%s: build packet failed: %s", | ||
192 | __func__, ssh_err(r)); | ||
171 | #ifdef DEBUG_PK | 193 | #ifdef DEBUG_PK |
172 | buffer_dump(&b); | 194 | sshbuf_dump(b, stderr); |
173 | #endif | 195 | #endif |
174 | pubkey_auth_info(authctxt, key, NULL); | ||
175 | 196 | ||
176 | /* test for correct signature */ | 197 | /* test for correct signature */ |
177 | authenticated = 0; | 198 | authenticated = 0; |
178 | if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && | 199 | if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && |
179 | PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | 200 | PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), |
180 | buffer_len(&b))) == 1) { | 201 | sshbuf_len(b), ssh->compat)) == 0) { |
181 | authenticated = 1; | 202 | authenticated = 1; |
182 | /* Record the successful key to prevent reuse */ | ||
183 | auth2_record_userkey(authctxt, key); | ||
184 | key = NULL; /* Don't free below */ | ||
185 | } | 203 | } |
186 | buffer_free(&b); | 204 | sshbuf_free(b); |
187 | free(sig); | 205 | free(sig); |
206 | auth2_record_key(authctxt, authenticated, key); | ||
188 | } else { | 207 | } else { |
189 | debug("%s: test whether pkalg/pkblob are acceptable for %s %s", | 208 | debug("%s: test whether pkalg/pkblob are acceptable for %s %s", |
190 | __func__, sshkey_type(key), fp); | 209 | __func__, sshkey_type(key), fp); |
191 | packet_check_eom(); | 210 | if ((r = sshpkt_get_end(ssh)) != 0) |
211 | fatal("%s: %s", __func__, ssh_err(r)); | ||
192 | 212 | ||
193 | /* XXX fake reply and always send PK_OK ? */ | 213 | /* XXX fake reply and always send PK_OK ? */ |
194 | /* | 214 | /* |
@@ -199,11 +219,13 @@ userauth_pubkey(Authctxt *authctxt) | |||
199 | * issue? -markus | 219 | * issue? -markus |
200 | */ | 220 | */ |
201 | if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { | 221 | if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { |
202 | packet_start(SSH2_MSG_USERAUTH_PK_OK); | 222 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) |
203 | packet_put_string(pkalg, alen); | 223 | != 0 || |
204 | packet_put_string(pkblob, blen); | 224 | (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || |
205 | packet_send(); | 225 | (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 || |
206 | packet_write_wait(); | 226 | (r = sshpkt_send(ssh)) != 0) |
227 | fatal("%s: %s", __func__, ssh_err(r)); | ||
228 | ssh_packet_write_wait(ssh); | ||
207 | authctxt->postponed = 1; | 229 | authctxt->postponed = 1; |
208 | } | 230 | } |
209 | } | 231 | } |
@@ -211,333 +233,14 @@ userauth_pubkey(Authctxt *authctxt) | |||
211 | auth_clear_options(); | 233 | auth_clear_options(); |
212 | done: | 234 | done: |
213 | debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); | 235 | debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); |
214 | if (key != NULL) | 236 | sshkey_free(key); |
215 | key_free(key); | 237 | free(userstyle); |
216 | free(pkalg); | 238 | free(pkalg); |
217 | free(pkblob); | 239 | free(pkblob); |
218 | free(fp); | 240 | free(fp); |
219 | return authenticated; | 241 | return authenticated; |
220 | } | 242 | } |
221 | 243 | ||
222 | void | ||
223 | pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) | ||
224 | { | ||
225 | char *fp, *extra; | ||
226 | va_list ap; | ||
227 | int i; | ||
228 | |||
229 | extra = NULL; | ||
230 | if (fmt != NULL) { | ||
231 | va_start(ap, fmt); | ||
232 | i = vasprintf(&extra, fmt, ap); | ||
233 | va_end(ap); | ||
234 | if (i < 0 || extra == NULL) | ||
235 | fatal("%s: vasprintf failed", __func__); | ||
236 | } | ||
237 | |||
238 | if (key_is_cert(key)) { | ||
239 | fp = sshkey_fingerprint(key->cert->signature_key, | ||
240 | options.fingerprint_hash, SSH_FP_DEFAULT); | ||
241 | auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", | ||
242 | key_type(key), key->cert->key_id, | ||
243 | (unsigned long long)key->cert->serial, | ||
244 | key_type(key->cert->signature_key), | ||
245 | fp == NULL ? "(null)" : fp, | ||
246 | extra == NULL ? "" : ", ", extra == NULL ? "" : extra); | ||
247 | free(fp); | ||
248 | } else { | ||
249 | fp = sshkey_fingerprint(key, options.fingerprint_hash, | ||
250 | SSH_FP_DEFAULT); | ||
251 | auth_info(authctxt, "%s %s%s%s", key_type(key), | ||
252 | fp == NULL ? "(null)" : fp, | ||
253 | extra == NULL ? "" : ", ", extra == NULL ? "" : extra); | ||
254 | free(fp); | ||
255 | } | ||
256 | free(extra); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Splits 's' into an argument vector. Handles quoted string and basic | ||
261 | * escape characters (\\, \", \'). Caller must free the argument vector | ||
262 | * and its members. | ||
263 | */ | ||
264 | static int | ||
265 | split_argv(const char *s, int *argcp, char ***argvp) | ||
266 | { | ||
267 | int r = SSH_ERR_INTERNAL_ERROR; | ||
268 | int argc = 0, quote, i, j; | ||
269 | char *arg, **argv = xcalloc(1, sizeof(*argv)); | ||
270 | |||
271 | *argvp = NULL; | ||
272 | *argcp = 0; | ||
273 | |||
274 | for (i = 0; s[i] != '\0'; i++) { | ||
275 | /* Skip leading whitespace */ | ||
276 | if (s[i] == ' ' || s[i] == '\t') | ||
277 | continue; | ||
278 | |||
279 | /* Start of a token */ | ||
280 | quote = 0; | ||
281 | if (s[i] == '\\' && | ||
282 | (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\')) | ||
283 | i++; | ||
284 | else if (s[i] == '\'' || s[i] == '"') | ||
285 | quote = s[i++]; | ||
286 | |||
287 | argv = xreallocarray(argv, (argc + 2), sizeof(*argv)); | ||
288 | arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1); | ||
289 | argv[argc] = NULL; | ||
290 | |||
291 | /* Copy the token in, removing escapes */ | ||
292 | for (j = 0; s[i] != '\0'; i++) { | ||
293 | if (s[i] == '\\') { | ||
294 | if (s[i + 1] == '\'' || | ||
295 | s[i + 1] == '\"' || | ||
296 | s[i + 1] == '\\') { | ||
297 | i++; /* Skip '\' */ | ||
298 | arg[j++] = s[i]; | ||
299 | } else { | ||
300 | /* Unrecognised escape */ | ||
301 | arg[j++] = s[i]; | ||
302 | } | ||
303 | } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t')) | ||
304 | break; /* done */ | ||
305 | else if (quote != 0 && s[i] == quote) | ||
306 | break; /* done */ | ||
307 | else | ||
308 | arg[j++] = s[i]; | ||
309 | } | ||
310 | if (s[i] == '\0') { | ||
311 | if (quote != 0) { | ||
312 | /* Ran out of string looking for close quote */ | ||
313 | r = SSH_ERR_INVALID_FORMAT; | ||
314 | goto out; | ||
315 | } | ||
316 | break; | ||
317 | } | ||
318 | } | ||
319 | /* Success */ | ||
320 | *argcp = argc; | ||
321 | *argvp = argv; | ||
322 | argc = 0; | ||
323 | argv = NULL; | ||
324 | r = 0; | ||
325 | out: | ||
326 | if (argc != 0 && argv != NULL) { | ||
327 | for (i = 0; i < argc; i++) | ||
328 | free(argv[i]); | ||
329 | free(argv); | ||
330 | } | ||
331 | return r; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Reassemble an argument vector into a string, quoting and escaping as | ||
336 | * necessary. Caller must free returned string. | ||
337 | */ | ||
338 | static char * | ||
339 | assemble_argv(int argc, char **argv) | ||
340 | { | ||
341 | int i, j, ws, r; | ||
342 | char c, *ret; | ||
343 | struct sshbuf *buf, *arg; | ||
344 | |||
345 | if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) | ||
346 | fatal("%s: sshbuf_new failed", __func__); | ||
347 | |||
348 | for (i = 0; i < argc; i++) { | ||
349 | ws = 0; | ||
350 | sshbuf_reset(arg); | ||
351 | for (j = 0; argv[i][j] != '\0'; j++) { | ||
352 | r = 0; | ||
353 | c = argv[i][j]; | ||
354 | switch (c) { | ||
355 | case ' ': | ||
356 | case '\t': | ||
357 | ws = 1; | ||
358 | r = sshbuf_put_u8(arg, c); | ||
359 | break; | ||
360 | case '\\': | ||
361 | case '\'': | ||
362 | case '"': | ||
363 | if ((r = sshbuf_put_u8(arg, '\\')) != 0) | ||
364 | break; | ||
365 | /* FALLTHROUGH */ | ||
366 | default: | ||
367 | r = sshbuf_put_u8(arg, c); | ||
368 | break; | ||
369 | } | ||
370 | if (r != 0) | ||
371 | fatal("%s: sshbuf_put_u8: %s", | ||
372 | __func__, ssh_err(r)); | ||
373 | } | ||
374 | if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || | ||
375 | (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || | ||
376 | (r = sshbuf_putb(buf, arg)) != 0 || | ||
377 | (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) | ||
378 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
379 | } | ||
380 | if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) | ||
381 | fatal("%s: malloc failed", __func__); | ||
382 | memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); | ||
383 | ret[sshbuf_len(buf)] = '\0'; | ||
384 | sshbuf_free(buf); | ||
385 | sshbuf_free(arg); | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * Runs command in a subprocess. Returns pid on success and a FILE* to the | ||
391 | * subprocess' stdout or 0 on failure. | ||
392 | * NB. "command" is only used for logging. | ||
393 | */ | ||
394 | static pid_t | ||
395 | subprocess(const char *tag, struct passwd *pw, const char *command, | ||
396 | int ac, char **av, FILE **child) | ||
397 | { | ||
398 | FILE *f; | ||
399 | struct stat st; | ||
400 | int devnull, p[2], i; | ||
401 | pid_t pid; | ||
402 | char *cp, errmsg[512]; | ||
403 | u_int envsize; | ||
404 | char **child_env; | ||
405 | |||
406 | *child = NULL; | ||
407 | |||
408 | debug3("%s: %s command \"%s\" running as %s", __func__, | ||
409 | tag, command, pw->pw_name); | ||
410 | |||
411 | /* Verify the path exists and is safe-ish to execute */ | ||
412 | if (*av[0] != '/') { | ||
413 | error("%s path is not absolute", tag); | ||
414 | return 0; | ||
415 | } | ||
416 | temporarily_use_uid(pw); | ||
417 | if (stat(av[0], &st) < 0) { | ||
418 | error("Could not stat %s \"%s\": %s", tag, | ||
419 | av[0], strerror(errno)); | ||
420 | restore_uid(); | ||
421 | return 0; | ||
422 | } | ||
423 | if (auth_secure_path(av[0], &st, NULL, 0, | ||
424 | errmsg, sizeof(errmsg)) != 0) { | ||
425 | error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); | ||
426 | restore_uid(); | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * Run the command; stderr is left in place, stdout is the | ||
432 | * authorized_keys output. | ||
433 | */ | ||
434 | if (pipe(p) != 0) { | ||
435 | error("%s: pipe: %s", tag, strerror(errno)); | ||
436 | restore_uid(); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Don't want to call this in the child, where it can fatal() and | ||
442 | * run cleanup_exit() code. | ||
443 | */ | ||
444 | restore_uid(); | ||
445 | |||
446 | switch ((pid = fork())) { | ||
447 | case -1: /* error */ | ||
448 | error("%s: fork: %s", tag, strerror(errno)); | ||
449 | close(p[0]); | ||
450 | close(p[1]); | ||
451 | return 0; | ||
452 | case 0: /* child */ | ||
453 | /* Prepare a minimal environment for the child. */ | ||
454 | envsize = 5; | ||
455 | child_env = xcalloc(sizeof(*child_env), envsize); | ||
456 | child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); | ||
457 | child_set_env(&child_env, &envsize, "USER", pw->pw_name); | ||
458 | child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); | ||
459 | child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); | ||
460 | if ((cp = getenv("LANG")) != NULL) | ||
461 | child_set_env(&child_env, &envsize, "LANG", cp); | ||
462 | |||
463 | for (i = 0; i < NSIG; i++) | ||
464 | signal(i, SIG_DFL); | ||
465 | |||
466 | if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { | ||
467 | error("%s: open %s: %s", tag, _PATH_DEVNULL, | ||
468 | strerror(errno)); | ||
469 | _exit(1); | ||
470 | } | ||
471 | /* Keep stderr around a while longer to catch errors */ | ||
472 | if (dup2(devnull, STDIN_FILENO) == -1 || | ||
473 | dup2(p[1], STDOUT_FILENO) == -1) { | ||
474 | error("%s: dup2: %s", tag, strerror(errno)); | ||
475 | _exit(1); | ||
476 | } | ||
477 | closefrom(STDERR_FILENO + 1); | ||
478 | |||
479 | /* Don't use permanently_set_uid() here to avoid fatal() */ | ||
480 | if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { | ||
481 | error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, | ||
482 | strerror(errno)); | ||
483 | _exit(1); | ||
484 | } | ||
485 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { | ||
486 | error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, | ||
487 | strerror(errno)); | ||
488 | _exit(1); | ||
489 | } | ||
490 | /* stdin is pointed to /dev/null at this point */ | ||
491 | if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) { | ||
492 | error("%s: dup2: %s", tag, strerror(errno)); | ||
493 | _exit(1); | ||
494 | } | ||
495 | |||
496 | execve(av[0], av, child_env); | ||
497 | error("%s exec \"%s\": %s", tag, command, strerror(errno)); | ||
498 | _exit(127); | ||
499 | default: /* parent */ | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | close(p[1]); | ||
504 | if ((f = fdopen(p[0], "r")) == NULL) { | ||
505 | error("%s: fdopen: %s", tag, strerror(errno)); | ||
506 | close(p[0]); | ||
507 | /* Don't leave zombie child */ | ||
508 | kill(pid, SIGTERM); | ||
509 | while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) | ||
510 | ; | ||
511 | return 0; | ||
512 | } | ||
513 | /* Success */ | ||
514 | debug3("%s: %s pid %ld", __func__, tag, (long)pid); | ||
515 | *child = f; | ||
516 | return pid; | ||
517 | } | ||
518 | |||
519 | /* Returns 0 if pid exited cleanly, non-zero otherwise */ | ||
520 | static int | ||
521 | exited_cleanly(pid_t pid, const char *tag, const char *cmd) | ||
522 | { | ||
523 | int status; | ||
524 | |||
525 | while (waitpid(pid, &status, 0) == -1) { | ||
526 | if (errno != EINTR) { | ||
527 | error("%s: waitpid: %s", tag, strerror(errno)); | ||
528 | return -1; | ||
529 | } | ||
530 | } | ||
531 | if (WIFSIGNALED(status)) { | ||
532 | error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status)); | ||
533 | return -1; | ||
534 | } else if (WEXITSTATUS(status) != 0) { | ||
535 | error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status)); | ||
536 | return -1; | ||
537 | } | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int | 244 | static int |
542 | match_principals_option(const char *principal_list, struct sshkey_cert *cert) | 245 | match_principals_option(const char *principal_list, struct sshkey_cert *cert) |
543 | { | 246 | { |
@@ -559,7 +262,7 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert) | |||
559 | } | 262 | } |
560 | 263 | ||
561 | static int | 264 | static int |
562 | process_principals(FILE *f, char *file, struct passwd *pw, | 265 | process_principals(FILE *f, const char *file, struct passwd *pw, |
563 | const struct sshkey_cert *cert) | 266 | const struct sshkey_cert *cert) |
564 | { | 267 | { |
565 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; | 268 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; |
@@ -598,8 +301,7 @@ process_principals(FILE *f, char *file, struct passwd *pw, | |||
598 | for (i = 0; i < cert->nprincipals; i++) { | 301 | for (i = 0; i < cert->nprincipals; i++) { |
599 | if (strcmp(cp, cert->principals[i]) == 0) { | 302 | if (strcmp(cp, cert->principals[i]) == 0) { |
600 | debug3("%s:%lu: matched principal \"%.100s\"", | 303 | debug3("%s:%lu: matched principal \"%.100s\"", |
601 | file == NULL ? "(command)" : file, | 304 | file, linenum, cert->principals[i]); |
602 | linenum, cert->principals[i]); | ||
603 | if (auth_parse_options(pw, line_opts, | 305 | if (auth_parse_options(pw, line_opts, |
604 | file, linenum) != 1) | 306 | file, linenum) != 1) |
605 | continue; | 307 | continue; |
@@ -672,7 +374,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) | |||
672 | } | 374 | } |
673 | 375 | ||
674 | /* Turn the command into an argument vector */ | 376 | /* Turn the command into an argument vector */ |
675 | if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { | 377 | if (argv_split(options.authorized_principals_command, &ac, &av) != 0) { |
676 | error("AuthorizedPrincipalsCommand \"%s\" contains " | 378 | error("AuthorizedPrincipalsCommand \"%s\" contains " |
677 | "invalid quotes", command); | 379 | "invalid quotes", command); |
678 | goto out; | 380 | goto out; |
@@ -721,21 +423,22 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) | |||
721 | av[i] = tmp; | 423 | av[i] = tmp; |
722 | } | 424 | } |
723 | /* Prepare a printable command for logs, etc. */ | 425 | /* Prepare a printable command for logs, etc. */ |
724 | command = assemble_argv(ac, av); | 426 | command = argv_assemble(ac, av); |
725 | 427 | ||
726 | if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, | 428 | if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, |
727 | ac, av, &f)) == 0) | 429 | ac, av, &f, |
430 | SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) | ||
728 | goto out; | 431 | goto out; |
729 | 432 | ||
730 | uid_swapped = 1; | 433 | uid_swapped = 1; |
731 | temporarily_use_uid(pw); | 434 | temporarily_use_uid(pw); |
732 | 435 | ||
733 | ok = process_principals(f, NULL, pw, cert); | 436 | ok = process_principals(f, "(command)", pw, cert); |
734 | 437 | ||
735 | fclose(f); | 438 | fclose(f); |
736 | f = NULL; | 439 | f = NULL; |
737 | 440 | ||
738 | if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) | 441 | if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0) |
739 | goto out; | 442 | goto out; |
740 | 443 | ||
741 | /* Read completed successfully */ | 444 | /* Read completed successfully */ |
@@ -762,27 +465,26 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key) | |||
762 | * returns 1 if the key is allowed or 0 otherwise. | 465 | * returns 1 if the key is allowed or 0 otherwise. |
763 | */ | 466 | */ |
764 | static int | 467 | static int |
765 | check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | 468 | check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw) |
766 | { | 469 | { |
767 | char line[SSH_MAX_PUBKEY_BYTES]; | 470 | char line[SSH_MAX_PUBKEY_BYTES]; |
768 | int found_key = 0; | 471 | int found_key = 0; |
769 | u_long linenum = 0; | 472 | u_long linenum = 0; |
770 | Key *found; | 473 | struct sshkey *found = NULL; |
771 | |||
772 | found_key = 0; | ||
773 | 474 | ||
774 | found = NULL; | ||
775 | auth_start_parse_options(); | 475 | auth_start_parse_options(); |
776 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { | 476 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { |
777 | char *cp, *key_options = NULL, *fp = NULL; | 477 | char *cp, *key_options = NULL, *fp = NULL; |
778 | const char *reason = NULL; | 478 | const char *reason = NULL; |
779 | 479 | ||
780 | /* Always consume entrire file */ | 480 | /* Always consume entire file */ |
781 | if (found_key) | 481 | if (found_key) |
782 | continue; | 482 | continue; |
783 | if (found != NULL) | 483 | if (found != NULL) |
784 | key_free(found); | 484 | sshkey_free(found); |
785 | found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); | 485 | found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type); |
486 | if (found == NULL) | ||
487 | goto done; | ||
786 | auth_clear_options(); | 488 | auth_clear_options(); |
787 | 489 | ||
788 | /* Skip leading whitespace, empty and comment lines. */ | 490 | /* Skip leading whitespace, empty and comment lines. */ |
@@ -791,7 +493,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
791 | if (!*cp || *cp == '\n' || *cp == '#') | 493 | if (!*cp || *cp == '\n' || *cp == '#') |
792 | continue; | 494 | continue; |
793 | 495 | ||
794 | if (key_read(found, &cp) != 1) { | 496 | if (sshkey_read(found, &cp) != 0) { |
795 | /* no key? check if there are options for this key */ | 497 | /* no key? check if there are options for this key */ |
796 | int quoted = 0; | 498 | int quoted = 0; |
797 | debug2("user_key_allowed: check options: '%s'", cp); | 499 | debug2("user_key_allowed: check options: '%s'", cp); |
@@ -805,14 +507,14 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
805 | /* Skip remaining whitespace. */ | 507 | /* Skip remaining whitespace. */ |
806 | for (; *cp == ' ' || *cp == '\t'; cp++) | 508 | for (; *cp == ' ' || *cp == '\t'; cp++) |
807 | ; | 509 | ; |
808 | if (key_read(found, &cp) != 1) { | 510 | if (sshkey_read(found, &cp) != 0) { |
809 | debug2("user_key_allowed: advance: '%s'", cp); | 511 | debug2("user_key_allowed: advance: '%s'", cp); |
810 | /* still no key? advance to next line*/ | 512 | /* still no key? advance to next line*/ |
811 | continue; | 513 | continue; |
812 | } | 514 | } |
813 | } | 515 | } |
814 | if (key_is_cert(key)) { | 516 | if (sshkey_is_cert(key)) { |
815 | if (!key_equal(found, key->cert->signature_key)) | 517 | if (!sshkey_equal(found, key->cert->signature_key)) |
816 | continue; | 518 | continue; |
817 | if (auth_parse_options(pw, key_options, file, | 519 | if (auth_parse_options(pw, key_options, file, |
818 | linenum) != 1) | 520 | linenum) != 1) |
@@ -823,7 +525,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
823 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) | 525 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
824 | continue; | 526 | continue; |
825 | debug("matching CA found: file %s, line %lu, %s %s", | 527 | debug("matching CA found: file %s, line %lu, %s %s", |
826 | file, linenum, key_type(found), fp); | 528 | file, linenum, sshkey_type(found), fp); |
827 | /* | 529 | /* |
828 | * If the user has specified a list of principals as | 530 | * If the user has specified a list of principals as |
829 | * a key option, then prefer that list to matching | 531 | * a key option, then prefer that list to matching |
@@ -840,7 +542,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
840 | auth_debug_add("%s", reason); | 542 | auth_debug_add("%s", reason); |
841 | continue; | 543 | continue; |
842 | } | 544 | } |
843 | if (key_cert_check_authority(key, 0, 0, | 545 | if (sshkey_cert_check_authority(key, 0, 0, |
844 | authorized_principals == NULL ? pw->pw_name : NULL, | 546 | authorized_principals == NULL ? pw->pw_name : NULL, |
845 | &reason) != 0) | 547 | &reason) != 0) |
846 | goto fail_reason; | 548 | goto fail_reason; |
@@ -849,11 +551,11 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
849 | verbose("Accepted certificate ID \"%s\" (serial %llu) " | 551 | verbose("Accepted certificate ID \"%s\" (serial %llu) " |
850 | "signed by %s CA %s via %s", key->cert->key_id, | 552 | "signed by %s CA %s via %s", key->cert->key_id, |
851 | (unsigned long long)key->cert->serial, | 553 | (unsigned long long)key->cert->serial, |
852 | key_type(found), fp, file); | 554 | sshkey_type(found), fp, file); |
853 | free(fp); | 555 | free(fp); |
854 | found_key = 1; | 556 | found_key = 1; |
855 | break; | 557 | break; |
856 | } else if (key_equal(found, key)) { | 558 | } else if (sshkey_equal(found, key)) { |
857 | if (auth_parse_options(pw, key_options, file, | 559 | if (auth_parse_options(pw, key_options, file, |
858 | linenum) != 1) | 560 | linenum) != 1) |
859 | continue; | 561 | continue; |
@@ -863,14 +565,15 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
863 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) | 565 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
864 | continue; | 566 | continue; |
865 | debug("matching key found: file %s, line %lu %s %s", | 567 | debug("matching key found: file %s, line %lu %s %s", |
866 | file, linenum, key_type(found), fp); | 568 | file, linenum, sshkey_type(found), fp); |
867 | free(fp); | 569 | free(fp); |
868 | found_key = 1; | 570 | found_key = 1; |
869 | continue; | 571 | continue; |
870 | } | 572 | } |
871 | } | 573 | } |
574 | done: | ||
872 | if (found != NULL) | 575 | if (found != NULL) |
873 | key_free(found); | 576 | sshkey_free(found); |
874 | if (!found_key) | 577 | if (!found_key) |
875 | debug2("key not found"); | 578 | debug2("key not found"); |
876 | return found_key; | 579 | return found_key; |
@@ -878,24 +581,24 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | |||
878 | 581 | ||
879 | /* Authenticate a certificate key against TrustedUserCAKeys */ | 582 | /* Authenticate a certificate key against TrustedUserCAKeys */ |
880 | static int | 583 | static int |
881 | user_cert_trusted_ca(struct passwd *pw, Key *key) | 584 | user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) |
882 | { | 585 | { |
883 | char *ca_fp, *principals_file = NULL; | 586 | char *ca_fp, *principals_file = NULL; |
884 | const char *reason; | 587 | const char *reason; |
885 | int ret = 0, found_principal = 0, use_authorized_principals; | 588 | int r, ret = 0, found_principal = 0, use_authorized_principals; |
886 | 589 | ||
887 | if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) | 590 | if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) |
888 | return 0; | 591 | return 0; |
889 | 592 | ||
890 | if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, | 593 | if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, |
891 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) | 594 | options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) |
892 | return 0; | 595 | return 0; |
893 | 596 | ||
894 | if (sshkey_in_file(key->cert->signature_key, | 597 | if ((r = sshkey_in_file(key->cert->signature_key, |
895 | options.trusted_user_ca_keys, 1, 0) != 0) { | 598 | options.trusted_user_ca_keys, 1, 0)) != 0) { |
896 | debug2("%s: CA %s %s is not listed in %s", __func__, | 599 | debug2("%s: CA %s %s is not listed in %s: %s", __func__, |
897 | key_type(key->cert->signature_key), ca_fp, | 600 | sshkey_type(key->cert->signature_key), ca_fp, |
898 | options.trusted_user_ca_keys); | 601 | options.trusted_user_ca_keys, ssh_err(r)); |
899 | goto out; | 602 | goto out; |
900 | } | 603 | } |
901 | /* | 604 | /* |
@@ -920,7 +623,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
920 | auth_debug_add("%s", reason); | 623 | auth_debug_add("%s", reason); |
921 | goto out; | 624 | goto out; |
922 | } | 625 | } |
923 | if (key_cert_check_authority(key, 0, 1, | 626 | if (sshkey_cert_check_authority(key, 0, 1, |
924 | use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) | 627 | use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) |
925 | goto fail_reason; | 628 | goto fail_reason; |
926 | auth_start_parse_options(); | 629 | auth_start_parse_options(); |
@@ -930,7 +633,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
930 | verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " | 633 | verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " |
931 | "%s CA %s via %s", key->cert->key_id, | 634 | "%s CA %s via %s", key->cert->key_id, |
932 | (unsigned long long)key->cert->serial, | 635 | (unsigned long long)key->cert->serial, |
933 | key_type(key->cert->signature_key), ca_fp, | 636 | sshkey_type(key->cert->signature_key), ca_fp, |
934 | options.trusted_user_ca_keys); | 637 | options.trusted_user_ca_keys); |
935 | ret = 1; | 638 | ret = 1; |
936 | 639 | ||
@@ -945,7 +648,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
945 | * returns 1 if the key is allowed or 0 otherwise. | 648 | * returns 1 if the key is allowed or 0 otherwise. |
946 | */ | 649 | */ |
947 | static int | 650 | static int |
948 | user_key_allowed2(struct passwd *pw, Key *key, char *file) | 651 | user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) |
949 | { | 652 | { |
950 | FILE *f; | 653 | FILE *f; |
951 | int found_key = 0; | 654 | int found_key = 0; |
@@ -968,7 +671,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) | |||
968 | * returns 1 if the key is allowed or 0 otherwise. | 671 | * returns 1 if the key is allowed or 0 otherwise. |
969 | */ | 672 | */ |
970 | static int | 673 | static int |
971 | user_key_command_allowed2(struct passwd *user_pw, Key *key) | 674 | user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) |
972 | { | 675 | { |
973 | FILE *f = NULL; | 676 | FILE *f = NULL; |
974 | int r, ok, found_key = 0; | 677 | int r, ok, found_key = 0; |
@@ -1014,7 +717,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) | |||
1014 | } | 717 | } |
1015 | 718 | ||
1016 | /* Turn the command into an argument vector */ | 719 | /* Turn the command into an argument vector */ |
1017 | if (split_argv(options.authorized_keys_command, &ac, &av) != 0) { | 720 | if (argv_split(options.authorized_keys_command, &ac, &av) != 0) { |
1018 | error("AuthorizedKeysCommand \"%s\" contains invalid quotes", | 721 | error("AuthorizedKeysCommand \"%s\" contains invalid quotes", |
1019 | command); | 722 | command); |
1020 | goto out; | 723 | goto out; |
@@ -1038,7 +741,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) | |||
1038 | av[i] = tmp; | 741 | av[i] = tmp; |
1039 | } | 742 | } |
1040 | /* Prepare a printable command for logs, etc. */ | 743 | /* Prepare a printable command for logs, etc. */ |
1041 | command = assemble_argv(ac, av); | 744 | command = argv_assemble(ac, av); |
1042 | 745 | ||
1043 | /* | 746 | /* |
1044 | * If AuthorizedKeysCommand was run without arguments | 747 | * If AuthorizedKeysCommand was run without arguments |
@@ -1055,7 +758,8 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) | |||
1055 | } | 758 | } |
1056 | 759 | ||
1057 | if ((pid = subprocess("AuthorizedKeysCommand", pw, command, | 760 | if ((pid = subprocess("AuthorizedKeysCommand", pw, command, |
1058 | ac, av, &f)) == 0) | 761 | ac, av, &f, |
762 | SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) | ||
1059 | goto out; | 763 | goto out; |
1060 | 764 | ||
1061 | uid_swapped = 1; | 765 | uid_swapped = 1; |
@@ -1066,7 +770,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) | |||
1066 | fclose(f); | 770 | fclose(f); |
1067 | f = NULL; | 771 | f = NULL; |
1068 | 772 | ||
1069 | if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0) | 773 | if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0) |
1070 | goto out; | 774 | goto out; |
1071 | 775 | ||
1072 | /* Read completed successfully */ | 776 | /* Read completed successfully */ |
@@ -1091,14 +795,15 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) | |||
1091 | * Check whether key authenticates and authorises the user. | 795 | * Check whether key authenticates and authorises the user. |
1092 | */ | 796 | */ |
1093 | int | 797 | int |
1094 | user_key_allowed(struct passwd *pw, Key *key, int auth_attempt) | 798 | user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) |
1095 | { | 799 | { |
1096 | u_int success, i; | 800 | u_int success, i; |
1097 | char *file; | 801 | char *file; |
1098 | 802 | ||
1099 | if (auth_key_is_revoked(key)) | 803 | if (auth_key_is_revoked(key)) |
1100 | return 0; | 804 | return 0; |
1101 | if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) | 805 | if (sshkey_is_cert(key) && |
806 | auth_key_is_revoked(key->cert->signature_key)) | ||
1102 | return 0; | 807 | return 0; |
1103 | 808 | ||
1104 | success = user_cert_trusted_ca(pw, key); | 809 | success = user_cert_trusted_ca(pw, key); |
@@ -1123,35 +828,6 @@ user_key_allowed(struct passwd *pw, Key *key, int auth_attempt) | |||
1123 | return success; | 828 | return success; |
1124 | } | 829 | } |
1125 | 830 | ||
1126 | /* Records a public key in the list of previously-successful keys */ | ||
1127 | void | ||
1128 | auth2_record_userkey(Authctxt *authctxt, struct sshkey *key) | ||
1129 | { | ||
1130 | struct sshkey **tmp; | ||
1131 | |||
1132 | if (authctxt->nprev_userkeys >= INT_MAX || | ||
1133 | (tmp = reallocarray(authctxt->prev_userkeys, | ||
1134 | authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL) | ||
1135 | fatal("%s: reallocarray failed", __func__); | ||
1136 | authctxt->prev_userkeys = tmp; | ||
1137 | authctxt->prev_userkeys[authctxt->nprev_userkeys] = key; | ||
1138 | authctxt->nprev_userkeys++; | ||
1139 | } | ||
1140 | |||
1141 | /* Checks whether a key has already been used successfully for authentication */ | ||
1142 | int | ||
1143 | auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key) | ||
1144 | { | ||
1145 | u_int i; | ||
1146 | |||
1147 | for (i = 0; i < authctxt->nprev_userkeys; i++) { | ||
1148 | if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) { | ||
1149 | return 1; | ||
1150 | } | ||
1151 | } | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | Authmethod method_pubkey = { | 831 | Authmethod method_pubkey = { |
1156 | "publickey", | 832 | "publickey", |
1157 | userauth_pubkey, | 833 | userauth_pubkey, |