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