xref: /dflybsd-src/crypto/openssh/sshconnect2.c (revision ce74baca94b6dd2a80af6a625aba2cf14ab7fec8)
1*ce74bacaSMatthew Dillon /* $OpenBSD: sshconnect2.c,v 1.266 2017/08/27 00:38:41 dtucker Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4cb5eb4f1SPeter Avalos  * Copyright (c) 2008 Damien Miller.  All rights reserved.
518de8d7fSPeter Avalos  *
618de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
718de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
818de8d7fSPeter Avalos  * are met:
918de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1018de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1118de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1218de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1318de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1418de8d7fSPeter Avalos  *
1518de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1618de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1718de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1818de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1918de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2018de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2118de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2218de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2318de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2418de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2518de8d7fSPeter Avalos  */
2618de8d7fSPeter Avalos 
2718de8d7fSPeter Avalos #include "includes.h"
2818de8d7fSPeter Avalos 
2918de8d7fSPeter Avalos #include <sys/types.h>
3018de8d7fSPeter Avalos #include <sys/socket.h>
3118de8d7fSPeter Avalos #include <sys/wait.h>
3218de8d7fSPeter Avalos #include <sys/stat.h>
3318de8d7fSPeter Avalos 
3418de8d7fSPeter Avalos #include <errno.h>
35856ea928SPeter Avalos #include <fcntl.h>
3618de8d7fSPeter Avalos #include <netdb.h>
3718de8d7fSPeter Avalos #include <pwd.h>
3818de8d7fSPeter Avalos #include <signal.h>
3918de8d7fSPeter Avalos #include <stdarg.h>
4018de8d7fSPeter Avalos #include <stdio.h>
4118de8d7fSPeter Avalos #include <string.h>
4218de8d7fSPeter Avalos #include <unistd.h>
4336e94dc5SPeter Avalos #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
4418de8d7fSPeter Avalos #include <vis.h>
4518de8d7fSPeter Avalos #endif
4618de8d7fSPeter Avalos 
4718de8d7fSPeter Avalos #include "openbsd-compat/sys-queue.h"
4818de8d7fSPeter Avalos 
4918de8d7fSPeter Avalos #include "xmalloc.h"
5018de8d7fSPeter Avalos #include "ssh.h"
5118de8d7fSPeter Avalos #include "ssh2.h"
5218de8d7fSPeter Avalos #include "buffer.h"
5318de8d7fSPeter Avalos #include "packet.h"
5418de8d7fSPeter Avalos #include "compat.h"
5518de8d7fSPeter Avalos #include "cipher.h"
5618de8d7fSPeter Avalos #include "key.h"
5718de8d7fSPeter Avalos #include "kex.h"
5818de8d7fSPeter Avalos #include "myproposal.h"
5918de8d7fSPeter Avalos #include "sshconnect.h"
6018de8d7fSPeter Avalos #include "authfile.h"
6118de8d7fSPeter Avalos #include "dh.h"
6218de8d7fSPeter Avalos #include "authfd.h"
6318de8d7fSPeter Avalos #include "log.h"
6418de8d7fSPeter Avalos #include "misc.h"
6536e94dc5SPeter Avalos #include "readconf.h"
6618de8d7fSPeter Avalos #include "match.h"
6718de8d7fSPeter Avalos #include "dispatch.h"
6818de8d7fSPeter Avalos #include "canohost.h"
6918de8d7fSPeter Avalos #include "msg.h"
7018de8d7fSPeter Avalos #include "pathnames.h"
7118de8d7fSPeter Avalos #include "uidswap.h"
729f304aafSPeter Avalos #include "hostfile.h"
73e9778795SPeter Avalos #include "ssherr.h"
74e9778795SPeter Avalos #include "utf8.h"
7518de8d7fSPeter Avalos 
7618de8d7fSPeter Avalos #ifdef GSSAPI
7718de8d7fSPeter Avalos #include "ssh-gss.h"
7818de8d7fSPeter Avalos #endif
7918de8d7fSPeter Avalos 
8018de8d7fSPeter Avalos /* import */
8118de8d7fSPeter Avalos extern char *client_version_string;
8218de8d7fSPeter Avalos extern char *server_version_string;
8318de8d7fSPeter Avalos extern Options options;
8418de8d7fSPeter Avalos 
8518de8d7fSPeter Avalos /*
8618de8d7fSPeter Avalos  * SSH2 key exchange
8718de8d7fSPeter Avalos  */
8818de8d7fSPeter Avalos 
8918de8d7fSPeter Avalos u_char *session_id2 = NULL;
9018de8d7fSPeter Avalos u_int session_id2_len = 0;
9118de8d7fSPeter Avalos 
9218de8d7fSPeter Avalos char *xxx_host;
9318de8d7fSPeter Avalos struct sockaddr *xxx_hostaddr;
9418de8d7fSPeter Avalos 
9518de8d7fSPeter Avalos static int
96*ce74bacaSMatthew Dillon verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
9718de8d7fSPeter Avalos {
9818de8d7fSPeter Avalos 	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
9918de8d7fSPeter Avalos 		fatal("Host key verification failed.");
10018de8d7fSPeter Avalos 	return 0;
10118de8d7fSPeter Avalos }
10218de8d7fSPeter Avalos 
1039f304aafSPeter Avalos static char *
1049f304aafSPeter Avalos order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
1059f304aafSPeter Avalos {
1069f304aafSPeter Avalos 	char *oavail, *avail, *first, *last, *alg, *hostname, *ret;
1079f304aafSPeter Avalos 	size_t maxlen;
1089f304aafSPeter Avalos 	struct hostkeys *hostkeys;
1099f304aafSPeter Avalos 	int ktype;
1101c188a7fSPeter Avalos 	u_int i;
1119f304aafSPeter Avalos 
1129f304aafSPeter Avalos 	/* Find all hostkeys for this hostname */
1139f304aafSPeter Avalos 	get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL);
1149f304aafSPeter Avalos 	hostkeys = init_hostkeys();
1151c188a7fSPeter Avalos 	for (i = 0; i < options.num_user_hostfiles; i++)
1161c188a7fSPeter Avalos 		load_hostkeys(hostkeys, hostname, options.user_hostfiles[i]);
1171c188a7fSPeter Avalos 	for (i = 0; i < options.num_system_hostfiles; i++)
1181c188a7fSPeter Avalos 		load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]);
1199f304aafSPeter Avalos 
1209f304aafSPeter Avalos 	oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG);
1219f304aafSPeter Avalos 	maxlen = strlen(avail) + 1;
1229f304aafSPeter Avalos 	first = xmalloc(maxlen);
1239f304aafSPeter Avalos 	last = xmalloc(maxlen);
1249f304aafSPeter Avalos 	*first = *last = '\0';
1259f304aafSPeter Avalos 
1269f304aafSPeter Avalos #define ALG_APPEND(to, from) \
1279f304aafSPeter Avalos 	do { \
1289f304aafSPeter Avalos 		if (*to != '\0') \
1299f304aafSPeter Avalos 			strlcat(to, ",", maxlen); \
1309f304aafSPeter Avalos 		strlcat(to, from, maxlen); \
1319f304aafSPeter Avalos 	} while (0)
1329f304aafSPeter Avalos 
1339f304aafSPeter Avalos 	while ((alg = strsep(&avail, ",")) && *alg != '\0') {
134e9778795SPeter Avalos 		if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
1359f304aafSPeter Avalos 			fatal("%s: unknown alg %s", __func__, alg);
1369f304aafSPeter Avalos 		if (lookup_key_in_hostkeys_by_type(hostkeys,
137e9778795SPeter Avalos 		    sshkey_type_plain(ktype), NULL))
1389f304aafSPeter Avalos 			ALG_APPEND(first, alg);
1399f304aafSPeter Avalos 		else
1409f304aafSPeter Avalos 			ALG_APPEND(last, alg);
1419f304aafSPeter Avalos 	}
1429f304aafSPeter Avalos #undef ALG_APPEND
143e9778795SPeter Avalos 	xasprintf(&ret, "%s%s%s", first,
144e9778795SPeter Avalos 	    (*first == '\0' || *last == '\0') ? "" : ",", last);
1459f304aafSPeter Avalos 	if (*first != '\0')
1469f304aafSPeter Avalos 		debug3("%s: prefer hostkeyalgs: %s", __func__, first);
1479f304aafSPeter Avalos 
14836e94dc5SPeter Avalos 	free(first);
14936e94dc5SPeter Avalos 	free(last);
15036e94dc5SPeter Avalos 	free(hostname);
15136e94dc5SPeter Avalos 	free(oavail);
1529f304aafSPeter Avalos 	free_hostkeys(hostkeys);
1539f304aafSPeter Avalos 
1549f304aafSPeter Avalos 	return ret;
1559f304aafSPeter Avalos }
1569f304aafSPeter Avalos 
15718de8d7fSPeter Avalos void
1589f304aafSPeter Avalos ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
15918de8d7fSPeter Avalos {
16036e94dc5SPeter Avalos 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
161e9778795SPeter Avalos 	char *s;
162e9778795SPeter Avalos 	struct kex *kex;
163e9778795SPeter Avalos 	int r;
16418de8d7fSPeter Avalos 
16518de8d7fSPeter Avalos 	xxx_host = host;
16618de8d7fSPeter Avalos 	xxx_hostaddr = hostaddr;
16718de8d7fSPeter Avalos 
168e9778795SPeter Avalos 	if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
169e9778795SPeter Avalos 		fatal("%s: kex_names_cat", __func__);
170e9778795SPeter Avalos 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
17118de8d7fSPeter Avalos 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
172e9778795SPeter Avalos 	    compat_cipher_proposal(options.ciphers);
17318de8d7fSPeter Avalos 	myproposal[PROPOSAL_ENC_ALGS_STOC] =
174e9778795SPeter Avalos 	    compat_cipher_proposal(options.ciphers);
17518de8d7fSPeter Avalos 	myproposal[PROPOSAL_COMP_ALGS_CTOS] =
176e9778795SPeter Avalos 	    myproposal[PROPOSAL_COMP_ALGS_STOC] = options.compression ?
177e9778795SPeter Avalos 	    "zlib@openssh.com,zlib,none" : "none,zlib@openssh.com,zlib";
17818de8d7fSPeter Avalos 	myproposal[PROPOSAL_MAC_ALGS_CTOS] =
17918de8d7fSPeter Avalos 	    myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
180e9778795SPeter Avalos 	if (options.hostkeyalgorithms != NULL) {
181e9778795SPeter Avalos 		if (kex_assemble_names(KEX_DEFAULT_PK_ALG,
182e9778795SPeter Avalos 		    &options.hostkeyalgorithms) != 0)
183e9778795SPeter Avalos 			fatal("%s: kex_assemble_namelist", __func__);
18418de8d7fSPeter Avalos 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
18536e94dc5SPeter Avalos 		    compat_pkalg_proposal(options.hostkeyalgorithms);
186e9778795SPeter Avalos 	} else {
187e9778795SPeter Avalos 		/* Enforce default */
188e9778795SPeter Avalos 		options.hostkeyalgorithms = xstrdup(KEX_DEFAULT_PK_ALG);
1899f304aafSPeter Avalos 		/* Prefer algorithms that we already have keys for */
1909f304aafSPeter Avalos 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
19136e94dc5SPeter Avalos 		    compat_pkalg_proposal(
19236e94dc5SPeter Avalos 		    order_hostkeyalgs(host, hostaddr, port));
1939f304aafSPeter Avalos 	}
19418de8d7fSPeter Avalos 
19536e94dc5SPeter Avalos 	if (options.rekey_limit || options.rekey_interval)
196*ce74bacaSMatthew Dillon 		packet_set_rekey_limits(options.rekey_limit,
197*ce74bacaSMatthew Dillon 		    options.rekey_interval);
19818de8d7fSPeter Avalos 
19918de8d7fSPeter Avalos 	/* start key exchange */
200e9778795SPeter Avalos 	if ((r = kex_setup(active_state, myproposal)) != 0)
201e9778795SPeter Avalos 		fatal("kex_setup: %s", ssh_err(r));
202e9778795SPeter Avalos 	kex = active_state->kex;
20336e94dc5SPeter Avalos #ifdef WITH_OPENSSL
20418de8d7fSPeter Avalos 	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
20518de8d7fSPeter Avalos 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
206e9778795SPeter Avalos 	kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client;
207e9778795SPeter Avalos 	kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client;
208e9778795SPeter Avalos 	kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client;
20918de8d7fSPeter Avalos 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
21018de8d7fSPeter Avalos 	kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
211e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC
2129f304aafSPeter Avalos 	kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
21336e94dc5SPeter Avalos # endif
214e9778795SPeter Avalos #endif
21536e94dc5SPeter Avalos 	kex->kex[KEX_C25519_SHA256] = kexc25519_client;
21618de8d7fSPeter Avalos 	kex->client_version_string=client_version_string;
21718de8d7fSPeter Avalos 	kex->server_version_string=server_version_string;
21818de8d7fSPeter Avalos 	kex->verify_host_key=&verify_host_key_callback;
21918de8d7fSPeter Avalos 
220*ce74bacaSMatthew Dillon 	ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done);
22118de8d7fSPeter Avalos 
222e9778795SPeter Avalos 	/* remove ext-info from the KEX proposals for rekeying */
223e9778795SPeter Avalos 	myproposal[PROPOSAL_KEX_ALGS] =
224e9778795SPeter Avalos 	    compat_kex_proposal(options.kex_algorithms);
225e9778795SPeter Avalos 	if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
226e9778795SPeter Avalos 		fatal("kex_prop2buf: %s", ssh_err(r));
227856ea928SPeter Avalos 
22818de8d7fSPeter Avalos 	session_id2 = kex->session_id;
22918de8d7fSPeter Avalos 	session_id2_len = kex->session_id_len;
23018de8d7fSPeter Avalos 
23118de8d7fSPeter Avalos #ifdef DEBUG_KEXDH
23218de8d7fSPeter Avalos 	/* send 1st encrypted/maced/compressed message */
23318de8d7fSPeter Avalos 	packet_start(SSH2_MSG_IGNORE);
23418de8d7fSPeter Avalos 	packet_put_cstring("markus");
23518de8d7fSPeter Avalos 	packet_send();
23618de8d7fSPeter Avalos 	packet_write_wait();
23718de8d7fSPeter Avalos #endif
23818de8d7fSPeter Avalos }
23918de8d7fSPeter Avalos 
24018de8d7fSPeter Avalos /*
24118de8d7fSPeter Avalos  * Authenticate user
24218de8d7fSPeter Avalos  */
24318de8d7fSPeter Avalos 
244e9778795SPeter Avalos typedef struct cauthctxt Authctxt;
245e9778795SPeter Avalos typedef struct cauthmethod Authmethod;
24618de8d7fSPeter Avalos typedef struct identity Identity;
24718de8d7fSPeter Avalos typedef struct idlist Idlist;
24818de8d7fSPeter Avalos 
24918de8d7fSPeter Avalos struct identity {
25018de8d7fSPeter Avalos 	TAILQ_ENTRY(identity) next;
251e9778795SPeter Avalos 	int	agent_fd;		/* >=0 if agent supports key */
252e9778795SPeter Avalos 	struct sshkey	*key;		/* public/private key */
25318de8d7fSPeter Avalos 	char	*filename;		/* comment for agent-only keys */
25418de8d7fSPeter Avalos 	int	tried;
25518de8d7fSPeter Avalos 	int	isprivate;		/* key points to the private key */
25636e94dc5SPeter Avalos 	int	userprovided;
25718de8d7fSPeter Avalos };
25818de8d7fSPeter Avalos TAILQ_HEAD(idlist, identity);
25918de8d7fSPeter Avalos 
260e9778795SPeter Avalos struct cauthctxt {
26118de8d7fSPeter Avalos 	const char *server_user;
26218de8d7fSPeter Avalos 	const char *local_user;
26318de8d7fSPeter Avalos 	const char *host;
26418de8d7fSPeter Avalos 	const char *service;
265e9778795SPeter Avalos 	struct cauthmethod *method;
266856ea928SPeter Avalos 	sig_atomic_t success;
26718de8d7fSPeter Avalos 	char *authlist;
268e9778795SPeter Avalos 	int attempt;
26918de8d7fSPeter Avalos 	/* pubkey */
270e9778795SPeter Avalos 	struct idlist keys;
271e9778795SPeter Avalos 	int agent_fd;
27218de8d7fSPeter Avalos 	/* hostbased */
27318de8d7fSPeter Avalos 	Sensitive *sensitive;
274e9778795SPeter Avalos 	char *oktypes, *ktypes;
275e9778795SPeter Avalos 	const char *active_ktype;
27618de8d7fSPeter Avalos 	/* kbd-interactive */
27718de8d7fSPeter Avalos 	int info_req_seen;
27818de8d7fSPeter Avalos 	/* generic */
27918de8d7fSPeter Avalos 	void *methoddata;
28018de8d7fSPeter Avalos };
281e9778795SPeter Avalos 
282e9778795SPeter Avalos struct cauthmethod {
28318de8d7fSPeter Avalos 	char	*name;		/* string to compare against server's list */
28418de8d7fSPeter Avalos 	int	(*userauth)(Authctxt *authctxt);
285cb5eb4f1SPeter Avalos 	void	(*cleanup)(Authctxt *authctxt);
28618de8d7fSPeter Avalos 	int	*enabled;	/* flag in option struct that enables method */
28718de8d7fSPeter Avalos 	int	*batch_flag;	/* flag in option struct that disables method */
28818de8d7fSPeter Avalos };
28918de8d7fSPeter Avalos 
290*ce74bacaSMatthew Dillon int	input_userauth_service_accept(int, u_int32_t, struct ssh *);
291*ce74bacaSMatthew Dillon int	input_userauth_ext_info(int, u_int32_t, struct ssh *);
292*ce74bacaSMatthew Dillon int	input_userauth_success(int, u_int32_t, struct ssh *);
293*ce74bacaSMatthew Dillon int	input_userauth_success_unexpected(int, u_int32_t, struct ssh *);
294*ce74bacaSMatthew Dillon int	input_userauth_failure(int, u_int32_t, struct ssh *);
295*ce74bacaSMatthew Dillon int	input_userauth_banner(int, u_int32_t, struct ssh *);
296*ce74bacaSMatthew Dillon int	input_userauth_error(int, u_int32_t, struct ssh *);
297*ce74bacaSMatthew Dillon int	input_userauth_info_req(int, u_int32_t, struct ssh *);
298*ce74bacaSMatthew Dillon int	input_userauth_pk_ok(int, u_int32_t, struct ssh *);
299*ce74bacaSMatthew Dillon int	input_userauth_passwd_changereq(int, u_int32_t, struct ssh *);
30018de8d7fSPeter Avalos 
30118de8d7fSPeter Avalos int	userauth_none(Authctxt *);
30218de8d7fSPeter Avalos int	userauth_pubkey(Authctxt *);
30318de8d7fSPeter Avalos int	userauth_passwd(Authctxt *);
30418de8d7fSPeter Avalos int	userauth_kbdint(Authctxt *);
30518de8d7fSPeter Avalos int	userauth_hostbased(Authctxt *);
30618de8d7fSPeter Avalos 
30718de8d7fSPeter Avalos #ifdef GSSAPI
30818de8d7fSPeter Avalos int	userauth_gssapi(Authctxt *authctxt);
309*ce74bacaSMatthew Dillon int	input_gssapi_response(int type, u_int32_t, struct ssh *);
310*ce74bacaSMatthew Dillon int	input_gssapi_token(int type, u_int32_t, struct ssh *);
311*ce74bacaSMatthew Dillon int	input_gssapi_hash(int type, u_int32_t, struct ssh *);
312*ce74bacaSMatthew Dillon int	input_gssapi_error(int, u_int32_t, struct ssh *);
313*ce74bacaSMatthew Dillon int	input_gssapi_errtok(int, u_int32_t, struct ssh *);
31418de8d7fSPeter Avalos #endif
31518de8d7fSPeter Avalos 
31618de8d7fSPeter Avalos void	userauth(Authctxt *, char *);
31718de8d7fSPeter Avalos 
31818de8d7fSPeter Avalos static int sign_and_send_pubkey(Authctxt *, Identity *);
31918de8d7fSPeter Avalos static void pubkey_prepare(Authctxt *);
32018de8d7fSPeter Avalos static void pubkey_cleanup(Authctxt *);
321*ce74bacaSMatthew Dillon static void pubkey_reset(Authctxt *);
322*ce74bacaSMatthew Dillon static struct sshkey *load_identity_file(Identity *);
32318de8d7fSPeter Avalos 
32418de8d7fSPeter Avalos static Authmethod *authmethod_get(char *authlist);
32518de8d7fSPeter Avalos static Authmethod *authmethod_lookup(const char *name);
32618de8d7fSPeter Avalos static char *authmethods_get(void);
32718de8d7fSPeter Avalos 
32818de8d7fSPeter Avalos Authmethod authmethods[] = {
32918de8d7fSPeter Avalos #ifdef GSSAPI
33018de8d7fSPeter Avalos 	{"gssapi-with-mic",
33118de8d7fSPeter Avalos 		userauth_gssapi,
332cb5eb4f1SPeter Avalos 		NULL,
33318de8d7fSPeter Avalos 		&options.gss_authentication,
33418de8d7fSPeter Avalos 		NULL},
33518de8d7fSPeter Avalos #endif
33618de8d7fSPeter Avalos 	{"hostbased",
33718de8d7fSPeter Avalos 		userauth_hostbased,
338cb5eb4f1SPeter Avalos 		NULL,
33918de8d7fSPeter Avalos 		&options.hostbased_authentication,
34018de8d7fSPeter Avalos 		NULL},
34118de8d7fSPeter Avalos 	{"publickey",
34218de8d7fSPeter Avalos 		userauth_pubkey,
343cb5eb4f1SPeter Avalos 		NULL,
34418de8d7fSPeter Avalos 		&options.pubkey_authentication,
34518de8d7fSPeter Avalos 		NULL},
34618de8d7fSPeter Avalos 	{"keyboard-interactive",
34718de8d7fSPeter Avalos 		userauth_kbdint,
348cb5eb4f1SPeter Avalos 		NULL,
34918de8d7fSPeter Avalos 		&options.kbd_interactive_authentication,
35018de8d7fSPeter Avalos 		&options.batch_mode},
35118de8d7fSPeter Avalos 	{"password",
35218de8d7fSPeter Avalos 		userauth_passwd,
353cb5eb4f1SPeter Avalos 		NULL,
35418de8d7fSPeter Avalos 		&options.password_authentication,
35518de8d7fSPeter Avalos 		&options.batch_mode},
35618de8d7fSPeter Avalos 	{"none",
35718de8d7fSPeter Avalos 		userauth_none,
35818de8d7fSPeter Avalos 		NULL,
359cb5eb4f1SPeter Avalos 		NULL,
36018de8d7fSPeter Avalos 		NULL},
361cb5eb4f1SPeter Avalos 	{NULL, NULL, NULL, NULL, NULL}
36218de8d7fSPeter Avalos };
36318de8d7fSPeter Avalos 
36418de8d7fSPeter Avalos void
36518de8d7fSPeter Avalos ssh_userauth2(const char *local_user, const char *server_user, char *host,
36618de8d7fSPeter Avalos     Sensitive *sensitive)
36718de8d7fSPeter Avalos {
368e9778795SPeter Avalos 	struct ssh *ssh = active_state;
36918de8d7fSPeter Avalos 	Authctxt authctxt;
370e9778795SPeter Avalos 	int r;
37118de8d7fSPeter Avalos 
37218de8d7fSPeter Avalos 	if (options.challenge_response_authentication)
37318de8d7fSPeter Avalos 		options.kbd_interactive_authentication = 1;
37418de8d7fSPeter Avalos 	if (options.preferred_authentications == NULL)
37518de8d7fSPeter Avalos 		options.preferred_authentications = authmethods_get();
37618de8d7fSPeter Avalos 
37718de8d7fSPeter Avalos 	/* setup authentication context */
37818de8d7fSPeter Avalos 	memset(&authctxt, 0, sizeof(authctxt));
37918de8d7fSPeter Avalos 	pubkey_prepare(&authctxt);
38018de8d7fSPeter Avalos 	authctxt.server_user = server_user;
38118de8d7fSPeter Avalos 	authctxt.local_user = local_user;
38218de8d7fSPeter Avalos 	authctxt.host = host;
38318de8d7fSPeter Avalos 	authctxt.service = "ssh-connection";		/* service name */
38418de8d7fSPeter Avalos 	authctxt.success = 0;
38518de8d7fSPeter Avalos 	authctxt.method = authmethod_lookup("none");
38618de8d7fSPeter Avalos 	authctxt.authlist = NULL;
38718de8d7fSPeter Avalos 	authctxt.methoddata = NULL;
38818de8d7fSPeter Avalos 	authctxt.sensitive = sensitive;
389e9778795SPeter Avalos 	authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL;
39018de8d7fSPeter Avalos 	authctxt.info_req_seen = 0;
391e9778795SPeter Avalos 	authctxt.agent_fd = -1;
39218de8d7fSPeter Avalos 	if (authctxt.method == NULL)
39318de8d7fSPeter Avalos 		fatal("ssh_userauth2: internal error: cannot send userauth none request");
39418de8d7fSPeter Avalos 
395e9778795SPeter Avalos 	if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
396e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
397e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0)
398e9778795SPeter Avalos 		fatal("%s: %s", __func__, ssh_err(r));
39918de8d7fSPeter Avalos 
400*ce74bacaSMatthew Dillon 	ssh->authctxt = &authctxt;
401e9778795SPeter Avalos 	ssh_dispatch_init(ssh, &input_userauth_error);
402e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
403e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
404*ce74bacaSMatthew Dillon 	ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success);	/* loop until success */
405*ce74bacaSMatthew Dillon 	ssh->authctxt = NULL;
40618de8d7fSPeter Avalos 
40718de8d7fSPeter Avalos 	pubkey_cleanup(&authctxt);
408e9778795SPeter Avalos 	ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
40918de8d7fSPeter Avalos 
410*ce74bacaSMatthew Dillon 	if (!authctxt.success)
411*ce74bacaSMatthew Dillon 		fatal("Authentication failed.");
41218de8d7fSPeter Avalos 	debug("Authentication succeeded (%s).", authctxt.method->name);
41318de8d7fSPeter Avalos }
41418de8d7fSPeter Avalos 
415e9778795SPeter Avalos /* ARGSUSED */
416e9778795SPeter Avalos int
417*ce74bacaSMatthew Dillon input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
418e9778795SPeter Avalos {
419*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
420e9778795SPeter Avalos 	int r;
421e9778795SPeter Avalos 
422e9778795SPeter Avalos 	if (ssh_packet_remaining(ssh) > 0) {
423e9778795SPeter Avalos 		char *reply;
424e9778795SPeter Avalos 
425e9778795SPeter Avalos 		if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0)
426e9778795SPeter Avalos 			goto out;
427e9778795SPeter Avalos 		debug2("service_accept: %s", reply);
428e9778795SPeter Avalos 		free(reply);
429e9778795SPeter Avalos 	} else {
430e9778795SPeter Avalos 		debug2("buggy server: service_accept w/o service");
431e9778795SPeter Avalos 	}
432e9778795SPeter Avalos 	if ((r = sshpkt_get_end(ssh)) != 0)
433e9778795SPeter Avalos 		goto out;
434e9778795SPeter Avalos 	debug("SSH2_MSG_SERVICE_ACCEPT received");
435e9778795SPeter Avalos 
436e9778795SPeter Avalos 	/* initial userauth request */
437e9778795SPeter Avalos 	userauth_none(authctxt);
438e9778795SPeter Avalos 
439e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
440e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
441e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
442e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
443e9778795SPeter Avalos 	r = 0;
444e9778795SPeter Avalos  out:
445e9778795SPeter Avalos 	return r;
446e9778795SPeter Avalos }
447e9778795SPeter Avalos 
448e9778795SPeter Avalos /* ARGSUSED */
449e9778795SPeter Avalos int
450*ce74bacaSMatthew Dillon input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
451e9778795SPeter Avalos {
452*ce74bacaSMatthew Dillon 	return kex_input_ext_info(type, seqnr, ssh);
453e9778795SPeter Avalos }
454e9778795SPeter Avalos 
45518de8d7fSPeter Avalos void
45618de8d7fSPeter Avalos userauth(Authctxt *authctxt, char *authlist)
45718de8d7fSPeter Avalos {
458cb5eb4f1SPeter Avalos 	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
459cb5eb4f1SPeter Avalos 		authctxt->method->cleanup(authctxt);
460cb5eb4f1SPeter Avalos 
46136e94dc5SPeter Avalos 	free(authctxt->methoddata);
46218de8d7fSPeter Avalos 	authctxt->methoddata = NULL;
46318de8d7fSPeter Avalos 	if (authlist == NULL) {
46418de8d7fSPeter Avalos 		authlist = authctxt->authlist;
46518de8d7fSPeter Avalos 	} else {
46636e94dc5SPeter Avalos 		free(authctxt->authlist);
46718de8d7fSPeter Avalos 		authctxt->authlist = authlist;
46818de8d7fSPeter Avalos 	}
46918de8d7fSPeter Avalos 	for (;;) {
47018de8d7fSPeter Avalos 		Authmethod *method = authmethod_get(authlist);
47118de8d7fSPeter Avalos 		if (method == NULL)
472*ce74bacaSMatthew Dillon 			fatal("%s@%s: Permission denied (%s).",
473*ce74bacaSMatthew Dillon 			    authctxt->server_user, authctxt->host, authlist);
47418de8d7fSPeter Avalos 		authctxt->method = method;
47518de8d7fSPeter Avalos 
47618de8d7fSPeter Avalos 		/* reset the per method handler */
47718de8d7fSPeter Avalos 		dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
47818de8d7fSPeter Avalos 		    SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
47918de8d7fSPeter Avalos 
48018de8d7fSPeter Avalos 		/* and try new method */
48118de8d7fSPeter Avalos 		if (method->userauth(authctxt) != 0) {
48218de8d7fSPeter Avalos 			debug2("we sent a %s packet, wait for reply", method->name);
48318de8d7fSPeter Avalos 			break;
48418de8d7fSPeter Avalos 		} else {
48518de8d7fSPeter Avalos 			debug2("we did not send a packet, disable method");
48618de8d7fSPeter Avalos 			method->enabled = NULL;
48718de8d7fSPeter Avalos 		}
48818de8d7fSPeter Avalos 	}
48918de8d7fSPeter Avalos }
49018de8d7fSPeter Avalos 
491cb5eb4f1SPeter Avalos /* ARGSUSED */
492e9778795SPeter Avalos int
493*ce74bacaSMatthew Dillon input_userauth_error(int type, u_int32_t seq, struct ssh *ssh)
49418de8d7fSPeter Avalos {
49518de8d7fSPeter Avalos 	fatal("input_userauth_error: bad message during authentication: "
49618de8d7fSPeter Avalos 	    "type %d", type);
497e9778795SPeter Avalos 	return 0;
49818de8d7fSPeter Avalos }
49918de8d7fSPeter Avalos 
500cb5eb4f1SPeter Avalos /* ARGSUSED */
501e9778795SPeter Avalos int
502*ce74bacaSMatthew Dillon input_userauth_banner(int type, u_int32_t seq, struct ssh *ssh)
50318de8d7fSPeter Avalos {
504e9778795SPeter Avalos 	char *msg, *lang;
50518de8d7fSPeter Avalos 	u_int len;
50618de8d7fSPeter Avalos 
507e9778795SPeter Avalos 	debug3("%s", __func__);
508e9778795SPeter Avalos 	msg = packet_get_string(&len);
50918de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
510e9778795SPeter Avalos 	if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO)
511e9778795SPeter Avalos 		fmprintf(stderr, "%s", msg);
51236e94dc5SPeter Avalos 	free(msg);
51336e94dc5SPeter Avalos 	free(lang);
514e9778795SPeter Avalos 	return 0;
51518de8d7fSPeter Avalos }
51618de8d7fSPeter Avalos 
517cb5eb4f1SPeter Avalos /* ARGSUSED */
518e9778795SPeter Avalos int
519*ce74bacaSMatthew Dillon input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
52018de8d7fSPeter Avalos {
521*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
522856ea928SPeter Avalos 
52318de8d7fSPeter Avalos 	if (authctxt == NULL)
52418de8d7fSPeter Avalos 		fatal("input_userauth_success: no authentication context");
52536e94dc5SPeter Avalos 	free(authctxt->authlist);
52618de8d7fSPeter Avalos 	authctxt->authlist = NULL;
527856ea928SPeter Avalos 	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
528856ea928SPeter Avalos 		authctxt->method->cleanup(authctxt);
52936e94dc5SPeter Avalos 	free(authctxt->methoddata);
53018de8d7fSPeter Avalos 	authctxt->methoddata = NULL;
53118de8d7fSPeter Avalos 	authctxt->success = 1;			/* break out */
532e9778795SPeter Avalos 	return 0;
53318de8d7fSPeter Avalos }
53418de8d7fSPeter Avalos 
535e9778795SPeter Avalos int
536*ce74bacaSMatthew Dillon input_userauth_success_unexpected(int type, u_int32_t seq, struct ssh *ssh)
537856ea928SPeter Avalos {
538*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
539856ea928SPeter Avalos 
540856ea928SPeter Avalos 	if (authctxt == NULL)
541856ea928SPeter Avalos 		fatal("%s: no authentication context", __func__);
542856ea928SPeter Avalos 
543856ea928SPeter Avalos 	fatal("Unexpected authentication success during %s.",
544856ea928SPeter Avalos 	    authctxt->method->name);
545e9778795SPeter Avalos 	return 0;
546856ea928SPeter Avalos }
547856ea928SPeter Avalos 
548cb5eb4f1SPeter Avalos /* ARGSUSED */
549e9778795SPeter Avalos int
550*ce74bacaSMatthew Dillon input_userauth_failure(int type, u_int32_t seq, struct ssh *ssh)
55118de8d7fSPeter Avalos {
552*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
55318de8d7fSPeter Avalos 	char *authlist = NULL;
55418de8d7fSPeter Avalos 	int partial;
55518de8d7fSPeter Avalos 
55618de8d7fSPeter Avalos 	if (authctxt == NULL)
55718de8d7fSPeter Avalos 		fatal("input_userauth_failure: no authentication context");
55818de8d7fSPeter Avalos 
55918de8d7fSPeter Avalos 	authlist = packet_get_string(NULL);
56018de8d7fSPeter Avalos 	partial = packet_get_char();
56118de8d7fSPeter Avalos 	packet_check_eom();
56218de8d7fSPeter Avalos 
56336e94dc5SPeter Avalos 	if (partial != 0) {
564e9778795SPeter Avalos 		verbose("Authenticated with partial success.");
56536e94dc5SPeter Avalos 		/* reset state */
566*ce74bacaSMatthew Dillon 		pubkey_reset(authctxt);
56736e94dc5SPeter Avalos 	}
56818de8d7fSPeter Avalos 	debug("Authentications that can continue: %s", authlist);
56918de8d7fSPeter Avalos 
57018de8d7fSPeter Avalos 	userauth(authctxt, authlist);
571e9778795SPeter Avalos 	return 0;
57218de8d7fSPeter Avalos }
573cb5eb4f1SPeter Avalos 
574cb5eb4f1SPeter Avalos /* ARGSUSED */
575e9778795SPeter Avalos int
576*ce74bacaSMatthew Dillon input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh)
57718de8d7fSPeter Avalos {
578*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
579*ce74bacaSMatthew Dillon 	struct sshkey *key = NULL;
58018de8d7fSPeter Avalos 	Identity *id = NULL;
58118de8d7fSPeter Avalos 	Buffer b;
58218de8d7fSPeter Avalos 	int pktype, sent = 0;
58318de8d7fSPeter Avalos 	u_int alen, blen;
58418de8d7fSPeter Avalos 	char *pkalg, *fp;
58518de8d7fSPeter Avalos 	u_char *pkblob;
58618de8d7fSPeter Avalos 
58718de8d7fSPeter Avalos 	if (authctxt == NULL)
58818de8d7fSPeter Avalos 		fatal("input_userauth_pk_ok: no authentication context");
58918de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKOK) {
59018de8d7fSPeter Avalos 		/* this is similar to SSH_BUG_PKAUTH */
59118de8d7fSPeter Avalos 		debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
59218de8d7fSPeter Avalos 		pkblob = packet_get_string(&blen);
59318de8d7fSPeter Avalos 		buffer_init(&b);
59418de8d7fSPeter Avalos 		buffer_append(&b, pkblob, blen);
59518de8d7fSPeter Avalos 		pkalg = buffer_get_string(&b, &alen);
59618de8d7fSPeter Avalos 		buffer_free(&b);
59718de8d7fSPeter Avalos 	} else {
59818de8d7fSPeter Avalos 		pkalg = packet_get_string(&alen);
59918de8d7fSPeter Avalos 		pkblob = packet_get_string(&blen);
60018de8d7fSPeter Avalos 	}
60118de8d7fSPeter Avalos 	packet_check_eom();
60218de8d7fSPeter Avalos 
60318de8d7fSPeter Avalos 	debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
60418de8d7fSPeter Avalos 
60518de8d7fSPeter Avalos 	if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
60618de8d7fSPeter Avalos 		debug("unknown pkalg %s", pkalg);
60718de8d7fSPeter Avalos 		goto done;
60818de8d7fSPeter Avalos 	}
60918de8d7fSPeter Avalos 	if ((key = key_from_blob(pkblob, blen)) == NULL) {
61018de8d7fSPeter Avalos 		debug("no key from blob. pkalg %s", pkalg);
61118de8d7fSPeter Avalos 		goto done;
61218de8d7fSPeter Avalos 	}
61318de8d7fSPeter Avalos 	if (key->type != pktype) {
61418de8d7fSPeter Avalos 		error("input_userauth_pk_ok: type mismatch "
61518de8d7fSPeter Avalos 		    "for decoded key (received %d, expected %d)",
61618de8d7fSPeter Avalos 		    key->type, pktype);
61718de8d7fSPeter Avalos 		goto done;
61818de8d7fSPeter Avalos 	}
619e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
620e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL)
621e9778795SPeter Avalos 		goto done;
62218de8d7fSPeter Avalos 	debug2("input_userauth_pk_ok: fp %s", fp);
62336e94dc5SPeter Avalos 	free(fp);
62418de8d7fSPeter Avalos 
62518de8d7fSPeter Avalos 	/*
62618de8d7fSPeter Avalos 	 * search keys in the reverse order, because last candidate has been
62718de8d7fSPeter Avalos 	 * moved to the end of the queue.  this also avoids confusion by
62818de8d7fSPeter Avalos 	 * duplicate keys
62918de8d7fSPeter Avalos 	 */
63018de8d7fSPeter Avalos 	TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
63118de8d7fSPeter Avalos 		if (key_equal(key, id->key)) {
63218de8d7fSPeter Avalos 			sent = sign_and_send_pubkey(authctxt, id);
63318de8d7fSPeter Avalos 			break;
63418de8d7fSPeter Avalos 		}
63518de8d7fSPeter Avalos 	}
63618de8d7fSPeter Avalos done:
63718de8d7fSPeter Avalos 	if (key != NULL)
63818de8d7fSPeter Avalos 		key_free(key);
63936e94dc5SPeter Avalos 	free(pkalg);
64036e94dc5SPeter Avalos 	free(pkblob);
64118de8d7fSPeter Avalos 
64218de8d7fSPeter Avalos 	/* try another method if we did not send a packet */
64318de8d7fSPeter Avalos 	if (sent == 0)
64418de8d7fSPeter Avalos 		userauth(authctxt, NULL);
645e9778795SPeter Avalos 	return 0;
64618de8d7fSPeter Avalos }
64718de8d7fSPeter Avalos 
64818de8d7fSPeter Avalos #ifdef GSSAPI
64918de8d7fSPeter Avalos int
65018de8d7fSPeter Avalos userauth_gssapi(Authctxt *authctxt)
65118de8d7fSPeter Avalos {
65218de8d7fSPeter Avalos 	Gssctxt *gssctxt = NULL;
65318de8d7fSPeter Avalos 	static gss_OID_set gss_supported = NULL;
65418de8d7fSPeter Avalos 	static u_int mech = 0;
65518de8d7fSPeter Avalos 	OM_uint32 min;
65618de8d7fSPeter Avalos 	int ok = 0;
65718de8d7fSPeter Avalos 
65818de8d7fSPeter Avalos 	/* Try one GSSAPI method at a time, rather than sending them all at
65918de8d7fSPeter Avalos 	 * once. */
66018de8d7fSPeter Avalos 
66118de8d7fSPeter Avalos 	if (gss_supported == NULL)
66218de8d7fSPeter Avalos 		gss_indicate_mechs(&min, &gss_supported);
66318de8d7fSPeter Avalos 
66418de8d7fSPeter Avalos 	/* Check to see if the mechanism is usable before we offer it */
66518de8d7fSPeter Avalos 	while (mech < gss_supported->count && !ok) {
66618de8d7fSPeter Avalos 		/* My DER encoding requires length<128 */
66718de8d7fSPeter Avalos 		if (gss_supported->elements[mech].length < 128 &&
66818de8d7fSPeter Avalos 		    ssh_gssapi_check_mechanism(&gssctxt,
66918de8d7fSPeter Avalos 		    &gss_supported->elements[mech], authctxt->host)) {
67018de8d7fSPeter Avalos 			ok = 1; /* Mechanism works */
67118de8d7fSPeter Avalos 		} else {
67218de8d7fSPeter Avalos 			mech++;
67318de8d7fSPeter Avalos 		}
67418de8d7fSPeter Avalos 	}
67518de8d7fSPeter Avalos 
67618de8d7fSPeter Avalos 	if (!ok)
67718de8d7fSPeter Avalos 		return 0;
67818de8d7fSPeter Avalos 
67918de8d7fSPeter Avalos 	authctxt->methoddata=(void *)gssctxt;
68018de8d7fSPeter Avalos 
68118de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
68218de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
68318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
68418de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
68518de8d7fSPeter Avalos 
68618de8d7fSPeter Avalos 	packet_put_int(1);
68718de8d7fSPeter Avalos 
68818de8d7fSPeter Avalos 	packet_put_int((gss_supported->elements[mech].length) + 2);
68918de8d7fSPeter Avalos 	packet_put_char(SSH_GSS_OIDTYPE);
69018de8d7fSPeter Avalos 	packet_put_char(gss_supported->elements[mech].length);
69118de8d7fSPeter Avalos 	packet_put_raw(gss_supported->elements[mech].elements,
69218de8d7fSPeter Avalos 	    gss_supported->elements[mech].length);
69318de8d7fSPeter Avalos 
69418de8d7fSPeter Avalos 	packet_send();
69518de8d7fSPeter Avalos 
69618de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
69718de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
69818de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
69918de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
70018de8d7fSPeter Avalos 
70118de8d7fSPeter Avalos 	mech++; /* Move along to next candidate */
70218de8d7fSPeter Avalos 
70318de8d7fSPeter Avalos 	return 1;
70418de8d7fSPeter Avalos }
70518de8d7fSPeter Avalos 
70618de8d7fSPeter Avalos static OM_uint32
707*ce74bacaSMatthew Dillon process_gssapi_token(struct ssh *ssh, gss_buffer_t recv_tok)
70818de8d7fSPeter Avalos {
709*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
71018de8d7fSPeter Avalos 	Gssctxt *gssctxt = authctxt->methoddata;
71118de8d7fSPeter Avalos 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
71218de8d7fSPeter Avalos 	gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
71318de8d7fSPeter Avalos 	gss_buffer_desc gssbuf;
71418de8d7fSPeter Avalos 	OM_uint32 status, ms, flags;
71518de8d7fSPeter Avalos 	Buffer b;
71618de8d7fSPeter Avalos 
71718de8d7fSPeter Avalos 	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
71818de8d7fSPeter Avalos 	    recv_tok, &send_tok, &flags);
71918de8d7fSPeter Avalos 
72018de8d7fSPeter Avalos 	if (send_tok.length > 0) {
72118de8d7fSPeter Avalos 		if (GSS_ERROR(status))
72218de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
72318de8d7fSPeter Avalos 		else
72418de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
72518de8d7fSPeter Avalos 
72618de8d7fSPeter Avalos 		packet_put_string(send_tok.value, send_tok.length);
72718de8d7fSPeter Avalos 		packet_send();
72818de8d7fSPeter Avalos 		gss_release_buffer(&ms, &send_tok);
72918de8d7fSPeter Avalos 	}
73018de8d7fSPeter Avalos 
73118de8d7fSPeter Avalos 	if (status == GSS_S_COMPLETE) {
73218de8d7fSPeter Avalos 		/* send either complete or MIC, depending on mechanism */
73318de8d7fSPeter Avalos 		if (!(flags & GSS_C_INTEG_FLAG)) {
73418de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
73518de8d7fSPeter Avalos 			packet_send();
73618de8d7fSPeter Avalos 		} else {
73718de8d7fSPeter Avalos 			ssh_gssapi_buildmic(&b, authctxt->server_user,
73818de8d7fSPeter Avalos 			    authctxt->service, "gssapi-with-mic");
73918de8d7fSPeter Avalos 
74018de8d7fSPeter Avalos 			gssbuf.value = buffer_ptr(&b);
74118de8d7fSPeter Avalos 			gssbuf.length = buffer_len(&b);
74218de8d7fSPeter Avalos 
74318de8d7fSPeter Avalos 			status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);
74418de8d7fSPeter Avalos 
74518de8d7fSPeter Avalos 			if (!GSS_ERROR(status)) {
74618de8d7fSPeter Avalos 				packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);
74718de8d7fSPeter Avalos 				packet_put_string(mic.value, mic.length);
74818de8d7fSPeter Avalos 
74918de8d7fSPeter Avalos 				packet_send();
75018de8d7fSPeter Avalos 			}
75118de8d7fSPeter Avalos 
75218de8d7fSPeter Avalos 			buffer_free(&b);
75318de8d7fSPeter Avalos 			gss_release_buffer(&ms, &mic);
75418de8d7fSPeter Avalos 		}
75518de8d7fSPeter Avalos 	}
75618de8d7fSPeter Avalos 
75718de8d7fSPeter Avalos 	return status;
75818de8d7fSPeter Avalos }
75918de8d7fSPeter Avalos 
760cb5eb4f1SPeter Avalos /* ARGSUSED */
761e9778795SPeter Avalos int
762*ce74bacaSMatthew Dillon input_gssapi_response(int type, u_int32_t plen, struct ssh *ssh)
76318de8d7fSPeter Avalos {
764*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
76518de8d7fSPeter Avalos 	Gssctxt *gssctxt;
76618de8d7fSPeter Avalos 	int oidlen;
76718de8d7fSPeter Avalos 	char *oidv;
76818de8d7fSPeter Avalos 
76918de8d7fSPeter Avalos 	if (authctxt == NULL)
77018de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
77118de8d7fSPeter Avalos 	gssctxt = authctxt->methoddata;
77218de8d7fSPeter Avalos 
77318de8d7fSPeter Avalos 	/* Setup our OID */
77418de8d7fSPeter Avalos 	oidv = packet_get_string(&oidlen);
77518de8d7fSPeter Avalos 
77618de8d7fSPeter Avalos 	if (oidlen <= 2 ||
77718de8d7fSPeter Avalos 	    oidv[0] != SSH_GSS_OIDTYPE ||
77818de8d7fSPeter Avalos 	    oidv[1] != oidlen - 2) {
77936e94dc5SPeter Avalos 		free(oidv);
78018de8d7fSPeter Avalos 		debug("Badly encoded mechanism OID received");
78118de8d7fSPeter Avalos 		userauth(authctxt, NULL);
782e9778795SPeter Avalos 		return 0;
78318de8d7fSPeter Avalos 	}
78418de8d7fSPeter Avalos 
78518de8d7fSPeter Avalos 	if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
78618de8d7fSPeter Avalos 		fatal("Server returned different OID than expected");
78718de8d7fSPeter Avalos 
78818de8d7fSPeter Avalos 	packet_check_eom();
78918de8d7fSPeter Avalos 
79036e94dc5SPeter Avalos 	free(oidv);
79118de8d7fSPeter Avalos 
792*ce74bacaSMatthew Dillon 	if (GSS_ERROR(process_gssapi_token(ssh, GSS_C_NO_BUFFER))) {
79318de8d7fSPeter Avalos 		/* Start again with next method on list */
79418de8d7fSPeter Avalos 		debug("Trying to start again");
79518de8d7fSPeter Avalos 		userauth(authctxt, NULL);
796e9778795SPeter Avalos 		return 0;
79718de8d7fSPeter Avalos 	}
798e9778795SPeter Avalos 	return 0;
79918de8d7fSPeter Avalos }
80018de8d7fSPeter Avalos 
801cb5eb4f1SPeter Avalos /* ARGSUSED */
802e9778795SPeter Avalos int
803*ce74bacaSMatthew Dillon input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
80418de8d7fSPeter Avalos {
805*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
80618de8d7fSPeter Avalos 	gss_buffer_desc recv_tok;
80718de8d7fSPeter Avalos 	OM_uint32 status;
80818de8d7fSPeter Avalos 	u_int slen;
80918de8d7fSPeter Avalos 
81018de8d7fSPeter Avalos 	if (authctxt == NULL)
81118de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
81218de8d7fSPeter Avalos 
81318de8d7fSPeter Avalos 	recv_tok.value = packet_get_string(&slen);
81418de8d7fSPeter Avalos 	recv_tok.length = slen;	/* safe typecast */
81518de8d7fSPeter Avalos 
81618de8d7fSPeter Avalos 	packet_check_eom();
81718de8d7fSPeter Avalos 
818*ce74bacaSMatthew Dillon 	status = process_gssapi_token(ssh, &recv_tok);
81918de8d7fSPeter Avalos 
82036e94dc5SPeter Avalos 	free(recv_tok.value);
82118de8d7fSPeter Avalos 
82218de8d7fSPeter Avalos 	if (GSS_ERROR(status)) {
82318de8d7fSPeter Avalos 		/* Start again with the next method in the list */
82418de8d7fSPeter Avalos 		userauth(authctxt, NULL);
825e9778795SPeter Avalos 		return 0;
82618de8d7fSPeter Avalos 	}
827e9778795SPeter Avalos 	return 0;
82818de8d7fSPeter Avalos }
82918de8d7fSPeter Avalos 
830cb5eb4f1SPeter Avalos /* ARGSUSED */
831e9778795SPeter Avalos int
832*ce74bacaSMatthew Dillon input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
83318de8d7fSPeter Avalos {
834*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
83518de8d7fSPeter Avalos 	Gssctxt *gssctxt;
83618de8d7fSPeter Avalos 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
83718de8d7fSPeter Avalos 	gss_buffer_desc recv_tok;
83836e94dc5SPeter Avalos 	OM_uint32 ms;
83918de8d7fSPeter Avalos 	u_int len;
84018de8d7fSPeter Avalos 
84118de8d7fSPeter Avalos 	if (authctxt == NULL)
84218de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
84318de8d7fSPeter Avalos 	gssctxt = authctxt->methoddata;
84418de8d7fSPeter Avalos 
84518de8d7fSPeter Avalos 	recv_tok.value = packet_get_string(&len);
84618de8d7fSPeter Avalos 	recv_tok.length = len;
84718de8d7fSPeter Avalos 
84818de8d7fSPeter Avalos 	packet_check_eom();
84918de8d7fSPeter Avalos 
85018de8d7fSPeter Avalos 	/* Stick it into GSSAPI and see what it says */
85136e94dc5SPeter Avalos 	(void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
85218de8d7fSPeter Avalos 	    &recv_tok, &send_tok, NULL);
85318de8d7fSPeter Avalos 
85436e94dc5SPeter Avalos 	free(recv_tok.value);
85518de8d7fSPeter Avalos 	gss_release_buffer(&ms, &send_tok);
85618de8d7fSPeter Avalos 
85718de8d7fSPeter Avalos 	/* Server will be returning a failed packet after this one */
858e9778795SPeter Avalos 	return 0;
85918de8d7fSPeter Avalos }
86018de8d7fSPeter Avalos 
861cb5eb4f1SPeter Avalos /* ARGSUSED */
862e9778795SPeter Avalos int
863*ce74bacaSMatthew Dillon input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh)
86418de8d7fSPeter Avalos {
86518de8d7fSPeter Avalos 	char *msg;
86618de8d7fSPeter Avalos 	char *lang;
86718de8d7fSPeter Avalos 
86836e94dc5SPeter Avalos 	/* maj */(void)packet_get_int();
86936e94dc5SPeter Avalos 	/* min */(void)packet_get_int();
87018de8d7fSPeter Avalos 	msg=packet_get_string(NULL);
87118de8d7fSPeter Avalos 	lang=packet_get_string(NULL);
87218de8d7fSPeter Avalos 
87318de8d7fSPeter Avalos 	packet_check_eom();
87418de8d7fSPeter Avalos 
87518de8d7fSPeter Avalos 	debug("Server GSSAPI Error:\n%s", msg);
87636e94dc5SPeter Avalos 	free(msg);
87736e94dc5SPeter Avalos 	free(lang);
878e9778795SPeter Avalos 	return 0;
87918de8d7fSPeter Avalos }
88018de8d7fSPeter Avalos #endif /* GSSAPI */
88118de8d7fSPeter Avalos 
88218de8d7fSPeter Avalos int
88318de8d7fSPeter Avalos userauth_none(Authctxt *authctxt)
88418de8d7fSPeter Avalos {
88518de8d7fSPeter Avalos 	/* initial userauth request */
88618de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
88718de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
88818de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
88918de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
89018de8d7fSPeter Avalos 	packet_send();
89118de8d7fSPeter Avalos 	return 1;
89218de8d7fSPeter Avalos }
89318de8d7fSPeter Avalos 
89418de8d7fSPeter Avalos int
89518de8d7fSPeter Avalos userauth_passwd(Authctxt *authctxt)
89618de8d7fSPeter Avalos {
89718de8d7fSPeter Avalos 	static int attempt = 0;
898*ce74bacaSMatthew Dillon 	char prompt[256];
89918de8d7fSPeter Avalos 	char *password;
900856ea928SPeter Avalos 	const char *host = options.host_key_alias ?  options.host_key_alias :
901856ea928SPeter Avalos 	    authctxt->host;
90218de8d7fSPeter Avalos 
90318de8d7fSPeter Avalos 	if (attempt++ >= options.number_of_password_prompts)
90418de8d7fSPeter Avalos 		return 0;
90518de8d7fSPeter Avalos 
90618de8d7fSPeter Avalos 	if (attempt != 1)
90718de8d7fSPeter Avalos 		error("Permission denied, please try again.");
90818de8d7fSPeter Avalos 
90918de8d7fSPeter Avalos 	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
910856ea928SPeter Avalos 	    authctxt->server_user, host);
91118de8d7fSPeter Avalos 	password = read_passphrase(prompt, 0);
91218de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
91318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
91418de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
91518de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
91618de8d7fSPeter Avalos 	packet_put_char(0);
91718de8d7fSPeter Avalos 	packet_put_cstring(password);
91836e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
91936e94dc5SPeter Avalos 	free(password);
92018de8d7fSPeter Avalos 	packet_add_padding(64);
92118de8d7fSPeter Avalos 	packet_send();
92218de8d7fSPeter Avalos 
92318de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
92418de8d7fSPeter Avalos 	    &input_userauth_passwd_changereq);
92518de8d7fSPeter Avalos 
92618de8d7fSPeter Avalos 	return 1;
92718de8d7fSPeter Avalos }
928cb5eb4f1SPeter Avalos 
92918de8d7fSPeter Avalos /*
93018de8d7fSPeter Avalos  * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
93118de8d7fSPeter Avalos  */
932cb5eb4f1SPeter Avalos /* ARGSUSED */
933e9778795SPeter Avalos int
934*ce74bacaSMatthew Dillon input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh)
93518de8d7fSPeter Avalos {
936*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
93718de8d7fSPeter Avalos 	char *info, *lang, *password = NULL, *retype = NULL;
938*ce74bacaSMatthew Dillon 	char prompt[256];
939*ce74bacaSMatthew Dillon 	const char *host;
94018de8d7fSPeter Avalos 
94118de8d7fSPeter Avalos 	debug2("input_userauth_passwd_changereq");
94218de8d7fSPeter Avalos 
94318de8d7fSPeter Avalos 	if (authctxt == NULL)
94418de8d7fSPeter Avalos 		fatal("input_userauth_passwd_changereq: "
94518de8d7fSPeter Avalos 		    "no authentication context");
946*ce74bacaSMatthew Dillon 	host = options.host_key_alias ? options.host_key_alias : authctxt->host;
94718de8d7fSPeter Avalos 
94818de8d7fSPeter Avalos 	info = packet_get_string(NULL);
94918de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
95018de8d7fSPeter Avalos 	if (strlen(info) > 0)
95118de8d7fSPeter Avalos 		logit("%s", info);
95236e94dc5SPeter Avalos 	free(info);
95336e94dc5SPeter Avalos 	free(lang);
95418de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
95518de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
95618de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
95718de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
95818de8d7fSPeter Avalos 	packet_put_char(1);			/* additional info */
95918de8d7fSPeter Avalos 	snprintf(prompt, sizeof(prompt),
96018de8d7fSPeter Avalos 	    "Enter %.30s@%.128s's old password: ",
961856ea928SPeter Avalos 	    authctxt->server_user, host);
96218de8d7fSPeter Avalos 	password = read_passphrase(prompt, 0);
96318de8d7fSPeter Avalos 	packet_put_cstring(password);
96436e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
96536e94dc5SPeter Avalos 	free(password);
96618de8d7fSPeter Avalos 	password = NULL;
96718de8d7fSPeter Avalos 	while (password == NULL) {
96818de8d7fSPeter Avalos 		snprintf(prompt, sizeof(prompt),
96918de8d7fSPeter Avalos 		    "Enter %.30s@%.128s's new password: ",
970856ea928SPeter Avalos 		    authctxt->server_user, host);
97118de8d7fSPeter Avalos 		password = read_passphrase(prompt, RP_ALLOW_EOF);
97218de8d7fSPeter Avalos 		if (password == NULL) {
97318de8d7fSPeter Avalos 			/* bail out */
974e9778795SPeter Avalos 			return 0;
97518de8d7fSPeter Avalos 		}
97618de8d7fSPeter Avalos 		snprintf(prompt, sizeof(prompt),
97718de8d7fSPeter Avalos 		    "Retype %.30s@%.128s's new password: ",
978856ea928SPeter Avalos 		    authctxt->server_user, host);
97918de8d7fSPeter Avalos 		retype = read_passphrase(prompt, 0);
98018de8d7fSPeter Avalos 		if (strcmp(password, retype) != 0) {
98136e94dc5SPeter Avalos 			explicit_bzero(password, strlen(password));
98236e94dc5SPeter Avalos 			free(password);
98318de8d7fSPeter Avalos 			logit("Mismatch; try again, EOF to quit.");
98418de8d7fSPeter Avalos 			password = NULL;
98518de8d7fSPeter Avalos 		}
98636e94dc5SPeter Avalos 		explicit_bzero(retype, strlen(retype));
98736e94dc5SPeter Avalos 		free(retype);
98818de8d7fSPeter Avalos 	}
98918de8d7fSPeter Avalos 	packet_put_cstring(password);
99036e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
99136e94dc5SPeter Avalos 	free(password);
99218de8d7fSPeter Avalos 	packet_add_padding(64);
99318de8d7fSPeter Avalos 	packet_send();
99418de8d7fSPeter Avalos 
99518de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
99618de8d7fSPeter Avalos 	    &input_userauth_passwd_changereq);
997e9778795SPeter Avalos 	return 0;
998e9778795SPeter Avalos }
999e9778795SPeter Avalos 
1000e9778795SPeter Avalos static const char *
1001*ce74bacaSMatthew Dillon key_sign_encode(const struct sshkey *key)
1002e9778795SPeter Avalos {
1003e9778795SPeter Avalos 	struct ssh *ssh = active_state;
1004e9778795SPeter Avalos 
1005*ce74bacaSMatthew Dillon 	if (key->type == KEY_RSA) {
1006e9778795SPeter Avalos 		switch (ssh->kex->rsa_sha2) {
1007e9778795SPeter Avalos 		case 256:
1008e9778795SPeter Avalos 			return "rsa-sha2-256";
1009e9778795SPeter Avalos 		case 512:
1010e9778795SPeter Avalos 			return "rsa-sha2-512";
1011e9778795SPeter Avalos 		}
1012e9778795SPeter Avalos 	}
1013*ce74bacaSMatthew Dillon 	return key_ssh_name(key);
101418de8d7fSPeter Avalos }
101518de8d7fSPeter Avalos 
101618de8d7fSPeter Avalos static int
1017e9778795SPeter Avalos identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1018e9778795SPeter Avalos     const u_char *data, size_t datalen, u_int compat)
101918de8d7fSPeter Avalos {
1020*ce74bacaSMatthew Dillon 	struct sshkey *prv;
102118de8d7fSPeter Avalos 	int ret;
102218de8d7fSPeter Avalos 
102318de8d7fSPeter Avalos 	/* the agent supports this key */
1024*ce74bacaSMatthew Dillon 	if (id->key != NULL && id->agent_fd != -1)
1025e9778795SPeter Avalos 		return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
1026*ce74bacaSMatthew Dillon 		    data, datalen, key_sign_encode(id->key), compat);
1027e9778795SPeter Avalos 
102818de8d7fSPeter Avalos 	/*
102918de8d7fSPeter Avalos 	 * we have already loaded the private key or
103018de8d7fSPeter Avalos 	 * the private key is stored in external hardware
103118de8d7fSPeter Avalos 	 */
1032*ce74bacaSMatthew Dillon 	if (id->key != NULL &&
1033*ce74bacaSMatthew Dillon 	    (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)))
1034*ce74bacaSMatthew Dillon 		return (sshkey_sign(id->key, sigp, lenp, data, datalen,
1035*ce74bacaSMatthew Dillon 		    key_sign_encode(id->key), compat));
1036*ce74bacaSMatthew Dillon 
103718de8d7fSPeter Avalos 	/* load the private key from the file */
1038e9778795SPeter Avalos 	if ((prv = load_identity_file(id)) == NULL)
1039e9778795SPeter Avalos 		return SSH_ERR_KEY_NOT_FOUND;
1040*ce74bacaSMatthew Dillon 	if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
1041*ce74bacaSMatthew Dillon 		error("%s: private key %s contents do not match public",
1042*ce74bacaSMatthew Dillon 		   __func__, id->filename);
1043*ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_NOT_FOUND;
1044*ce74bacaSMatthew Dillon 	}
1045*ce74bacaSMatthew Dillon 	ret = sshkey_sign(prv, sigp, lenp, data, datalen,
1046*ce74bacaSMatthew Dillon 	    key_sign_encode(prv), compat);
1047e9778795SPeter Avalos 	sshkey_free(prv);
104818de8d7fSPeter Avalos 	return (ret);
104918de8d7fSPeter Avalos }
105018de8d7fSPeter Avalos 
105118de8d7fSPeter Avalos static int
1052*ce74bacaSMatthew Dillon id_filename_matches(Identity *id, Identity *private_id)
1053*ce74bacaSMatthew Dillon {
1054*ce74bacaSMatthew Dillon 	const char *suffixes[] = { ".pub", "-cert.pub", NULL };
1055*ce74bacaSMatthew Dillon 	size_t len = strlen(id->filename), plen = strlen(private_id->filename);
1056*ce74bacaSMatthew Dillon 	size_t i, slen;
1057*ce74bacaSMatthew Dillon 
1058*ce74bacaSMatthew Dillon 	if (strcmp(id->filename, private_id->filename) == 0)
1059*ce74bacaSMatthew Dillon 		return 1;
1060*ce74bacaSMatthew Dillon 	for (i = 0; suffixes[i]; i++) {
1061*ce74bacaSMatthew Dillon 		slen = strlen(suffixes[i]);
1062*ce74bacaSMatthew Dillon 		if (len > slen && plen == len - slen &&
1063*ce74bacaSMatthew Dillon 		    strcmp(id->filename + (len - slen), suffixes[i]) == 0 &&
1064*ce74bacaSMatthew Dillon 		    memcmp(id->filename, private_id->filename, plen) == 0)
1065*ce74bacaSMatthew Dillon 			return 1;
1066*ce74bacaSMatthew Dillon 	}
1067*ce74bacaSMatthew Dillon 	return 0;
1068*ce74bacaSMatthew Dillon }
1069*ce74bacaSMatthew Dillon 
1070*ce74bacaSMatthew Dillon static int
107118de8d7fSPeter Avalos sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
107218de8d7fSPeter Avalos {
107318de8d7fSPeter Avalos 	Buffer b;
1074e9778795SPeter Avalos 	Identity *private_id;
107518de8d7fSPeter Avalos 	u_char *blob, *signature;
1076e9778795SPeter Avalos 	size_t slen;
1077e9778795SPeter Avalos 	u_int bloblen, skip = 0;
1078e9778795SPeter Avalos 	int matched, ret = -1, have_sig = 1;
1079856ea928SPeter Avalos 	char *fp;
108018de8d7fSPeter Avalos 
1081e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
1082e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL)
1083e9778795SPeter Avalos 		return 0;
1084e9778795SPeter Avalos 	debug3("%s: %s %s", __func__, key_type(id->key), fp);
108536e94dc5SPeter Avalos 	free(fp);
108618de8d7fSPeter Avalos 
108718de8d7fSPeter Avalos 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
108818de8d7fSPeter Avalos 		/* we cannot handle this key */
108918de8d7fSPeter Avalos 		debug3("sign_and_send_pubkey: cannot handle key");
109018de8d7fSPeter Avalos 		return 0;
109118de8d7fSPeter Avalos 	}
109218de8d7fSPeter Avalos 	/* data to be signed */
109318de8d7fSPeter Avalos 	buffer_init(&b);
109418de8d7fSPeter Avalos 	if (datafellows & SSH_OLD_SESSIONID) {
109518de8d7fSPeter Avalos 		buffer_append(&b, session_id2, session_id2_len);
109618de8d7fSPeter Avalos 		skip = session_id2_len;
109718de8d7fSPeter Avalos 	} else {
109818de8d7fSPeter Avalos 		buffer_put_string(&b, session_id2, session_id2_len);
109918de8d7fSPeter Avalos 		skip = buffer_len(&b);
110018de8d7fSPeter Avalos 	}
110118de8d7fSPeter Avalos 	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
110218de8d7fSPeter Avalos 	buffer_put_cstring(&b, authctxt->server_user);
110318de8d7fSPeter Avalos 	buffer_put_cstring(&b,
110418de8d7fSPeter Avalos 	    datafellows & SSH_BUG_PKSERVICE ?
110518de8d7fSPeter Avalos 	    "ssh-userauth" :
110618de8d7fSPeter Avalos 	    authctxt->service);
110718de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKAUTH) {
110818de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
110918de8d7fSPeter Avalos 	} else {
111018de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->method->name);
111118de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
1112*ce74bacaSMatthew Dillon 		buffer_put_cstring(&b, key_sign_encode(id->key));
111318de8d7fSPeter Avalos 	}
111418de8d7fSPeter Avalos 	buffer_put_string(&b, blob, bloblen);
111518de8d7fSPeter Avalos 
1116e9778795SPeter Avalos 	/*
1117e9778795SPeter Avalos 	 * If the key is an certificate, try to find a matching private key
1118e9778795SPeter Avalos 	 * and use it to complete the signature.
1119e9778795SPeter Avalos 	 * If no such private key exists, fall back to trying the certificate
1120e9778795SPeter Avalos 	 * key itself in case it has a private half already loaded.
1121e9778795SPeter Avalos 	 */
1122e9778795SPeter Avalos 	if (key_is_cert(id->key)) {
1123e9778795SPeter Avalos 		matched = 0;
1124e9778795SPeter Avalos 		TAILQ_FOREACH(private_id, &authctxt->keys, next) {
1125e9778795SPeter Avalos 			if (sshkey_equal_public(id->key, private_id->key) &&
1126e9778795SPeter Avalos 			    id->key->type != private_id->key->type) {
1127e9778795SPeter Avalos 				id = private_id;
1128e9778795SPeter Avalos 				matched = 1;
1129e9778795SPeter Avalos 				break;
1130e9778795SPeter Avalos 			}
1131e9778795SPeter Avalos 		}
1132*ce74bacaSMatthew Dillon 		/*
1133*ce74bacaSMatthew Dillon 		 * Exact key matches are preferred, but also allow
1134*ce74bacaSMatthew Dillon 		 * filename matches for non-PKCS#11/agent keys that
1135*ce74bacaSMatthew Dillon 		 * didn't load public keys. This supports the case
1136*ce74bacaSMatthew Dillon 		 * of keeping just a private key file and public
1137*ce74bacaSMatthew Dillon 		 * certificate on disk.
1138*ce74bacaSMatthew Dillon 		 */
1139*ce74bacaSMatthew Dillon 		if (!matched && !id->isprivate && id->agent_fd == -1 &&
1140*ce74bacaSMatthew Dillon 		    (id->key->flags & SSHKEY_FLAG_EXT) == 0) {
1141*ce74bacaSMatthew Dillon 			TAILQ_FOREACH(private_id, &authctxt->keys, next) {
1142*ce74bacaSMatthew Dillon 				if (private_id->key == NULL &&
1143*ce74bacaSMatthew Dillon 				    id_filename_matches(id, private_id)) {
1144*ce74bacaSMatthew Dillon 					id = private_id;
1145*ce74bacaSMatthew Dillon 					matched = 1;
1146*ce74bacaSMatthew Dillon 					break;
1147*ce74bacaSMatthew Dillon 				}
1148*ce74bacaSMatthew Dillon 			}
1149*ce74bacaSMatthew Dillon 		}
1150e9778795SPeter Avalos 		if (matched) {
1151e9778795SPeter Avalos 			debug2("%s: using private key \"%s\"%s for "
1152e9778795SPeter Avalos 			    "certificate", __func__, id->filename,
1153e9778795SPeter Avalos 			    id->agent_fd != -1 ? " from agent" : "");
1154e9778795SPeter Avalos 		} else {
1155e9778795SPeter Avalos 			debug("%s: no separate private key for certificate "
1156e9778795SPeter Avalos 			    "\"%s\"", __func__, id->filename);
1157e9778795SPeter Avalos 		}
1158e9778795SPeter Avalos 	}
1159e9778795SPeter Avalos 
116018de8d7fSPeter Avalos 	/* generate signature */
116118de8d7fSPeter Avalos 	ret = identity_sign(id, &signature, &slen,
1162e9778795SPeter Avalos 	    buffer_ptr(&b), buffer_len(&b), datafellows);
1163e9778795SPeter Avalos 	if (ret != 0) {
1164e9778795SPeter Avalos 		if (ret != SSH_ERR_KEY_NOT_FOUND)
1165e9778795SPeter Avalos 			error("%s: signing failed: %s", __func__, ssh_err(ret));
116636e94dc5SPeter Avalos 		free(blob);
116718de8d7fSPeter Avalos 		buffer_free(&b);
116818de8d7fSPeter Avalos 		return 0;
116918de8d7fSPeter Avalos 	}
117018de8d7fSPeter Avalos #ifdef DEBUG_PK
117118de8d7fSPeter Avalos 	buffer_dump(&b);
117218de8d7fSPeter Avalos #endif
117318de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKSERVICE) {
117418de8d7fSPeter Avalos 		buffer_clear(&b);
117518de8d7fSPeter Avalos 		buffer_append(&b, session_id2, session_id2_len);
117618de8d7fSPeter Avalos 		skip = session_id2_len;
117718de8d7fSPeter Avalos 		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
117818de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->server_user);
117918de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->service);
118018de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->method->name);
118118de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
118218de8d7fSPeter Avalos 		if (!(datafellows & SSH_BUG_PKAUTH))
118318de8d7fSPeter Avalos 			buffer_put_cstring(&b, key_ssh_name(id->key));
118418de8d7fSPeter Avalos 		buffer_put_string(&b, blob, bloblen);
118518de8d7fSPeter Avalos 	}
118636e94dc5SPeter Avalos 	free(blob);
118718de8d7fSPeter Avalos 
118818de8d7fSPeter Avalos 	/* append signature */
118918de8d7fSPeter Avalos 	buffer_put_string(&b, signature, slen);
119036e94dc5SPeter Avalos 	free(signature);
119118de8d7fSPeter Avalos 
119218de8d7fSPeter Avalos 	/* skip session id and packet type */
119318de8d7fSPeter Avalos 	if (buffer_len(&b) < skip + 1)
119418de8d7fSPeter Avalos 		fatal("userauth_pubkey: internal error");
119518de8d7fSPeter Avalos 	buffer_consume(&b, skip + 1);
119618de8d7fSPeter Avalos 
119718de8d7fSPeter Avalos 	/* put remaining data from buffer into packet */
119818de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
119918de8d7fSPeter Avalos 	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
120018de8d7fSPeter Avalos 	buffer_free(&b);
120118de8d7fSPeter Avalos 	packet_send();
120218de8d7fSPeter Avalos 
120318de8d7fSPeter Avalos 	return 1;
120418de8d7fSPeter Avalos }
120518de8d7fSPeter Avalos 
120618de8d7fSPeter Avalos static int
120718de8d7fSPeter Avalos send_pubkey_test(Authctxt *authctxt, Identity *id)
120818de8d7fSPeter Avalos {
120918de8d7fSPeter Avalos 	u_char *blob;
121018de8d7fSPeter Avalos 	u_int bloblen, have_sig = 0;
121118de8d7fSPeter Avalos 
121218de8d7fSPeter Avalos 	debug3("send_pubkey_test");
121318de8d7fSPeter Avalos 
121418de8d7fSPeter Avalos 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
121518de8d7fSPeter Avalos 		/* we cannot handle this key */
121618de8d7fSPeter Avalos 		debug3("send_pubkey_test: cannot handle key");
121718de8d7fSPeter Avalos 		return 0;
121818de8d7fSPeter Avalos 	}
121918de8d7fSPeter Avalos 	/* register callback for USERAUTH_PK_OK message */
122018de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
122118de8d7fSPeter Avalos 
122218de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
122318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
122418de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
122518de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
122618de8d7fSPeter Avalos 	packet_put_char(have_sig);
122718de8d7fSPeter Avalos 	if (!(datafellows & SSH_BUG_PKAUTH))
1228*ce74bacaSMatthew Dillon 		packet_put_cstring(key_sign_encode(id->key));
122918de8d7fSPeter Avalos 	packet_put_string(blob, bloblen);
123036e94dc5SPeter Avalos 	free(blob);
123118de8d7fSPeter Avalos 	packet_send();
123218de8d7fSPeter Avalos 	return 1;
123318de8d7fSPeter Avalos }
123418de8d7fSPeter Avalos 
1235*ce74bacaSMatthew Dillon static struct sshkey *
1236e9778795SPeter Avalos load_identity_file(Identity *id)
123718de8d7fSPeter Avalos {
1238*ce74bacaSMatthew Dillon 	struct sshkey *private = NULL;
1239e9778795SPeter Avalos 	char prompt[300], *passphrase, *comment;
1240e9778795SPeter Avalos 	int r, perm_ok = 0, quit = 0, i;
124118de8d7fSPeter Avalos 	struct stat st;
124218de8d7fSPeter Avalos 
1243e9778795SPeter Avalos 	if (stat(id->filename, &st) < 0) {
1244e9778795SPeter Avalos 		(id->userprovided ? logit : debug3)("no such identity: %s: %s",
1245e9778795SPeter Avalos 		    id->filename, strerror(errno));
124618de8d7fSPeter Avalos 		return NULL;
124718de8d7fSPeter Avalos 	}
124818de8d7fSPeter Avalos 	snprintf(prompt, sizeof prompt,
1249e9778795SPeter Avalos 	    "Enter passphrase for key '%.100s': ", id->filename);
1250e9778795SPeter Avalos 	for (i = 0; i <= options.number_of_password_prompts; i++) {
1251e9778795SPeter Avalos 		if (i == 0)
1252e9778795SPeter Avalos 			passphrase = "";
1253e9778795SPeter Avalos 		else {
125418de8d7fSPeter Avalos 			passphrase = read_passphrase(prompt, 0);
1255e9778795SPeter Avalos 			if (*passphrase == '\0') {
125618de8d7fSPeter Avalos 				debug2("no passphrase given, try next key");
1257e9778795SPeter Avalos 				free(passphrase);
1258e9778795SPeter Avalos 				break;
125918de8d7fSPeter Avalos 			}
1260e9778795SPeter Avalos 		}
1261e9778795SPeter Avalos 		switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename,
1262e9778795SPeter Avalos 		    passphrase, &private, &comment, &perm_ok))) {
1263e9778795SPeter Avalos 		case 0:
1264e9778795SPeter Avalos 			break;
1265e9778795SPeter Avalos 		case SSH_ERR_KEY_WRONG_PASSPHRASE:
1266e9778795SPeter Avalos 			if (options.batch_mode) {
1267e9778795SPeter Avalos 				quit = 1;
1268e9778795SPeter Avalos 				break;
1269e9778795SPeter Avalos 			}
1270e9778795SPeter Avalos 			if (i != 0)
1271e9778795SPeter Avalos 				debug2("bad passphrase given, try again...");
1272e9778795SPeter Avalos 			break;
1273e9778795SPeter Avalos 		case SSH_ERR_SYSTEM_ERROR:
1274e9778795SPeter Avalos 			if (errno == ENOENT) {
1275e9778795SPeter Avalos 				debug2("Load key \"%s\": %s",
1276e9778795SPeter Avalos 				    id->filename, ssh_err(r));
1277e9778795SPeter Avalos 				quit = 1;
1278e9778795SPeter Avalos 				break;
1279e9778795SPeter Avalos 			}
1280e9778795SPeter Avalos 			/* FALLTHROUGH */
1281e9778795SPeter Avalos 		default:
1282e9778795SPeter Avalos 			error("Load key \"%s\": %s", id->filename, ssh_err(r));
1283e9778795SPeter Avalos 			quit = 1;
1284e9778795SPeter Avalos 			break;
1285e9778795SPeter Avalos 		}
1286e9778795SPeter Avalos 		if (!quit && private != NULL && id->agent_fd == -1 &&
1287e9778795SPeter Avalos 		    !(id->key && id->isprivate))
1288e9778795SPeter Avalos 			maybe_add_key_to_agent(id->filename, private, comment,
1289e9778795SPeter Avalos 			    passphrase);
1290e9778795SPeter Avalos 		if (i > 0) {
129136e94dc5SPeter Avalos 			explicit_bzero(passphrase, strlen(passphrase));
129236e94dc5SPeter Avalos 			free(passphrase);
1293e9778795SPeter Avalos 		}
1294e9778795SPeter Avalos 		free(comment);
129518de8d7fSPeter Avalos 		if (private != NULL || quit)
129618de8d7fSPeter Avalos 			break;
129718de8d7fSPeter Avalos 	}
129818de8d7fSPeter Avalos 	return private;
129918de8d7fSPeter Avalos }
130018de8d7fSPeter Avalos 
130118de8d7fSPeter Avalos /*
130218de8d7fSPeter Avalos  * try keys in the following order:
1303e9778795SPeter Avalos  * 	1. certificates listed in the config file
1304e9778795SPeter Avalos  * 	2. other input certificates
1305e9778795SPeter Avalos  *	3. agent keys that are found in the config file
1306e9778795SPeter Avalos  *	4. other agent keys
1307e9778795SPeter Avalos  *	5. keys that are only listed in the config file
130818de8d7fSPeter Avalos  */
130918de8d7fSPeter Avalos static void
131018de8d7fSPeter Avalos pubkey_prepare(Authctxt *authctxt)
131118de8d7fSPeter Avalos {
1312e9778795SPeter Avalos 	struct identity *id, *id2, *tmp;
1313e9778795SPeter Avalos 	struct idlist agent, files, *preferred;
1314e9778795SPeter Avalos 	struct sshkey *key;
1315e9778795SPeter Avalos 	int agent_fd = -1, i, r, found;
1316e9778795SPeter Avalos 	size_t j;
1317e9778795SPeter Avalos 	struct ssh_identitylist *idlist;
131818de8d7fSPeter Avalos 
131918de8d7fSPeter Avalos 	TAILQ_INIT(&agent);	/* keys from the agent */
132018de8d7fSPeter Avalos 	TAILQ_INIT(&files);	/* keys from the config file */
132118de8d7fSPeter Avalos 	preferred = &authctxt->keys;
132218de8d7fSPeter Avalos 	TAILQ_INIT(preferred);	/* preferred order of keys */
132318de8d7fSPeter Avalos 
132436e94dc5SPeter Avalos 	/* list of keys stored in the filesystem and PKCS#11 */
132518de8d7fSPeter Avalos 	for (i = 0; i < options.num_identity_files; i++) {
132618de8d7fSPeter Avalos 		key = options.identity_keys[i];
1327856ea928SPeter Avalos 		if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER)
1328856ea928SPeter Avalos 			continue;
132918de8d7fSPeter Avalos 		options.identity_keys[i] = NULL;
133018de8d7fSPeter Avalos 		id = xcalloc(1, sizeof(*id));
1331e9778795SPeter Avalos 		id->agent_fd = -1;
133218de8d7fSPeter Avalos 		id->key = key;
133318de8d7fSPeter Avalos 		id->filename = xstrdup(options.identity_files[i]);
133436e94dc5SPeter Avalos 		id->userprovided = options.identity_file_userprovided[i];
133518de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(&files, id, next);
133618de8d7fSPeter Avalos 	}
1337e9778795SPeter Avalos 	/* list of certificates specified by user */
1338e9778795SPeter Avalos 	for (i = 0; i < options.num_certificate_files; i++) {
1339e9778795SPeter Avalos 		key = options.certificates[i];
1340e9778795SPeter Avalos 		if (!key_is_cert(key) || key->cert == NULL ||
1341e9778795SPeter Avalos 		    key->cert->type != SSH2_CERT_TYPE_USER)
1342e9778795SPeter Avalos 			continue;
1343e9778795SPeter Avalos 		id = xcalloc(1, sizeof(*id));
1344e9778795SPeter Avalos 		id->agent_fd = -1;
1345e9778795SPeter Avalos 		id->key = key;
1346e9778795SPeter Avalos 		id->filename = xstrdup(options.certificate_files[i]);
1347e9778795SPeter Avalos 		id->userprovided = options.certificate_file_userprovided[i];
1348e9778795SPeter Avalos 		TAILQ_INSERT_TAIL(preferred, id, next);
1349e9778795SPeter Avalos 	}
1350e9778795SPeter Avalos 	/* list of keys supported by the agent */
1351e9778795SPeter Avalos 	if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
1352e9778795SPeter Avalos 		if (r != SSH_ERR_AGENT_NOT_PRESENT)
1353e9778795SPeter Avalos 			debug("%s: ssh_get_authentication_socket: %s",
1354e9778795SPeter Avalos 			    __func__, ssh_err(r));
1355*ce74bacaSMatthew Dillon 	} else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
1356e9778795SPeter Avalos 		if (r != SSH_ERR_AGENT_NO_IDENTITIES)
1357e9778795SPeter Avalos 			debug("%s: ssh_fetch_identitylist: %s",
1358e9778795SPeter Avalos 			    __func__, ssh_err(r));
1359e9778795SPeter Avalos 		close(agent_fd);
1360e9778795SPeter Avalos 	} else {
1361e9778795SPeter Avalos 		for (j = 0; j < idlist->nkeys; j++) {
1362e9778795SPeter Avalos 			found = 0;
1363e9778795SPeter Avalos 			TAILQ_FOREACH(id, &files, next) {
1364e9778795SPeter Avalos 				/*
1365e9778795SPeter Avalos 				 * agent keys from the config file are
1366e9778795SPeter Avalos 				 * preferred
1367e9778795SPeter Avalos 				 */
1368e9778795SPeter Avalos 				if (sshkey_equal(idlist->keys[j], id->key)) {
1369e9778795SPeter Avalos 					TAILQ_REMOVE(&files, id, next);
1370e9778795SPeter Avalos 					TAILQ_INSERT_TAIL(preferred, id, next);
1371e9778795SPeter Avalos 					id->agent_fd = agent_fd;
1372e9778795SPeter Avalos 					found = 1;
1373e9778795SPeter Avalos 					break;
1374e9778795SPeter Avalos 				}
1375e9778795SPeter Avalos 			}
1376e9778795SPeter Avalos 			if (!found && !options.identities_only) {
1377e9778795SPeter Avalos 				id = xcalloc(1, sizeof(*id));
1378e9778795SPeter Avalos 				/* XXX "steals" key/comment from idlist */
1379e9778795SPeter Avalos 				id->key = idlist->keys[j];
1380e9778795SPeter Avalos 				id->filename = idlist->comments[j];
1381e9778795SPeter Avalos 				idlist->keys[j] = NULL;
1382e9778795SPeter Avalos 				idlist->comments[j] = NULL;
1383e9778795SPeter Avalos 				id->agent_fd = agent_fd;
1384e9778795SPeter Avalos 				TAILQ_INSERT_TAIL(&agent, id, next);
1385e9778795SPeter Avalos 			}
1386e9778795SPeter Avalos 		}
1387e9778795SPeter Avalos 		ssh_free_identitylist(idlist);
1388e9778795SPeter Avalos 		/* append remaining agent keys */
1389e9778795SPeter Avalos 		for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
1390e9778795SPeter Avalos 			TAILQ_REMOVE(&agent, id, next);
1391e9778795SPeter Avalos 			TAILQ_INSERT_TAIL(preferred, id, next);
1392e9778795SPeter Avalos 		}
1393e9778795SPeter Avalos 		authctxt->agent_fd = agent_fd;
1394e9778795SPeter Avalos 	}
139536e94dc5SPeter Avalos 	/* Prefer PKCS11 keys that are explicitly listed */
139636e94dc5SPeter Avalos 	TAILQ_FOREACH_SAFE(id, &files, next, tmp) {
139736e94dc5SPeter Avalos 		if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0)
139836e94dc5SPeter Avalos 			continue;
139936e94dc5SPeter Avalos 		found = 0;
140036e94dc5SPeter Avalos 		TAILQ_FOREACH(id2, &files, next) {
140136e94dc5SPeter Avalos 			if (id2->key == NULL ||
140236e94dc5SPeter Avalos 			    (id2->key->flags & SSHKEY_FLAG_EXT) == 0)
140336e94dc5SPeter Avalos 				continue;
1404e9778795SPeter Avalos 			if (sshkey_equal(id->key, id2->key)) {
140536e94dc5SPeter Avalos 				TAILQ_REMOVE(&files, id, next);
140636e94dc5SPeter Avalos 				TAILQ_INSERT_TAIL(preferred, id, next);
140736e94dc5SPeter Avalos 				found = 1;
140836e94dc5SPeter Avalos 				break;
140936e94dc5SPeter Avalos 			}
141036e94dc5SPeter Avalos 		}
141136e94dc5SPeter Avalos 		/* If IdentitiesOnly set and key not found then don't use it */
141236e94dc5SPeter Avalos 		if (!found && options.identities_only) {
141336e94dc5SPeter Avalos 			TAILQ_REMOVE(&files, id, next);
141436e94dc5SPeter Avalos 			explicit_bzero(id, sizeof(*id));
141536e94dc5SPeter Avalos 			free(id);
141636e94dc5SPeter Avalos 		}
141736e94dc5SPeter Avalos 	}
141818de8d7fSPeter Avalos 	/* append remaining keys from the config file */
141918de8d7fSPeter Avalos 	for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
142018de8d7fSPeter Avalos 		TAILQ_REMOVE(&files, id, next);
142118de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(preferred, id, next);
142218de8d7fSPeter Avalos 	}
1423e9778795SPeter Avalos 	/* finally, filter by PubkeyAcceptedKeyTypes */
1424e9778795SPeter Avalos 	TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
1425e9778795SPeter Avalos 		if (id->key != NULL &&
1426e9778795SPeter Avalos 		    match_pattern_list(sshkey_ssh_name(id->key),
1427e9778795SPeter Avalos 		    options.pubkey_key_types, 0) != 1) {
1428e9778795SPeter Avalos 			debug("Skipping %s key %s - "
1429e9778795SPeter Avalos 			    "not in PubkeyAcceptedKeyTypes",
1430e9778795SPeter Avalos 			    sshkey_ssh_name(id->key), id->filename);
1431e9778795SPeter Avalos 			TAILQ_REMOVE(preferred, id, next);
1432e9778795SPeter Avalos 			sshkey_free(id->key);
1433e9778795SPeter Avalos 			free(id->filename);
1434e9778795SPeter Avalos 			memset(id, 0, sizeof(*id));
1435e9778795SPeter Avalos 			continue;
1436e9778795SPeter Avalos 		}
1437e9778795SPeter Avalos 		debug2("key: %s (%p)%s%s", id->filename, id->key,
1438e9778795SPeter Avalos 		    id->userprovided ? ", explicit" : "",
1439e9778795SPeter Avalos 		    id->agent_fd != -1 ? ", agent" : "");
144018de8d7fSPeter Avalos 	}
144118de8d7fSPeter Avalos }
144218de8d7fSPeter Avalos 
144318de8d7fSPeter Avalos static void
144418de8d7fSPeter Avalos pubkey_cleanup(Authctxt *authctxt)
144518de8d7fSPeter Avalos {
144618de8d7fSPeter Avalos 	Identity *id;
144718de8d7fSPeter Avalos 
1448e9778795SPeter Avalos 	if (authctxt->agent_fd != -1)
1449e9778795SPeter Avalos 		ssh_close_authentication_socket(authctxt->agent_fd);
145018de8d7fSPeter Avalos 	for (id = TAILQ_FIRST(&authctxt->keys); id;
145118de8d7fSPeter Avalos 	    id = TAILQ_FIRST(&authctxt->keys)) {
145218de8d7fSPeter Avalos 		TAILQ_REMOVE(&authctxt->keys, id, next);
1453e9778795SPeter Avalos 		sshkey_free(id->key);
145436e94dc5SPeter Avalos 		free(id->filename);
145536e94dc5SPeter Avalos 		free(id);
145618de8d7fSPeter Avalos 	}
145718de8d7fSPeter Avalos }
145818de8d7fSPeter Avalos 
1459*ce74bacaSMatthew Dillon static void
1460*ce74bacaSMatthew Dillon pubkey_reset(Authctxt *authctxt)
1461*ce74bacaSMatthew Dillon {
1462*ce74bacaSMatthew Dillon 	Identity *id;
1463*ce74bacaSMatthew Dillon 
1464*ce74bacaSMatthew Dillon 	TAILQ_FOREACH(id, &authctxt->keys, next)
1465*ce74bacaSMatthew Dillon 		id->tried = 0;
1466*ce74bacaSMatthew Dillon }
1467*ce74bacaSMatthew Dillon 
1468e9778795SPeter Avalos static int
1469e9778795SPeter Avalos try_identity(Identity *id)
1470e9778795SPeter Avalos {
1471e9778795SPeter Avalos 	if (!id->key)
1472e9778795SPeter Avalos 		return (0);
1473e9778795SPeter Avalos 	if (key_type_plain(id->key->type) == KEY_RSA &&
1474e9778795SPeter Avalos 	    (datafellows & SSH_BUG_RSASIGMD5) != 0) {
1475e9778795SPeter Avalos 		debug("Skipped %s key %s for RSA/MD5 server",
1476e9778795SPeter Avalos 		    key_type(id->key), id->filename);
1477e9778795SPeter Avalos 		return (0);
1478e9778795SPeter Avalos 	}
1479*ce74bacaSMatthew Dillon 	return 1;
1480e9778795SPeter Avalos }
1481e9778795SPeter Avalos 
148218de8d7fSPeter Avalos int
148318de8d7fSPeter Avalos userauth_pubkey(Authctxt *authctxt)
148418de8d7fSPeter Avalos {
148518de8d7fSPeter Avalos 	Identity *id;
148618de8d7fSPeter Avalos 	int sent = 0;
1487*ce74bacaSMatthew Dillon 	char *fp;
148818de8d7fSPeter Avalos 
148918de8d7fSPeter Avalos 	while ((id = TAILQ_FIRST(&authctxt->keys))) {
149018de8d7fSPeter Avalos 		if (id->tried++)
149118de8d7fSPeter Avalos 			return (0);
149218de8d7fSPeter Avalos 		/* move key to the end of the queue */
149318de8d7fSPeter Avalos 		TAILQ_REMOVE(&authctxt->keys, id, next);
149418de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
149518de8d7fSPeter Avalos 		/*
149618de8d7fSPeter Avalos 		 * send a test message if we have the public key. for
149718de8d7fSPeter Avalos 		 * encrypted keys we cannot do this and have to load the
149818de8d7fSPeter Avalos 		 * private key instead
149918de8d7fSPeter Avalos 		 */
150036e94dc5SPeter Avalos 		if (id->key != NULL) {
1501e9778795SPeter Avalos 			if (try_identity(id)) {
1502*ce74bacaSMatthew Dillon 				if ((fp = sshkey_fingerprint(id->key,
1503*ce74bacaSMatthew Dillon 				    options.fingerprint_hash,
1504*ce74bacaSMatthew Dillon 				    SSH_FP_DEFAULT)) == NULL) {
1505*ce74bacaSMatthew Dillon 					error("%s: sshkey_fingerprint failed",
1506*ce74bacaSMatthew Dillon 					    __func__);
1507*ce74bacaSMatthew Dillon 					return 0;
1508*ce74bacaSMatthew Dillon 				}
1509*ce74bacaSMatthew Dillon 				debug("Offering public key: %s %s %s",
1510*ce74bacaSMatthew Dillon 				    sshkey_type(id->key), fp, id->filename);
1511*ce74bacaSMatthew Dillon 				free(fp);
151218de8d7fSPeter Avalos 				sent = send_pubkey_test(authctxt, id);
151336e94dc5SPeter Avalos 			}
151436e94dc5SPeter Avalos 		} else {
151518de8d7fSPeter Avalos 			debug("Trying private key: %s", id->filename);
1516e9778795SPeter Avalos 			id->key = load_identity_file(id);
151718de8d7fSPeter Avalos 			if (id->key != NULL) {
1518e9778795SPeter Avalos 				if (try_identity(id)) {
151918de8d7fSPeter Avalos 					id->isprivate = 1;
152036e94dc5SPeter Avalos 					sent = sign_and_send_pubkey(
152136e94dc5SPeter Avalos 					    authctxt, id);
152236e94dc5SPeter Avalos 				}
152318de8d7fSPeter Avalos 				key_free(id->key);
152418de8d7fSPeter Avalos 				id->key = NULL;
1525*ce74bacaSMatthew Dillon 				id->isprivate = 0;
152618de8d7fSPeter Avalos 			}
152718de8d7fSPeter Avalos 		}
152818de8d7fSPeter Avalos 		if (sent)
152918de8d7fSPeter Avalos 			return (sent);
153018de8d7fSPeter Avalos 	}
153118de8d7fSPeter Avalos 	return (0);
153218de8d7fSPeter Avalos }
153318de8d7fSPeter Avalos 
153418de8d7fSPeter Avalos /*
153518de8d7fSPeter Avalos  * Send userauth request message specifying keyboard-interactive method.
153618de8d7fSPeter Avalos  */
153718de8d7fSPeter Avalos int
153818de8d7fSPeter Avalos userauth_kbdint(Authctxt *authctxt)
153918de8d7fSPeter Avalos {
154018de8d7fSPeter Avalos 	static int attempt = 0;
154118de8d7fSPeter Avalos 
154218de8d7fSPeter Avalos 	if (attempt++ >= options.number_of_password_prompts)
154318de8d7fSPeter Avalos 		return 0;
154418de8d7fSPeter Avalos 	/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
154518de8d7fSPeter Avalos 	if (attempt > 1 && !authctxt->info_req_seen) {
154618de8d7fSPeter Avalos 		debug3("userauth_kbdint: disable: no info_req_seen");
154718de8d7fSPeter Avalos 		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
154818de8d7fSPeter Avalos 		return 0;
154918de8d7fSPeter Avalos 	}
155018de8d7fSPeter Avalos 
155118de8d7fSPeter Avalos 	debug2("userauth_kbdint");
155218de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
155318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
155418de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
155518de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
155618de8d7fSPeter Avalos 	packet_put_cstring("");					/* lang */
155718de8d7fSPeter Avalos 	packet_put_cstring(options.kbd_interactive_devices ?
155818de8d7fSPeter Avalos 	    options.kbd_interactive_devices : "");
155918de8d7fSPeter Avalos 	packet_send();
156018de8d7fSPeter Avalos 
156118de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
156218de8d7fSPeter Avalos 	return 1;
156318de8d7fSPeter Avalos }
156418de8d7fSPeter Avalos 
156518de8d7fSPeter Avalos /*
156618de8d7fSPeter Avalos  * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
156718de8d7fSPeter Avalos  */
1568e9778795SPeter Avalos int
1569*ce74bacaSMatthew Dillon input_userauth_info_req(int type, u_int32_t seq, struct ssh *ssh)
157018de8d7fSPeter Avalos {
1571*ce74bacaSMatthew Dillon 	Authctxt *authctxt = ssh->authctxt;
157218de8d7fSPeter Avalos 	char *name, *inst, *lang, *prompt, *response;
157318de8d7fSPeter Avalos 	u_int num_prompts, i;
157418de8d7fSPeter Avalos 	int echo = 0;
157518de8d7fSPeter Avalos 
157618de8d7fSPeter Avalos 	debug2("input_userauth_info_req");
157718de8d7fSPeter Avalos 
157818de8d7fSPeter Avalos 	if (authctxt == NULL)
157918de8d7fSPeter Avalos 		fatal("input_userauth_info_req: no authentication context");
158018de8d7fSPeter Avalos 
158118de8d7fSPeter Avalos 	authctxt->info_req_seen = 1;
158218de8d7fSPeter Avalos 
158318de8d7fSPeter Avalos 	name = packet_get_string(NULL);
158418de8d7fSPeter Avalos 	inst = packet_get_string(NULL);
158518de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
158618de8d7fSPeter Avalos 	if (strlen(name) > 0)
158718de8d7fSPeter Avalos 		logit("%s", name);
158818de8d7fSPeter Avalos 	if (strlen(inst) > 0)
158918de8d7fSPeter Avalos 		logit("%s", inst);
159036e94dc5SPeter Avalos 	free(name);
159136e94dc5SPeter Avalos 	free(inst);
159236e94dc5SPeter Avalos 	free(lang);
159318de8d7fSPeter Avalos 
159418de8d7fSPeter Avalos 	num_prompts = packet_get_int();
159518de8d7fSPeter Avalos 	/*
159618de8d7fSPeter Avalos 	 * Begin to build info response packet based on prompts requested.
159718de8d7fSPeter Avalos 	 * We commit to providing the correct number of responses, so if
159818de8d7fSPeter Avalos 	 * further on we run into a problem that prevents this, we have to
159918de8d7fSPeter Avalos 	 * be sure and clean this up and send a correct error response.
160018de8d7fSPeter Avalos 	 */
160118de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
160218de8d7fSPeter Avalos 	packet_put_int(num_prompts);
160318de8d7fSPeter Avalos 
160418de8d7fSPeter Avalos 	debug2("input_userauth_info_req: num_prompts %d", num_prompts);
160518de8d7fSPeter Avalos 	for (i = 0; i < num_prompts; i++) {
160618de8d7fSPeter Avalos 		prompt = packet_get_string(NULL);
160718de8d7fSPeter Avalos 		echo = packet_get_char();
160818de8d7fSPeter Avalos 
160918de8d7fSPeter Avalos 		response = read_passphrase(prompt, echo ? RP_ECHO : 0);
161018de8d7fSPeter Avalos 
161118de8d7fSPeter Avalos 		packet_put_cstring(response);
161236e94dc5SPeter Avalos 		explicit_bzero(response, strlen(response));
161336e94dc5SPeter Avalos 		free(response);
161436e94dc5SPeter Avalos 		free(prompt);
161518de8d7fSPeter Avalos 	}
161618de8d7fSPeter Avalos 	packet_check_eom(); /* done with parsing incoming message. */
161718de8d7fSPeter Avalos 
161818de8d7fSPeter Avalos 	packet_add_padding(64);
161918de8d7fSPeter Avalos 	packet_send();
1620e9778795SPeter Avalos 	return 0;
162118de8d7fSPeter Avalos }
162218de8d7fSPeter Avalos 
162318de8d7fSPeter Avalos static int
1624e9778795SPeter Avalos ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp,
1625e9778795SPeter Avalos     const u_char *data, size_t datalen)
162618de8d7fSPeter Avalos {
1627e9778795SPeter Avalos 	struct sshbuf *b;
162818de8d7fSPeter Avalos 	struct stat st;
162918de8d7fSPeter Avalos 	pid_t pid;
1630e9778795SPeter Avalos 	int i, r, to[2], from[2], status, sock = packet_get_connection_in();
1631e9778795SPeter Avalos 	u_char rversion = 0, version = 2;
1632e9778795SPeter Avalos 	void (*osigchld)(int);
163318de8d7fSPeter Avalos 
1634e9778795SPeter Avalos 	*sigp = NULL;
1635e9778795SPeter Avalos 	*lenp = 0;
163618de8d7fSPeter Avalos 
163718de8d7fSPeter Avalos 	if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1638e9778795SPeter Avalos 		error("%s: not installed: %s", __func__, strerror(errno));
163918de8d7fSPeter Avalos 		return -1;
164018de8d7fSPeter Avalos 	}
1641e9778795SPeter Avalos 	if (fflush(stdout) != 0) {
1642e9778795SPeter Avalos 		error("%s: fflush: %s", __func__, strerror(errno));
1643e9778795SPeter Avalos 		return -1;
1644e9778795SPeter Avalos 	}
164518de8d7fSPeter Avalos 	if (pipe(to) < 0) {
1646e9778795SPeter Avalos 		error("%s: pipe: %s", __func__, strerror(errno));
164718de8d7fSPeter Avalos 		return -1;
164818de8d7fSPeter Avalos 	}
164918de8d7fSPeter Avalos 	if (pipe(from) < 0) {
1650e9778795SPeter Avalos 		error("%s: pipe: %s", __func__, strerror(errno));
165118de8d7fSPeter Avalos 		return -1;
165218de8d7fSPeter Avalos 	}
165318de8d7fSPeter Avalos 	if ((pid = fork()) < 0) {
1654e9778795SPeter Avalos 		error("%s: fork: %s", __func__, strerror(errno));
165518de8d7fSPeter Avalos 		return -1;
165618de8d7fSPeter Avalos 	}
1657e9778795SPeter Avalos 	osigchld = signal(SIGCHLD, SIG_DFL);
165818de8d7fSPeter Avalos 	if (pid == 0) {
1659856ea928SPeter Avalos 		/* keep the socket on exec */
1660e9778795SPeter Avalos 		fcntl(sock, F_SETFD, 0);
166118de8d7fSPeter Avalos 		permanently_drop_suid(getuid());
166218de8d7fSPeter Avalos 		close(from[0]);
166318de8d7fSPeter Avalos 		if (dup2(from[1], STDOUT_FILENO) < 0)
1664e9778795SPeter Avalos 			fatal("%s: dup2: %s", __func__, strerror(errno));
166518de8d7fSPeter Avalos 		close(to[1]);
166618de8d7fSPeter Avalos 		if (dup2(to[0], STDIN_FILENO) < 0)
1667e9778795SPeter Avalos 			fatal("%s: dup2: %s", __func__, strerror(errno));
166818de8d7fSPeter Avalos 		close(from[1]);
166918de8d7fSPeter Avalos 		close(to[0]);
1670e9778795SPeter Avalos 		/* Close everything but stdio and the socket */
1671e9778795SPeter Avalos 		for (i = STDERR_FILENO + 1; i < sock; i++)
1672e9778795SPeter Avalos 			close(i);
1673e9778795SPeter Avalos 		closefrom(sock + 1);
1674e9778795SPeter Avalos 		debug3("%s: [child] pid=%ld, exec %s",
1675e9778795SPeter Avalos 		    __func__, (long)getpid(), _PATH_SSH_KEY_SIGN);
1676e9778795SPeter Avalos 		execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL);
1677e9778795SPeter Avalos 		fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN,
167818de8d7fSPeter Avalos 		    strerror(errno));
167918de8d7fSPeter Avalos 	}
168018de8d7fSPeter Avalos 	close(from[1]);
168118de8d7fSPeter Avalos 	close(to[0]);
168218de8d7fSPeter Avalos 
1683e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL)
1684e9778795SPeter Avalos 		fatal("%s: sshbuf_new failed", __func__);
1685e9778795SPeter Avalos 	/* send # of sock, data to be signed */
1686*ce74bacaSMatthew Dillon 	if ((r = sshbuf_put_u32(b, sock)) != 0 ||
1687e9778795SPeter Avalos 	    (r = sshbuf_put_string(b, data, datalen)) != 0)
1688e9778795SPeter Avalos 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1689e9778795SPeter Avalos 	if (ssh_msg_send(to[1], version, b) == -1)
1690e9778795SPeter Avalos 		fatal("%s: couldn't send request", __func__);
1691e9778795SPeter Avalos 	sshbuf_reset(b);
1692e9778795SPeter Avalos 	r = ssh_msg_recv(from[0], b);
169318de8d7fSPeter Avalos 	close(from[0]);
169418de8d7fSPeter Avalos 	close(to[1]);
1695e9778795SPeter Avalos 	if (r < 0) {
1696e9778795SPeter Avalos 		error("%s: no reply", __func__);
1697e9778795SPeter Avalos 		goto fail;
1698e9778795SPeter Avalos 	}
169918de8d7fSPeter Avalos 
1700e9778795SPeter Avalos 	errno = 0;
1701e9778795SPeter Avalos 	while (waitpid(pid, &status, 0) < 0) {
1702e9778795SPeter Avalos 		if (errno != EINTR) {
1703e9778795SPeter Avalos 			error("%s: waitpid %ld: %s",
1704e9778795SPeter Avalos 			    __func__, (long)pid, strerror(errno));
1705e9778795SPeter Avalos 			goto fail;
1706e9778795SPeter Avalos 		}
1707e9778795SPeter Avalos 	}
1708e9778795SPeter Avalos 	if (!WIFEXITED(status)) {
1709e9778795SPeter Avalos 		error("%s: exited abnormally", __func__);
1710e9778795SPeter Avalos 		goto fail;
1711e9778795SPeter Avalos 	}
1712e9778795SPeter Avalos 	if (WEXITSTATUS(status) != 0) {
1713e9778795SPeter Avalos 		error("%s: exited with status %d",
1714e9778795SPeter Avalos 		    __func__, WEXITSTATUS(status));
1715e9778795SPeter Avalos 		goto fail;
1716e9778795SPeter Avalos 	}
1717e9778795SPeter Avalos 	if ((r = sshbuf_get_u8(b, &rversion)) != 0) {
1718e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1719e9778795SPeter Avalos 		goto fail;
1720e9778795SPeter Avalos 	}
1721e9778795SPeter Avalos 	if (rversion != version) {
1722e9778795SPeter Avalos 		error("%s: bad version", __func__);
1723e9778795SPeter Avalos 		goto fail;
1724e9778795SPeter Avalos 	}
1725e9778795SPeter Avalos 	if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) {
1726e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1727e9778795SPeter Avalos  fail:
1728e9778795SPeter Avalos 		signal(SIGCHLD, osigchld);
1729e9778795SPeter Avalos 		sshbuf_free(b);
173018de8d7fSPeter Avalos 		return -1;
173118de8d7fSPeter Avalos 	}
1732e9778795SPeter Avalos 	signal(SIGCHLD, osigchld);
1733e9778795SPeter Avalos 	sshbuf_free(b);
173418de8d7fSPeter Avalos 
173518de8d7fSPeter Avalos 	return 0;
173618de8d7fSPeter Avalos }
173718de8d7fSPeter Avalos 
173818de8d7fSPeter Avalos int
173918de8d7fSPeter Avalos userauth_hostbased(Authctxt *authctxt)
174018de8d7fSPeter Avalos {
1741e9778795SPeter Avalos 	struct ssh *ssh = active_state;
1742e9778795SPeter Avalos 	struct sshkey *private = NULL;
1743e9778795SPeter Avalos 	struct sshbuf *b = NULL;
174418de8d7fSPeter Avalos 	const char *service;
1745e9778795SPeter Avalos 	u_char *sig = NULL, *keyblob = NULL;
1746e9778795SPeter Avalos 	char *fp = NULL, *chost = NULL, *lname = NULL;
1747e9778795SPeter Avalos 	size_t siglen = 0, keylen = 0;
1748e9778795SPeter Avalos 	int i, r, success = 0;
1749e9778795SPeter Avalos 
1750e9778795SPeter Avalos 	if (authctxt->ktypes == NULL) {
1751e9778795SPeter Avalos 		authctxt->oktypes = xstrdup(options.hostbased_key_types);
1752e9778795SPeter Avalos 		authctxt->ktypes = authctxt->oktypes;
1753e9778795SPeter Avalos 	}
1754e9778795SPeter Avalos 
1755e9778795SPeter Avalos 	/*
1756e9778795SPeter Avalos 	 * Work through each listed type pattern in HostbasedKeyTypes,
1757e9778795SPeter Avalos 	 * trying each hostkey that matches the type in turn.
1758e9778795SPeter Avalos 	 */
1759e9778795SPeter Avalos 	for (;;) {
1760e9778795SPeter Avalos 		if (authctxt->active_ktype == NULL)
1761e9778795SPeter Avalos 			authctxt->active_ktype = strsep(&authctxt->ktypes, ",");
1762e9778795SPeter Avalos 		if (authctxt->active_ktype == NULL ||
1763e9778795SPeter Avalos 		    *authctxt->active_ktype == '\0')
1764e9778795SPeter Avalos 			break;
1765e9778795SPeter Avalos 		debug3("%s: trying key type %s", __func__,
1766e9778795SPeter Avalos 		    authctxt->active_ktype);
176718de8d7fSPeter Avalos 
176818de8d7fSPeter Avalos 		/* check for a useful key */
1769e9778795SPeter Avalos 		private = NULL;
1770e9778795SPeter Avalos 		for (i = 0; i < authctxt->sensitive->nkeys; i++) {
1771e9778795SPeter Avalos 			if (authctxt->sensitive->keys[i] == NULL ||
1772e9778795SPeter Avalos 			    authctxt->sensitive->keys[i]->type == KEY_UNSPEC)
1773e9778795SPeter Avalos 				continue;
1774e9778795SPeter Avalos 			if (match_pattern_list(
1775e9778795SPeter Avalos 			    sshkey_ssh_name(authctxt->sensitive->keys[i]),
1776e9778795SPeter Avalos 			    authctxt->active_ktype, 0) != 1)
1777e9778795SPeter Avalos 				continue;
177818de8d7fSPeter Avalos 			/* we take and free the key */
1779e9778795SPeter Avalos 			private = authctxt->sensitive->keys[i];
1780e9778795SPeter Avalos 			authctxt->sensitive->keys[i] = NULL;
178118de8d7fSPeter Avalos 			break;
178218de8d7fSPeter Avalos 		}
1783e9778795SPeter Avalos 		/* Found one */
1784e9778795SPeter Avalos 		if (private != NULL)
1785e9778795SPeter Avalos 			break;
1786e9778795SPeter Avalos 		/* No more keys of this type; advance */
1787e9778795SPeter Avalos 		authctxt->active_ktype = NULL;
178818de8d7fSPeter Avalos 	}
1789e9778795SPeter Avalos 	if (private == NULL) {
1790e9778795SPeter Avalos 		free(authctxt->oktypes);
1791e9778795SPeter Avalos 		authctxt->oktypes = authctxt->ktypes = NULL;
1792e9778795SPeter Avalos 		authctxt->active_ktype = NULL;
179318de8d7fSPeter Avalos 		debug("No more client hostkeys for hostbased authentication.");
1794e9778795SPeter Avalos 		goto out;
179518de8d7fSPeter Avalos 	}
1796e9778795SPeter Avalos 
1797e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(private, options.fingerprint_hash,
1798e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL) {
1799e9778795SPeter Avalos 		error("%s: sshkey_fingerprint failed", __func__);
1800e9778795SPeter Avalos 		goto out;
180118de8d7fSPeter Avalos 	}
1802e9778795SPeter Avalos 	debug("%s: trying hostkey %s %s",
1803e9778795SPeter Avalos 	    __func__, sshkey_ssh_name(private), fp);
1804e9778795SPeter Avalos 
180518de8d7fSPeter Avalos 	/* figure out a name for the client host */
1806e9778795SPeter Avalos 	if ((lname = get_local_name(packet_get_connection_in())) == NULL) {
1807e9778795SPeter Avalos 		error("%s: cannot get local ipaddr/name", __func__);
1808e9778795SPeter Avalos 		goto out;
180918de8d7fSPeter Avalos 	}
1810e9778795SPeter Avalos 
1811e9778795SPeter Avalos 	/* XXX sshbuf_put_stringf? */
1812e9778795SPeter Avalos 	xasprintf(&chost, "%s.", lname);
1813e9778795SPeter Avalos 	debug2("%s: chost %s", __func__, chost);
181418de8d7fSPeter Avalos 
181518de8d7fSPeter Avalos 	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
181618de8d7fSPeter Avalos 	    authctxt->service;
181718de8d7fSPeter Avalos 
1818e9778795SPeter Avalos 	/* construct data */
1819e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL) {
1820e9778795SPeter Avalos 		error("%s: sshbuf_new failed", __func__);
1821e9778795SPeter Avalos 		goto out;
1822e9778795SPeter Avalos 	}
1823e9778795SPeter Avalos 	if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) {
1824e9778795SPeter Avalos 		error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
1825e9778795SPeter Avalos 		goto out;
1826e9778795SPeter Avalos 	}
1827e9778795SPeter Avalos 	if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
1828e9778795SPeter Avalos 	    (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1829e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 ||
1830e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, service)) != 0 ||
1831e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 ||
1832e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 ||
1833e9778795SPeter Avalos 	    (r = sshbuf_put_string(b, keyblob, keylen)) != 0 ||
1834e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, chost)) != 0 ||
1835e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) {
1836e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1837e9778795SPeter Avalos 		goto out;
1838e9778795SPeter Avalos 	}
1839e9778795SPeter Avalos 
1840e9778795SPeter Avalos #ifdef DEBUG_PK
1841e9778795SPeter Avalos 	sshbuf_dump(b, stderr);
1842e9778795SPeter Avalos #endif
1843e9778795SPeter Avalos 	if (authctxt->sensitive->external_keysign)
1844e9778795SPeter Avalos 		r = ssh_keysign(private, &sig, &siglen,
1845e9778795SPeter Avalos 		    sshbuf_ptr(b), sshbuf_len(b));
1846e9778795SPeter Avalos 	else if ((r = sshkey_sign(private, &sig, &siglen,
1847e9778795SPeter Avalos 	    sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0)
1848e9778795SPeter Avalos 		debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1849e9778795SPeter Avalos 	if (r != 0) {
1850e9778795SPeter Avalos 		error("sign using hostkey %s %s failed",
1851e9778795SPeter Avalos 		    sshkey_ssh_name(private), fp);
1852e9778795SPeter Avalos 		goto out;
1853e9778795SPeter Avalos 	}
1854e9778795SPeter Avalos 	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1855e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1856e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1857e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1858e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 ||
1859e9778795SPeter Avalos 	    (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 ||
1860e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, chost)) != 0 ||
1861e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 ||
1862e9778795SPeter Avalos 	    (r = sshpkt_put_string(ssh, sig, siglen)) != 0 ||
1863e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0) {
1864e9778795SPeter Avalos 		error("%s: packet error: %s", __func__, ssh_err(r));
1865e9778795SPeter Avalos 		goto out;
1866e9778795SPeter Avalos 	}
1867e9778795SPeter Avalos 	success = 1;
1868e9778795SPeter Avalos 
1869e9778795SPeter Avalos  out:
1870e9778795SPeter Avalos 	if (sig != NULL) {
1871e9778795SPeter Avalos 		explicit_bzero(sig, siglen);
1872e9778795SPeter Avalos 		free(sig);
1873e9778795SPeter Avalos 	}
1874e9778795SPeter Avalos 	free(keyblob);
1875e9778795SPeter Avalos 	free(lname);
1876e9778795SPeter Avalos 	free(fp);
1877e9778795SPeter Avalos 	free(chost);
1878e9778795SPeter Avalos 	sshkey_free(private);
1879e9778795SPeter Avalos 	sshbuf_free(b);
1880e9778795SPeter Avalos 
1881e9778795SPeter Avalos 	return success;
188218de8d7fSPeter Avalos }
188318de8d7fSPeter Avalos 
188418de8d7fSPeter Avalos /* find auth method */
188518de8d7fSPeter Avalos 
188618de8d7fSPeter Avalos /*
188718de8d7fSPeter Avalos  * given auth method name, if configurable options permit this method fill
188818de8d7fSPeter Avalos  * in auth_ident field and return true, otherwise return false.
188918de8d7fSPeter Avalos  */
189018de8d7fSPeter Avalos static int
189118de8d7fSPeter Avalos authmethod_is_enabled(Authmethod *method)
189218de8d7fSPeter Avalos {
189318de8d7fSPeter Avalos 	if (method == NULL)
189418de8d7fSPeter Avalos 		return 0;
189518de8d7fSPeter Avalos 	/* return false if options indicate this method is disabled */
189618de8d7fSPeter Avalos 	if  (method->enabled == NULL || *method->enabled == 0)
189718de8d7fSPeter Avalos 		return 0;
189818de8d7fSPeter Avalos 	/* return false if batch mode is enabled but method needs interactive mode */
189918de8d7fSPeter Avalos 	if  (method->batch_flag != NULL && *method->batch_flag != 0)
190018de8d7fSPeter Avalos 		return 0;
190118de8d7fSPeter Avalos 	return 1;
190218de8d7fSPeter Avalos }
190318de8d7fSPeter Avalos 
190418de8d7fSPeter Avalos static Authmethod *
190518de8d7fSPeter Avalos authmethod_lookup(const char *name)
190618de8d7fSPeter Avalos {
190718de8d7fSPeter Avalos 	Authmethod *method = NULL;
190818de8d7fSPeter Avalos 	if (name != NULL)
190918de8d7fSPeter Avalos 		for (method = authmethods; method->name != NULL; method++)
191018de8d7fSPeter Avalos 			if (strcmp(name, method->name) == 0)
191118de8d7fSPeter Avalos 				return method;
191218de8d7fSPeter Avalos 	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
191318de8d7fSPeter Avalos 	return NULL;
191418de8d7fSPeter Avalos }
191518de8d7fSPeter Avalos 
191618de8d7fSPeter Avalos /* XXX internal state */
191718de8d7fSPeter Avalos static Authmethod *current = NULL;
191818de8d7fSPeter Avalos static char *supported = NULL;
191918de8d7fSPeter Avalos static char *preferred = NULL;
192018de8d7fSPeter Avalos 
192118de8d7fSPeter Avalos /*
192218de8d7fSPeter Avalos  * Given the authentication method list sent by the server, return the
192318de8d7fSPeter Avalos  * next method we should try.  If the server initially sends a nil list,
192418de8d7fSPeter Avalos  * use a built-in default list.
192518de8d7fSPeter Avalos  */
192618de8d7fSPeter Avalos static Authmethod *
192718de8d7fSPeter Avalos authmethod_get(char *authlist)
192818de8d7fSPeter Avalos {
192918de8d7fSPeter Avalos 	char *name = NULL;
193018de8d7fSPeter Avalos 	u_int next;
193118de8d7fSPeter Avalos 
193218de8d7fSPeter Avalos 	/* Use a suitable default if we're passed a nil list.  */
193318de8d7fSPeter Avalos 	if (authlist == NULL || strlen(authlist) == 0)
193418de8d7fSPeter Avalos 		authlist = options.preferred_authentications;
193518de8d7fSPeter Avalos 
193618de8d7fSPeter Avalos 	if (supported == NULL || strcmp(authlist, supported) != 0) {
193718de8d7fSPeter Avalos 		debug3("start over, passed a different list %s", authlist);
193836e94dc5SPeter Avalos 		free(supported);
193918de8d7fSPeter Avalos 		supported = xstrdup(authlist);
194018de8d7fSPeter Avalos 		preferred = options.preferred_authentications;
194118de8d7fSPeter Avalos 		debug3("preferred %s", preferred);
194218de8d7fSPeter Avalos 		current = NULL;
194318de8d7fSPeter Avalos 	} else if (current != NULL && authmethod_is_enabled(current))
194418de8d7fSPeter Avalos 		return current;
194518de8d7fSPeter Avalos 
194618de8d7fSPeter Avalos 	for (;;) {
194718de8d7fSPeter Avalos 		if ((name = match_list(preferred, supported, &next)) == NULL) {
194818de8d7fSPeter Avalos 			debug("No more authentication methods to try.");
194918de8d7fSPeter Avalos 			current = NULL;
195018de8d7fSPeter Avalos 			return NULL;
195118de8d7fSPeter Avalos 		}
195218de8d7fSPeter Avalos 		preferred += next;
195318de8d7fSPeter Avalos 		debug3("authmethod_lookup %s", name);
195418de8d7fSPeter Avalos 		debug3("remaining preferred: %s", preferred);
195518de8d7fSPeter Avalos 		if ((current = authmethod_lookup(name)) != NULL &&
195618de8d7fSPeter Avalos 		    authmethod_is_enabled(current)) {
195718de8d7fSPeter Avalos 			debug3("authmethod_is_enabled %s", name);
195818de8d7fSPeter Avalos 			debug("Next authentication method: %s", name);
195936e94dc5SPeter Avalos 			free(name);
196018de8d7fSPeter Avalos 			return current;
196118de8d7fSPeter Avalos 		}
196236e94dc5SPeter Avalos 		free(name);
196318de8d7fSPeter Avalos 	}
196418de8d7fSPeter Avalos }
196518de8d7fSPeter Avalos 
196618de8d7fSPeter Avalos static char *
196718de8d7fSPeter Avalos authmethods_get(void)
196818de8d7fSPeter Avalos {
196918de8d7fSPeter Avalos 	Authmethod *method = NULL;
197018de8d7fSPeter Avalos 	Buffer b;
197118de8d7fSPeter Avalos 	char *list;
197218de8d7fSPeter Avalos 
197318de8d7fSPeter Avalos 	buffer_init(&b);
197418de8d7fSPeter Avalos 	for (method = authmethods; method->name != NULL; method++) {
197518de8d7fSPeter Avalos 		if (authmethod_is_enabled(method)) {
197618de8d7fSPeter Avalos 			if (buffer_len(&b) > 0)
197718de8d7fSPeter Avalos 				buffer_append(&b, ",", 1);
197818de8d7fSPeter Avalos 			buffer_append(&b, method->name, strlen(method->name));
197918de8d7fSPeter Avalos 		}
198018de8d7fSPeter Avalos 	}
1981e9778795SPeter Avalos 	if ((list = sshbuf_dup_string(&b)) == NULL)
1982e9778795SPeter Avalos 		fatal("%s: sshbuf_dup_string failed", __func__);
198318de8d7fSPeter Avalos 	buffer_free(&b);
198418de8d7fSPeter Avalos 	return list;
198518de8d7fSPeter Avalos }
1986cb5eb4f1SPeter Avalos 
1987