xref: /openbsd-src/usr.bin/ssh/auth2-pubkey.c (revision c0dd97bfcad3dab6c31ec12b9de1274fd2d2f993)
1 /* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */
2 /*
3  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <paths.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <time.h>
39 #include <unistd.h>
40 #include <limits.h>
41 
42 #include "xmalloc.h"
43 #include "ssh.h"
44 #include "ssh2.h"
45 #include "packet.h"
46 #include "buffer.h"
47 #include "log.h"
48 #include "misc.h"
49 #include "servconf.h"
50 #include "compat.h"
51 #include "sshkey.h"
52 #include "hostfile.h"
53 #include "auth.h"
54 #include "pathnames.h"
55 #include "uidswap.h"
56 #include "auth-options.h"
57 #include "canohost.h"
58 #ifdef GSSAPI
59 #include "ssh-gss.h"
60 #endif
61 #include "monitor_wrap.h"
62 #include "authfile.h"
63 #include "match.h"
64 #include "ssherr.h"
65 #include "channels.h" /* XXX for session.h */
66 #include "session.h" /* XXX for child_set_env(); refactor? */
67 
68 /* import */
69 extern ServerOptions options;
70 extern u_char *session_id2;
71 extern u_int session_id2_len;
72 
73 static int
74 userauth_pubkey(struct ssh *ssh)
75 {
76 	Authctxt *authctxt = ssh->authctxt;
77 	struct sshbuf *b;
78 	struct sshkey *key = NULL;
79 	char *pkalg, *userstyle = NULL, *fp = NULL;
80 	u_char *pkblob, *sig, have_sig;
81 	size_t blen, slen;
82 	int r, pktype;
83 	int authenticated = 0;
84 
85 	if (!authctxt->valid) {
86 		debug2("%s: disabled because of invalid user", __func__);
87 		return 0;
88 	}
89 	if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0)
90 		fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r));
91 	if (ssh->compat & SSH_BUG_PKAUTH) {
92 		debug2("%s: SSH_BUG_PKAUTH", __func__);
93 		if ((b = sshbuf_new()) == NULL)
94 			fatal("%s: sshbuf_new failed", __func__);
95 		/* no explicit pkalg given */
96 		/* so we have to extract the pkalg from the pkblob */
97 		/* XXX use sshbuf_from() */
98 		if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
99 		    (r = sshbuf_put(b, pkblob, blen)) != 0 ||
100 		    (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0)
101 			fatal("%s: failed: %s", __func__, ssh_err(r));
102 		sshbuf_free(b);
103 	} else {
104 		if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
105 		    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
106 			fatal("%s: sshpkt_get_cstring failed: %s",
107 			    __func__, ssh_err(r));
108 	}
109 	pktype = sshkey_type_from_name(pkalg);
110 	if (pktype == KEY_UNSPEC) {
111 		/* this is perfectly legal */
112 		logit("%s: unsupported public key algorithm: %s",
113 		    __func__, pkalg);
114 		goto done;
115 	}
116 	if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
117 		error("%s: could not parse key: %s", __func__, ssh_err(r));
118 		goto done;
119 	}
120 	if (key == NULL) {
121 		error("%s: cannot decode key: %s", __func__, pkalg);
122 		goto done;
123 	}
124 	if (key->type != pktype) {
125 		error("%s: type mismatch for decoded key "
126 		    "(received %d, expected %d)", __func__, key->type, pktype);
127 		goto done;
128 	}
129 	if (sshkey_type_plain(key->type) == KEY_RSA &&
130 	    (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
131 		logit("Refusing RSA key because client uses unsafe "
132 		    "signature scheme");
133 		goto done;
134 	}
135 	fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
136 	if (auth2_key_already_used(authctxt, key)) {
137 		logit("refusing previously-used %s key", sshkey_type(key));
138 		goto done;
139 	}
140 	if (match_pattern_list(sshkey_ssh_name(key),
141 	    options.pubkey_key_types, 0) != 1) {
142 		logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
143 		    __func__, sshkey_ssh_name(key));
144 		goto done;
145 	}
146 
147 	if (have_sig) {
148 		debug3("%s: have signature for %s %s",
149 		    __func__, sshkey_type(key), fp);
150 		if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
151 		    (r = sshpkt_get_end(ssh)) != 0)
152 			fatal("%s: %s", __func__, ssh_err(r));
153 		if ((b = sshbuf_new()) == NULL)
154 			fatal("%s: sshbuf_new failed", __func__);
155 		if (ssh->compat & SSH_OLD_SESSIONID) {
156 			if ((r = sshbuf_put(b, session_id2,
157 			    session_id2_len)) != 0)
158 				fatal("%s: sshbuf_put session id: %s",
159 				    __func__, ssh_err(r));
160 		} else {
161 			if ((r = sshbuf_put_string(b, session_id2,
162 			    session_id2_len)) != 0)
163 				fatal("%s: sshbuf_put_string session id: %s",
164 				    __func__, ssh_err(r));
165 		}
166 		/* reconstruct packet */
167 		xasprintf(&userstyle, "%s%s%s", authctxt->user,
168 		    authctxt->style ? ":" : "",
169 		    authctxt->style ? authctxt->style : "");
170 		if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
171 		    (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
172 		    (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ?
173 		    "ssh-userauth" : authctxt->service)) != 0)
174 			fatal("%s: build packet failed: %s",
175 			    __func__, ssh_err(r));
176 		if (ssh->compat & SSH_BUG_PKAUTH) {
177 			if ((r = sshbuf_put_u8(b, have_sig)) != 0)
178 				fatal("%s: build packet failed: %s",
179 				    __func__, ssh_err(r));
180 		} else {
181 			if ((r = sshbuf_put_cstring(b, "publickey")) != 0 ||
182 			    (r = sshbuf_put_u8(b, have_sig)) != 0 ||
183 			    (r = sshbuf_put_cstring(b, pkalg) != 0))
184 				fatal("%s: build packet failed: %s",
185 				    __func__, ssh_err(r));
186 		}
187 		if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
188 			fatal("%s: build packet failed: %s",
189 			    __func__, ssh_err(r));
190 #ifdef DEBUG_PK
191 		sshbuf_dump(b, stderr);
192 #endif
193 
194 		/* test for correct signature */
195 		authenticated = 0;
196 		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
197 		    PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
198 		    sshbuf_len(b), ssh->compat)) == 0) {
199 			authenticated = 1;
200 		}
201 		sshbuf_free(b);
202 		free(sig);
203 		auth2_record_key(authctxt, authenticated, key);
204 	} else {
205 		debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
206 		    __func__, sshkey_type(key), fp);
207 		if ((r = sshpkt_get_end(ssh)) != 0)
208 			fatal("%s: %s", __func__, ssh_err(r));
209 
210 		/* XXX fake reply and always send PK_OK ? */
211 		/*
212 		 * XXX this allows testing whether a user is allowed
213 		 * to login: if you happen to have a valid pubkey this
214 		 * message is sent. the message is NEVER sent at all
215 		 * if a user is not allowed to login. is this an
216 		 * issue? -markus
217 		 */
218 		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
219 			if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
220 			    != 0 ||
221 			    (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
222 			    (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
223 			    (r = sshpkt_send(ssh)) != 0)
224 				fatal("%s: %s", __func__, ssh_err(r));
225 			ssh_packet_write_wait(ssh);
226 			authctxt->postponed = 1;
227 		}
228 	}
229 	if (authenticated != 1)
230 		auth_clear_options();
231 done:
232 	debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
233 	sshkey_free(key);
234 	free(userstyle);
235 	free(pkalg);
236 	free(pkblob);
237 	free(fp);
238 	return authenticated;
239 }
240 
241 static int
242 match_principals_option(const char *principal_list, struct sshkey_cert *cert)
243 {
244 	char *result;
245 	u_int i;
246 
247 	/* XXX percent_expand() sequences for authorized_principals? */
248 
249 	for (i = 0; i < cert->nprincipals; i++) {
250 		if ((result = match_list(cert->principals[i],
251 		    principal_list, NULL)) != NULL) {
252 			debug3("matched principal from key options \"%.100s\"",
253 			    result);
254 			free(result);
255 			return 1;
256 		}
257 	}
258 	return 0;
259 }
260 
261 static int
262 process_principals(FILE *f, const char *file, struct passwd *pw,
263     const struct sshkey_cert *cert)
264 {
265 	char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
266 	u_long linenum = 0;
267 	u_int i, found_principal = 0;
268 
269 	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
270 		/* Always consume entire input */
271 		if (found_principal)
272 			continue;
273 		/* Skip leading whitespace. */
274 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
275 			;
276 		/* Skip blank and comment lines. */
277 		if ((ep = strchr(cp, '#')) != NULL)
278 			*ep = '\0';
279 		if (!*cp || *cp == '\n')
280 			continue;
281 		/* Trim trailing whitespace. */
282 		ep = cp + strlen(cp) - 1;
283 		while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
284 			*ep-- = '\0';
285 		/*
286 		 * If the line has internal whitespace then assume it has
287 		 * key options.
288 		 */
289 		line_opts = NULL;
290 		if ((ep = strrchr(cp, ' ')) != NULL ||
291 		    (ep = strrchr(cp, '\t')) != NULL) {
292 			for (; *ep == ' ' || *ep == '\t'; ep++)
293 				;
294 			line_opts = cp;
295 			cp = ep;
296 		}
297 		for (i = 0; i < cert->nprincipals; i++) {
298 			if (strcmp(cp, cert->principals[i]) == 0) {
299 				debug3("%s:%lu: matched principal \"%.100s\"",
300 				    file, linenum, cert->principals[i]);
301 				if (auth_parse_options(pw, line_opts,
302 				    file, linenum) != 1)
303 					continue;
304 				found_principal = 1;
305 				continue;
306 			}
307 		}
308 	}
309 	return found_principal;
310 }
311 
312 static int
313 match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
314 {
315 	FILE *f;
316 	int success;
317 
318 	temporarily_use_uid(pw);
319 	debug("trying authorized principals file %s", file);
320 	if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
321 		restore_uid();
322 		return 0;
323 	}
324 	success = process_principals(f, file, pw, cert);
325 	fclose(f);
326 	restore_uid();
327 	return success;
328 }
329 
330 /*
331  * Checks whether principal is allowed in output of command.
332  * returns 1 if the principal is allowed or 0 otherwise.
333  */
334 static int
335 match_principals_command(struct passwd *user_pw, const struct sshkey *key)
336 {
337 	const struct sshkey_cert *cert = key->cert;
338 	FILE *f = NULL;
339 	int r, ok, found_principal = 0;
340 	struct passwd *pw;
341 	int i, ac = 0, uid_swapped = 0;
342 	pid_t pid;
343 	char *tmp, *username = NULL, *command = NULL, **av = NULL;
344 	char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
345 	char serial_s[16];
346 	void (*osigchld)(int);
347 
348 	if (options.authorized_principals_command == NULL)
349 		return 0;
350 	if (options.authorized_principals_command_user == NULL) {
351 		error("No user for AuthorizedPrincipalsCommand specified, "
352 		    "skipping");
353 		return 0;
354 	}
355 
356 	/*
357 	 * NB. all returns later this function should go via "out" to
358 	 * ensure the original SIGCHLD handler is restored properly.
359 	 */
360 	osigchld = signal(SIGCHLD, SIG_DFL);
361 
362 	/* Prepare and verify the user for the command */
363 	username = percent_expand(options.authorized_principals_command_user,
364 	    "u", user_pw->pw_name, (char *)NULL);
365 	pw = getpwnam(username);
366 	if (pw == NULL) {
367 		error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
368 		    username, strerror(errno));
369 		goto out;
370 	}
371 
372 	/* Turn the command into an argument vector */
373 	if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
374 		error("AuthorizedPrincipalsCommand \"%s\" contains "
375 		    "invalid quotes", command);
376 		goto out;
377 	}
378 	if (ac == 0) {
379 		error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
380 		    command);
381 		goto out;
382 	}
383 	if ((ca_fp = sshkey_fingerprint(cert->signature_key,
384 	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
385 		error("%s: sshkey_fingerprint failed", __func__);
386 		goto out;
387 	}
388 	if ((key_fp = sshkey_fingerprint(key,
389 	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
390 		error("%s: sshkey_fingerprint failed", __func__);
391 		goto out;
392 	}
393 	if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
394 		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
395 		goto out;
396 	}
397 	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
398 		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
399 		goto out;
400 	}
401 	snprintf(serial_s, sizeof(serial_s), "%llu",
402 	    (unsigned long long)cert->serial);
403 	for (i = 1; i < ac; i++) {
404 		tmp = percent_expand(av[i],
405 		    "u", user_pw->pw_name,
406 		    "h", user_pw->pw_dir,
407 		    "t", sshkey_ssh_name(key),
408 		    "T", sshkey_ssh_name(cert->signature_key),
409 		    "f", key_fp,
410 		    "F", ca_fp,
411 		    "k", keytext,
412 		    "K", catext,
413 		    "i", cert->key_id,
414 		    "s", serial_s,
415 		    (char *)NULL);
416 		if (tmp == NULL)
417 			fatal("%s: percent_expand failed", __func__);
418 		free(av[i]);
419 		av[i] = tmp;
420 	}
421 	/* Prepare a printable command for logs, etc. */
422 	command = argv_assemble(ac, av);
423 
424 	if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
425 	    ac, av, &f,
426 	    SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
427 		goto out;
428 
429 	uid_swapped = 1;
430 	temporarily_use_uid(pw);
431 
432 	ok = process_principals(f, "(command)", pw, cert);
433 
434 	fclose(f);
435 	f = NULL;
436 
437 	if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
438 		goto out;
439 
440 	/* Read completed successfully */
441 	found_principal = ok;
442  out:
443 	if (f != NULL)
444 		fclose(f);
445 	signal(SIGCHLD, osigchld);
446 	for (i = 0; i < ac; i++)
447 		free(av[i]);
448 	free(av);
449 	if (uid_swapped)
450 		restore_uid();
451 	free(command);
452 	free(username);
453 	free(ca_fp);
454 	free(key_fp);
455 	free(catext);
456 	free(keytext);
457 	return found_principal;
458 }
459 /*
460  * Checks whether key is allowed in authorized_keys-format file,
461  * returns 1 if the key is allowed or 0 otherwise.
462  */
463 static int
464 check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
465 {
466 	char line[SSH_MAX_PUBKEY_BYTES];
467 	int found_key = 0;
468 	u_long linenum = 0;
469 	struct sshkey *found = NULL;
470 
471 	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
472 		char *cp, *key_options = NULL, *fp = NULL;
473 		const char *reason = NULL;
474 
475 		/* Always consume entire file */
476 		if (found_key)
477 			continue;
478 		if (found != NULL)
479 			sshkey_free(found);
480 		found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
481 		if (found == NULL)
482 			goto done;
483 		auth_clear_options();
484 
485 		/* Skip leading whitespace, empty and comment lines. */
486 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
487 			;
488 		if (!*cp || *cp == '\n' || *cp == '#')
489 			continue;
490 
491 		if (sshkey_read(found, &cp) != 0) {
492 			/* no key?  check if there are options for this key */
493 			int quoted = 0;
494 			debug2("user_key_allowed: check options: '%s'", cp);
495 			key_options = cp;
496 			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
497 				if (*cp == '\\' && cp[1] == '"')
498 					cp++;	/* Skip both */
499 				else if (*cp == '"')
500 					quoted = !quoted;
501 			}
502 			/* Skip remaining whitespace. */
503 			for (; *cp == ' ' || *cp == '\t'; cp++)
504 				;
505 			if (sshkey_read(found, &cp) != 0) {
506 				debug2("user_key_allowed: advance: '%s'", cp);
507 				/* still no key?  advance to next line*/
508 				continue;
509 			}
510 		}
511 		if (sshkey_is_cert(key)) {
512 			if (!sshkey_equal(found, key->cert->signature_key))
513 				continue;
514 			if (auth_parse_options(pw, key_options, file,
515 			    linenum) != 1)
516 				continue;
517 			if (!key_is_cert_authority)
518 				continue;
519 			if ((fp = sshkey_fingerprint(found,
520 			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
521 				continue;
522 			debug("matching CA found: file %s, line %lu, %s %s",
523 			    file, linenum, sshkey_type(found), fp);
524 			/*
525 			 * If the user has specified a list of principals as
526 			 * a key option, then prefer that list to matching
527 			 * their username in the certificate principals list.
528 			 */
529 			if (authorized_principals != NULL &&
530 			    !match_principals_option(authorized_principals,
531 			    key->cert)) {
532 				reason = "Certificate does not contain an "
533 				    "authorized principal";
534  fail_reason:
535 				free(fp);
536 				error("%s", reason);
537 				auth_debug_add("%s", reason);
538 				continue;
539 			}
540 			if (sshkey_cert_check_authority(key, 0, 0,
541 			    authorized_principals == NULL ? pw->pw_name : NULL,
542 			    &reason) != 0)
543 				goto fail_reason;
544 			if (auth_cert_options(key, pw, &reason) != 0)
545 				goto fail_reason;
546 			verbose("Accepted certificate ID \"%s\" (serial %llu) "
547 			    "signed by %s CA %s via %s", key->cert->key_id,
548 			    (unsigned long long)key->cert->serial,
549 			    sshkey_type(found), fp, file);
550 			free(fp);
551 			found_key = 1;
552 			break;
553 		} else if (sshkey_equal(found, key)) {
554 			if (auth_parse_options(pw, key_options, file,
555 			    linenum) != 1)
556 				continue;
557 			if (key_is_cert_authority)
558 				continue;
559 			if ((fp = sshkey_fingerprint(found,
560 			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
561 				continue;
562 			debug("matching key found: file %s, line %lu %s %s",
563 			    file, linenum, sshkey_type(found), fp);
564 			free(fp);
565 			found_key = 1;
566 			continue;
567 		}
568 	}
569  done:
570 	if (found != NULL)
571 		sshkey_free(found);
572 	if (!found_key)
573 		debug2("key not found");
574 	return found_key;
575 }
576 
577 /* Authenticate a certificate key against TrustedUserCAKeys */
578 static int
579 user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
580 {
581 	char *ca_fp, *principals_file = NULL;
582 	const char *reason;
583 	int r, ret = 0, found_principal = 0, use_authorized_principals;
584 
585 	if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
586 		return 0;
587 
588 	if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
589 	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
590 		return 0;
591 
592 	if ((r = sshkey_in_file(key->cert->signature_key,
593 	    options.trusted_user_ca_keys, 1, 0)) != 0) {
594 		debug2("%s: CA %s %s is not listed in %s: %s", __func__,
595 		    sshkey_type(key->cert->signature_key), ca_fp,
596 		    options.trusted_user_ca_keys, ssh_err(r));
597 		goto out;
598 	}
599 	/*
600 	 * If AuthorizedPrincipals is in use, then compare the certificate
601 	 * principals against the names in that file rather than matching
602 	 * against the username.
603 	 */
604 	if ((principals_file = authorized_principals_file(pw)) != NULL) {
605 		if (match_principals_file(principals_file, pw, key->cert))
606 			found_principal = 1;
607 	}
608 	/* Try querying command if specified */
609 	if (!found_principal && match_principals_command(pw, key))
610 		found_principal = 1;
611 	/* If principals file or command is specified, then require a match */
612 	use_authorized_principals = principals_file != NULL ||
613             options.authorized_principals_command != NULL;
614 	if (!found_principal && use_authorized_principals) {
615 		reason = "Certificate does not contain an authorized principal";
616  fail_reason:
617 		error("%s", reason);
618 		auth_debug_add("%s", reason);
619 		goto out;
620 	}
621 	if (sshkey_cert_check_authority(key, 0, 1,
622 	    use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
623 		goto fail_reason;
624 	if (auth_cert_options(key, pw, &reason) != 0)
625 		goto fail_reason;
626 
627 	verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
628 	    "%s CA %s via %s", key->cert->key_id,
629 	    (unsigned long long)key->cert->serial,
630 	    sshkey_type(key->cert->signature_key), ca_fp,
631 	    options.trusted_user_ca_keys);
632 	ret = 1;
633 
634  out:
635 	free(principals_file);
636 	free(ca_fp);
637 	return ret;
638 }
639 
640 /*
641  * Checks whether key is allowed in file.
642  * returns 1 if the key is allowed or 0 otherwise.
643  */
644 static int
645 user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
646 {
647 	FILE *f;
648 	int found_key = 0;
649 
650 	/* Temporarily use the user's uid. */
651 	temporarily_use_uid(pw);
652 
653 	debug("trying public key file %s", file);
654 	if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
655 		found_key = check_authkeys_file(f, file, key, pw);
656 		fclose(f);
657 	}
658 
659 	restore_uid();
660 	return found_key;
661 }
662 
663 /*
664  * Checks whether key is allowed in output of command.
665  * returns 1 if the key is allowed or 0 otherwise.
666  */
667 static int
668 user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
669 {
670 	FILE *f = NULL;
671 	int r, ok, found_key = 0;
672 	struct passwd *pw;
673 	int i, uid_swapped = 0, ac = 0;
674 	pid_t pid;
675 	char *username = NULL, *key_fp = NULL, *keytext = NULL;
676 	char *tmp, *command = NULL, **av = NULL;
677 	void (*osigchld)(int);
678 
679 	if (options.authorized_keys_command == NULL)
680 		return 0;
681 	if (options.authorized_keys_command_user == NULL) {
682 		error("No user for AuthorizedKeysCommand specified, skipping");
683 		return 0;
684 	}
685 
686 	/*
687 	 * NB. all returns later this function should go via "out" to
688 	 * ensure the original SIGCHLD handler is restored properly.
689 	 */
690 	osigchld = signal(SIGCHLD, SIG_DFL);
691 
692 	/* Prepare and verify the user for the command */
693 	username = percent_expand(options.authorized_keys_command_user,
694 	    "u", user_pw->pw_name, (char *)NULL);
695 	pw = getpwnam(username);
696 	if (pw == NULL) {
697 		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
698 		    username, strerror(errno));
699 		goto out;
700 	}
701 
702 	/* Prepare AuthorizedKeysCommand */
703 	if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
704 	    SSH_FP_DEFAULT)) == NULL) {
705 		error("%s: sshkey_fingerprint failed", __func__);
706 		goto out;
707 	}
708 	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
709 		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
710 		goto out;
711 	}
712 
713 	/* Turn the command into an argument vector */
714 	if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
715 		error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
716 		    command);
717 		goto out;
718 	}
719 	if (ac == 0) {
720 		error("AuthorizedKeysCommand \"%s\" yielded no arguments",
721 		    command);
722 		goto out;
723 	}
724 	for (i = 1; i < ac; i++) {
725 		tmp = percent_expand(av[i],
726 		    "u", user_pw->pw_name,
727 		    "h", user_pw->pw_dir,
728 		    "t", sshkey_ssh_name(key),
729 		    "f", key_fp,
730 		    "k", keytext,
731 		    (char *)NULL);
732 		if (tmp == NULL)
733 			fatal("%s: percent_expand failed", __func__);
734 		free(av[i]);
735 		av[i] = tmp;
736 	}
737 	/* Prepare a printable command for logs, etc. */
738 	command = argv_assemble(ac, av);
739 
740 	/*
741 	 * If AuthorizedKeysCommand was run without arguments
742 	 * then fall back to the old behaviour of passing the
743 	 * target username as a single argument.
744 	 */
745 	if (ac == 1) {
746 		av = xreallocarray(av, ac + 2, sizeof(*av));
747 		av[1] = xstrdup(user_pw->pw_name);
748 		av[2] = NULL;
749 		/* Fix up command too, since it is used in log messages */
750 		free(command);
751 		xasprintf(&command, "%s %s", av[0], av[1]);
752 	}
753 
754 	if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
755 	    ac, av, &f,
756 	    SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
757 		goto out;
758 
759 	uid_swapped = 1;
760 	temporarily_use_uid(pw);
761 
762 	ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
763 
764 	fclose(f);
765 	f = NULL;
766 
767 	if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
768 		goto out;
769 
770 	/* Read completed successfully */
771 	found_key = ok;
772  out:
773 	if (f != NULL)
774 		fclose(f);
775 	signal(SIGCHLD, osigchld);
776 	for (i = 0; i < ac; i++)
777 		free(av[i]);
778 	free(av);
779 	if (uid_swapped)
780 		restore_uid();
781 	free(command);
782 	free(username);
783 	free(key_fp);
784 	free(keytext);
785 	return found_key;
786 }
787 
788 /*
789  * Check whether key authenticates and authorises the user.
790  */
791 int
792 user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
793 {
794 	u_int success, i;
795 	char *file;
796 
797 	if (auth_key_is_revoked(key))
798 		return 0;
799 	if (sshkey_is_cert(key) &&
800 	    auth_key_is_revoked(key->cert->signature_key))
801 		return 0;
802 
803 	success = user_cert_trusted_ca(pw, key);
804 	if (success)
805 		return success;
806 
807 	success = user_key_command_allowed2(pw, key);
808 	if (success > 0)
809 		return success;
810 
811 	for (i = 0; !success && i < options.num_authkeys_files; i++) {
812 
813 		if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
814 			continue;
815 		file = expand_authorized_keys(
816 		    options.authorized_keys_files[i], pw);
817 
818 		success = user_key_allowed2(pw, key, file);
819 		free(file);
820 	}
821 
822 	return success;
823 }
824 
825 Authmethod method_pubkey = {
826 	"publickey",
827 	userauth_pubkey,
828 	&options.pubkey_authentication
829 };
830