xref: /dflybsd-src/crypto/openssh/sshconnect2.c (revision e9778795382169f8c6fde18d0565a1acef2cac8b)
1*e9778795SPeter Avalos /* $OpenBSD: sshconnect2.c,v 1.247 2016/07/22 05:46:11 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"
73*e9778795SPeter Avalos #include "ssherr.h"
74*e9778795SPeter 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*e9778795SPeter Avalos verify_host_key_callback(Key *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') {
134*e9778795SPeter 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,
137*e9778795SPeter 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
143*e9778795SPeter Avalos 	xasprintf(&ret, "%s%s%s", first,
144*e9778795SPeter 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 };
161*e9778795SPeter Avalos 	char *s;
162*e9778795SPeter Avalos 	struct kex *kex;
163*e9778795SPeter Avalos 	int r;
16418de8d7fSPeter Avalos 
16518de8d7fSPeter Avalos 	xxx_host = host;
16618de8d7fSPeter Avalos 	xxx_hostaddr = hostaddr;
16718de8d7fSPeter Avalos 
168*e9778795SPeter Avalos 	if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
169*e9778795SPeter Avalos 		fatal("%s: kex_names_cat", __func__);
170*e9778795SPeter Avalos 	myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
17118de8d7fSPeter Avalos 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
172*e9778795SPeter Avalos 	    compat_cipher_proposal(options.ciphers);
17318de8d7fSPeter Avalos 	myproposal[PROPOSAL_ENC_ALGS_STOC] =
174*e9778795SPeter Avalos 	    compat_cipher_proposal(options.ciphers);
17518de8d7fSPeter Avalos 	myproposal[PROPOSAL_COMP_ALGS_CTOS] =
176*e9778795SPeter Avalos 	    myproposal[PROPOSAL_COMP_ALGS_STOC] = options.compression ?
177*e9778795SPeter 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;
180*e9778795SPeter Avalos 	if (options.hostkeyalgorithms != NULL) {
181*e9778795SPeter Avalos 		if (kex_assemble_names(KEX_DEFAULT_PK_ALG,
182*e9778795SPeter Avalos 		    &options.hostkeyalgorithms) != 0)
183*e9778795SPeter Avalos 			fatal("%s: kex_assemble_namelist", __func__);
18418de8d7fSPeter Avalos 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
18536e94dc5SPeter Avalos 		    compat_pkalg_proposal(options.hostkeyalgorithms);
186*e9778795SPeter Avalos 	} else {
187*e9778795SPeter Avalos 		/* Enforce default */
188*e9778795SPeter 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)
19636e94dc5SPeter Avalos 		packet_set_rekey_limits((u_int32_t)options.rekey_limit,
19736e94dc5SPeter Avalos 		    (time_t)options.rekey_interval);
19818de8d7fSPeter Avalos 
19918de8d7fSPeter Avalos 	/* start key exchange */
200*e9778795SPeter Avalos 	if ((r = kex_setup(active_state, myproposal)) != 0)
201*e9778795SPeter Avalos 		fatal("kex_setup: %s", ssh_err(r));
202*e9778795SPeter 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;
206*e9778795SPeter Avalos 	kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client;
207*e9778795SPeter Avalos 	kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client;
208*e9778795SPeter 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;
211*e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC
2129f304aafSPeter Avalos 	kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
21336e94dc5SPeter Avalos # endif
214*e9778795SPeter 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*e9778795SPeter Avalos 	dispatch_run(DISPATCH_BLOCK, &kex->done, active_state);
22118de8d7fSPeter Avalos 
222*e9778795SPeter Avalos 	/* remove ext-info from the KEX proposals for rekeying */
223*e9778795SPeter Avalos 	myproposal[PROPOSAL_KEX_ALGS] =
224*e9778795SPeter Avalos 	    compat_kex_proposal(options.kex_algorithms);
225*e9778795SPeter Avalos 	if ((r = kex_prop2buf(kex->my, myproposal)) != 0)
226*e9778795SPeter 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 
244*e9778795SPeter Avalos typedef struct cauthctxt Authctxt;
245*e9778795SPeter 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;
251*e9778795SPeter Avalos 	int	agent_fd;		/* >=0 if agent supports key */
252*e9778795SPeter 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 
260*e9778795SPeter 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;
265*e9778795SPeter Avalos 	struct cauthmethod *method;
266856ea928SPeter Avalos 	sig_atomic_t success;
26718de8d7fSPeter Avalos 	char *authlist;
268*e9778795SPeter Avalos 	int attempt;
26918de8d7fSPeter Avalos 	/* pubkey */
270*e9778795SPeter Avalos 	struct idlist keys;
271*e9778795SPeter Avalos 	int agent_fd;
27218de8d7fSPeter Avalos 	/* hostbased */
27318de8d7fSPeter Avalos 	Sensitive *sensitive;
274*e9778795SPeter Avalos 	char *oktypes, *ktypes;
275*e9778795SPeter Avalos 	const char *active_ktype;
27618de8d7fSPeter Avalos 	/* kbd-interactive */
27718de8d7fSPeter Avalos 	int info_req_seen;
27818de8d7fSPeter Avalos 	/* generic */
27918de8d7fSPeter Avalos 	void *methoddata;
28018de8d7fSPeter Avalos };
281*e9778795SPeter Avalos 
282*e9778795SPeter 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*e9778795SPeter Avalos int	input_userauth_service_accept(int, u_int32_t, void *);
291*e9778795SPeter Avalos int	input_userauth_ext_info(int, u_int32_t, void *);
292*e9778795SPeter Avalos int	input_userauth_success(int, u_int32_t, void *);
293*e9778795SPeter Avalos int	input_userauth_success_unexpected(int, u_int32_t, void *);
294*e9778795SPeter Avalos int	input_userauth_failure(int, u_int32_t, void *);
295*e9778795SPeter Avalos int	input_userauth_banner(int, u_int32_t, void *);
296*e9778795SPeter Avalos int	input_userauth_error(int, u_int32_t, void *);
297*e9778795SPeter Avalos int	input_userauth_info_req(int, u_int32_t, void *);
298*e9778795SPeter Avalos int	input_userauth_pk_ok(int, u_int32_t, void *);
299*e9778795SPeter Avalos int	input_userauth_passwd_changereq(int, u_int32_t, void *);
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*e9778795SPeter Avalos int	input_gssapi_response(int type, u_int32_t, void *);
310*e9778795SPeter Avalos int	input_gssapi_token(int type, u_int32_t, void *);
311*e9778795SPeter Avalos int	input_gssapi_hash(int type, u_int32_t, void *);
312*e9778795SPeter Avalos int	input_gssapi_error(int, u_int32_t, void *);
313*e9778795SPeter Avalos int	input_gssapi_errtok(int, u_int32_t, void *);
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*e9778795SPeter Avalos static Key *load_identity_file(Identity *);
32218de8d7fSPeter Avalos 
32318de8d7fSPeter Avalos static Authmethod *authmethod_get(char *authlist);
32418de8d7fSPeter Avalos static Authmethod *authmethod_lookup(const char *name);
32518de8d7fSPeter Avalos static char *authmethods_get(void);
32618de8d7fSPeter Avalos 
32718de8d7fSPeter Avalos Authmethod authmethods[] = {
32818de8d7fSPeter Avalos #ifdef GSSAPI
32918de8d7fSPeter Avalos 	{"gssapi-with-mic",
33018de8d7fSPeter Avalos 		userauth_gssapi,
331cb5eb4f1SPeter Avalos 		NULL,
33218de8d7fSPeter Avalos 		&options.gss_authentication,
33318de8d7fSPeter Avalos 		NULL},
33418de8d7fSPeter Avalos #endif
33518de8d7fSPeter Avalos 	{"hostbased",
33618de8d7fSPeter Avalos 		userauth_hostbased,
337cb5eb4f1SPeter Avalos 		NULL,
33818de8d7fSPeter Avalos 		&options.hostbased_authentication,
33918de8d7fSPeter Avalos 		NULL},
34018de8d7fSPeter Avalos 	{"publickey",
34118de8d7fSPeter Avalos 		userauth_pubkey,
342cb5eb4f1SPeter Avalos 		NULL,
34318de8d7fSPeter Avalos 		&options.pubkey_authentication,
34418de8d7fSPeter Avalos 		NULL},
34518de8d7fSPeter Avalos 	{"keyboard-interactive",
34618de8d7fSPeter Avalos 		userauth_kbdint,
347cb5eb4f1SPeter Avalos 		NULL,
34818de8d7fSPeter Avalos 		&options.kbd_interactive_authentication,
34918de8d7fSPeter Avalos 		&options.batch_mode},
35018de8d7fSPeter Avalos 	{"password",
35118de8d7fSPeter Avalos 		userauth_passwd,
352cb5eb4f1SPeter Avalos 		NULL,
35318de8d7fSPeter Avalos 		&options.password_authentication,
35418de8d7fSPeter Avalos 		&options.batch_mode},
35518de8d7fSPeter Avalos 	{"none",
35618de8d7fSPeter Avalos 		userauth_none,
35718de8d7fSPeter Avalos 		NULL,
358cb5eb4f1SPeter Avalos 		NULL,
35918de8d7fSPeter Avalos 		NULL},
360cb5eb4f1SPeter Avalos 	{NULL, NULL, NULL, NULL, NULL}
36118de8d7fSPeter Avalos };
36218de8d7fSPeter Avalos 
36318de8d7fSPeter Avalos void
36418de8d7fSPeter Avalos ssh_userauth2(const char *local_user, const char *server_user, char *host,
36518de8d7fSPeter Avalos     Sensitive *sensitive)
36618de8d7fSPeter Avalos {
367*e9778795SPeter Avalos 	struct ssh *ssh = active_state;
36818de8d7fSPeter Avalos 	Authctxt authctxt;
369*e9778795SPeter Avalos 	int r;
37018de8d7fSPeter Avalos 
37118de8d7fSPeter Avalos 	if (options.challenge_response_authentication)
37218de8d7fSPeter Avalos 		options.kbd_interactive_authentication = 1;
37318de8d7fSPeter Avalos 	if (options.preferred_authentications == NULL)
37418de8d7fSPeter Avalos 		options.preferred_authentications = authmethods_get();
37518de8d7fSPeter Avalos 
37618de8d7fSPeter Avalos 	/* setup authentication context */
37718de8d7fSPeter Avalos 	memset(&authctxt, 0, sizeof(authctxt));
37818de8d7fSPeter Avalos 	pubkey_prepare(&authctxt);
37918de8d7fSPeter Avalos 	authctxt.server_user = server_user;
38018de8d7fSPeter Avalos 	authctxt.local_user = local_user;
38118de8d7fSPeter Avalos 	authctxt.host = host;
38218de8d7fSPeter Avalos 	authctxt.service = "ssh-connection";		/* service name */
38318de8d7fSPeter Avalos 	authctxt.success = 0;
38418de8d7fSPeter Avalos 	authctxt.method = authmethod_lookup("none");
38518de8d7fSPeter Avalos 	authctxt.authlist = NULL;
38618de8d7fSPeter Avalos 	authctxt.methoddata = NULL;
38718de8d7fSPeter Avalos 	authctxt.sensitive = sensitive;
388*e9778795SPeter Avalos 	authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL;
38918de8d7fSPeter Avalos 	authctxt.info_req_seen = 0;
390*e9778795SPeter Avalos 	authctxt.agent_fd = -1;
39118de8d7fSPeter Avalos 	if (authctxt.method == NULL)
39218de8d7fSPeter Avalos 		fatal("ssh_userauth2: internal error: cannot send userauth none request");
39318de8d7fSPeter Avalos 
394*e9778795SPeter Avalos 	if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 ||
395*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 ||
396*e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0)
397*e9778795SPeter Avalos 		fatal("%s: %s", __func__, ssh_err(r));
39818de8d7fSPeter Avalos 
399*e9778795SPeter Avalos 	ssh_dispatch_init(ssh, &input_userauth_error);
400*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
401*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
402*e9778795SPeter Avalos 	ssh_dispatch_run(ssh, DISPATCH_BLOCK, &authctxt.success, &authctxt);	/* loop until success */
40318de8d7fSPeter Avalos 
40418de8d7fSPeter Avalos 	pubkey_cleanup(&authctxt);
405*e9778795SPeter Avalos 	ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
40618de8d7fSPeter Avalos 
40718de8d7fSPeter Avalos 	debug("Authentication succeeded (%s).", authctxt.method->name);
40818de8d7fSPeter Avalos }
40918de8d7fSPeter Avalos 
410*e9778795SPeter Avalos /* ARGSUSED */
411*e9778795SPeter Avalos int
412*e9778795SPeter Avalos input_userauth_service_accept(int type, u_int32_t seqnr, void *ctxt)
413*e9778795SPeter Avalos {
414*e9778795SPeter Avalos 	Authctxt *authctxt = ctxt;
415*e9778795SPeter Avalos 	struct ssh *ssh = active_state;
416*e9778795SPeter Avalos 	int r;
417*e9778795SPeter Avalos 
418*e9778795SPeter Avalos 	if (ssh_packet_remaining(ssh) > 0) {
419*e9778795SPeter Avalos 		char *reply;
420*e9778795SPeter Avalos 
421*e9778795SPeter Avalos 		if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0)
422*e9778795SPeter Avalos 			goto out;
423*e9778795SPeter Avalos 		debug2("service_accept: %s", reply);
424*e9778795SPeter Avalos 		free(reply);
425*e9778795SPeter Avalos 	} else {
426*e9778795SPeter Avalos 		debug2("buggy server: service_accept w/o service");
427*e9778795SPeter Avalos 	}
428*e9778795SPeter Avalos 	if ((r = sshpkt_get_end(ssh)) != 0)
429*e9778795SPeter Avalos 		goto out;
430*e9778795SPeter Avalos 	debug("SSH2_MSG_SERVICE_ACCEPT received");
431*e9778795SPeter Avalos 
432*e9778795SPeter Avalos 	/* initial userauth request */
433*e9778795SPeter Avalos 	userauth_none(authctxt);
434*e9778795SPeter Avalos 
435*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error);
436*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
437*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
438*e9778795SPeter Avalos 	ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
439*e9778795SPeter Avalos 	r = 0;
440*e9778795SPeter Avalos  out:
441*e9778795SPeter Avalos 	return r;
442*e9778795SPeter Avalos }
443*e9778795SPeter Avalos 
444*e9778795SPeter Avalos /* ARGSUSED */
445*e9778795SPeter Avalos int
446*e9778795SPeter Avalos input_userauth_ext_info(int type, u_int32_t seqnr, void *ctxt)
447*e9778795SPeter Avalos {
448*e9778795SPeter Avalos 	return kex_input_ext_info(type, seqnr, active_state);
449*e9778795SPeter Avalos }
450*e9778795SPeter Avalos 
45118de8d7fSPeter Avalos void
45218de8d7fSPeter Avalos userauth(Authctxt *authctxt, char *authlist)
45318de8d7fSPeter Avalos {
454cb5eb4f1SPeter Avalos 	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
455cb5eb4f1SPeter Avalos 		authctxt->method->cleanup(authctxt);
456cb5eb4f1SPeter Avalos 
45736e94dc5SPeter Avalos 	free(authctxt->methoddata);
45818de8d7fSPeter Avalos 	authctxt->methoddata = NULL;
45918de8d7fSPeter Avalos 	if (authlist == NULL) {
46018de8d7fSPeter Avalos 		authlist = authctxt->authlist;
46118de8d7fSPeter Avalos 	} else {
46236e94dc5SPeter Avalos 		free(authctxt->authlist);
46318de8d7fSPeter Avalos 		authctxt->authlist = authlist;
46418de8d7fSPeter Avalos 	}
46518de8d7fSPeter Avalos 	for (;;) {
46618de8d7fSPeter Avalos 		Authmethod *method = authmethod_get(authlist);
46718de8d7fSPeter Avalos 		if (method == NULL)
46818de8d7fSPeter Avalos 			fatal("Permission denied (%s).", authlist);
46918de8d7fSPeter Avalos 		authctxt->method = method;
47018de8d7fSPeter Avalos 
47118de8d7fSPeter Avalos 		/* reset the per method handler */
47218de8d7fSPeter Avalos 		dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
47318de8d7fSPeter Avalos 		    SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
47418de8d7fSPeter Avalos 
47518de8d7fSPeter Avalos 		/* and try new method */
47618de8d7fSPeter Avalos 		if (method->userauth(authctxt) != 0) {
47718de8d7fSPeter Avalos 			debug2("we sent a %s packet, wait for reply", method->name);
47818de8d7fSPeter Avalos 			break;
47918de8d7fSPeter Avalos 		} else {
48018de8d7fSPeter Avalos 			debug2("we did not send a packet, disable method");
48118de8d7fSPeter Avalos 			method->enabled = NULL;
48218de8d7fSPeter Avalos 		}
48318de8d7fSPeter Avalos 	}
48418de8d7fSPeter Avalos }
48518de8d7fSPeter Avalos 
486cb5eb4f1SPeter Avalos /* ARGSUSED */
487*e9778795SPeter Avalos int
48818de8d7fSPeter Avalos input_userauth_error(int type, u_int32_t seq, void *ctxt)
48918de8d7fSPeter Avalos {
49018de8d7fSPeter Avalos 	fatal("input_userauth_error: bad message during authentication: "
49118de8d7fSPeter Avalos 	    "type %d", type);
492*e9778795SPeter Avalos 	return 0;
49318de8d7fSPeter Avalos }
49418de8d7fSPeter Avalos 
495cb5eb4f1SPeter Avalos /* ARGSUSED */
496*e9778795SPeter Avalos int
49718de8d7fSPeter Avalos input_userauth_banner(int type, u_int32_t seq, void *ctxt)
49818de8d7fSPeter Avalos {
499*e9778795SPeter Avalos 	char *msg, *lang;
50018de8d7fSPeter Avalos 	u_int len;
50118de8d7fSPeter Avalos 
502*e9778795SPeter Avalos 	debug3("%s", __func__);
503*e9778795SPeter Avalos 	msg = packet_get_string(&len);
50418de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
505*e9778795SPeter Avalos 	if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO)
506*e9778795SPeter Avalos 		fmprintf(stderr, "%s", msg);
50736e94dc5SPeter Avalos 	free(msg);
50836e94dc5SPeter Avalos 	free(lang);
509*e9778795SPeter Avalos 	return 0;
51018de8d7fSPeter Avalos }
51118de8d7fSPeter Avalos 
512cb5eb4f1SPeter Avalos /* ARGSUSED */
513*e9778795SPeter Avalos int
51418de8d7fSPeter Avalos input_userauth_success(int type, u_int32_t seq, void *ctxt)
51518de8d7fSPeter Avalos {
51618de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
517856ea928SPeter Avalos 
51818de8d7fSPeter Avalos 	if (authctxt == NULL)
51918de8d7fSPeter Avalos 		fatal("input_userauth_success: no authentication context");
52036e94dc5SPeter Avalos 	free(authctxt->authlist);
52118de8d7fSPeter Avalos 	authctxt->authlist = NULL;
522856ea928SPeter Avalos 	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
523856ea928SPeter Avalos 		authctxt->method->cleanup(authctxt);
52436e94dc5SPeter Avalos 	free(authctxt->methoddata);
52518de8d7fSPeter Avalos 	authctxt->methoddata = NULL;
52618de8d7fSPeter Avalos 	authctxt->success = 1;			/* break out */
527*e9778795SPeter Avalos 	return 0;
52818de8d7fSPeter Avalos }
52918de8d7fSPeter Avalos 
530*e9778795SPeter Avalos int
531856ea928SPeter Avalos input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt)
532856ea928SPeter Avalos {
533856ea928SPeter Avalos 	Authctxt *authctxt = ctxt;
534856ea928SPeter Avalos 
535856ea928SPeter Avalos 	if (authctxt == NULL)
536856ea928SPeter Avalos 		fatal("%s: no authentication context", __func__);
537856ea928SPeter Avalos 
538856ea928SPeter Avalos 	fatal("Unexpected authentication success during %s.",
539856ea928SPeter Avalos 	    authctxt->method->name);
540*e9778795SPeter Avalos 	return 0;
541856ea928SPeter Avalos }
542856ea928SPeter Avalos 
543cb5eb4f1SPeter Avalos /* ARGSUSED */
544*e9778795SPeter Avalos int
54518de8d7fSPeter Avalos input_userauth_failure(int type, u_int32_t seq, void *ctxt)
54618de8d7fSPeter Avalos {
54718de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
54818de8d7fSPeter Avalos 	char *authlist = NULL;
54918de8d7fSPeter Avalos 	int partial;
55018de8d7fSPeter Avalos 
55118de8d7fSPeter Avalos 	if (authctxt == NULL)
55218de8d7fSPeter Avalos 		fatal("input_userauth_failure: no authentication context");
55318de8d7fSPeter Avalos 
55418de8d7fSPeter Avalos 	authlist = packet_get_string(NULL);
55518de8d7fSPeter Avalos 	partial = packet_get_char();
55618de8d7fSPeter Avalos 	packet_check_eom();
55718de8d7fSPeter Avalos 
55836e94dc5SPeter Avalos 	if (partial != 0) {
559*e9778795SPeter Avalos 		verbose("Authenticated with partial success.");
56036e94dc5SPeter Avalos 		/* reset state */
56136e94dc5SPeter Avalos 		pubkey_cleanup(authctxt);
56236e94dc5SPeter Avalos 		pubkey_prepare(authctxt);
56336e94dc5SPeter Avalos 	}
56418de8d7fSPeter Avalos 	debug("Authentications that can continue: %s", authlist);
56518de8d7fSPeter Avalos 
56618de8d7fSPeter Avalos 	userauth(authctxt, authlist);
567*e9778795SPeter Avalos 	return 0;
56818de8d7fSPeter Avalos }
569cb5eb4f1SPeter Avalos 
570cb5eb4f1SPeter Avalos /* ARGSUSED */
571*e9778795SPeter Avalos int
57218de8d7fSPeter Avalos input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
57318de8d7fSPeter Avalos {
57418de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
57518de8d7fSPeter Avalos 	Key *key = NULL;
57618de8d7fSPeter Avalos 	Identity *id = NULL;
57718de8d7fSPeter Avalos 	Buffer b;
57818de8d7fSPeter Avalos 	int pktype, sent = 0;
57918de8d7fSPeter Avalos 	u_int alen, blen;
58018de8d7fSPeter Avalos 	char *pkalg, *fp;
58118de8d7fSPeter Avalos 	u_char *pkblob;
58218de8d7fSPeter Avalos 
58318de8d7fSPeter Avalos 	if (authctxt == NULL)
58418de8d7fSPeter Avalos 		fatal("input_userauth_pk_ok: no authentication context");
58518de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKOK) {
58618de8d7fSPeter Avalos 		/* this is similar to SSH_BUG_PKAUTH */
58718de8d7fSPeter Avalos 		debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
58818de8d7fSPeter Avalos 		pkblob = packet_get_string(&blen);
58918de8d7fSPeter Avalos 		buffer_init(&b);
59018de8d7fSPeter Avalos 		buffer_append(&b, pkblob, blen);
59118de8d7fSPeter Avalos 		pkalg = buffer_get_string(&b, &alen);
59218de8d7fSPeter Avalos 		buffer_free(&b);
59318de8d7fSPeter Avalos 	} else {
59418de8d7fSPeter Avalos 		pkalg = packet_get_string(&alen);
59518de8d7fSPeter Avalos 		pkblob = packet_get_string(&blen);
59618de8d7fSPeter Avalos 	}
59718de8d7fSPeter Avalos 	packet_check_eom();
59818de8d7fSPeter Avalos 
59918de8d7fSPeter Avalos 	debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
60018de8d7fSPeter Avalos 
60118de8d7fSPeter Avalos 	if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
60218de8d7fSPeter Avalos 		debug("unknown pkalg %s", pkalg);
60318de8d7fSPeter Avalos 		goto done;
60418de8d7fSPeter Avalos 	}
60518de8d7fSPeter Avalos 	if ((key = key_from_blob(pkblob, blen)) == NULL) {
60618de8d7fSPeter Avalos 		debug("no key from blob. pkalg %s", pkalg);
60718de8d7fSPeter Avalos 		goto done;
60818de8d7fSPeter Avalos 	}
60918de8d7fSPeter Avalos 	if (key->type != pktype) {
61018de8d7fSPeter Avalos 		error("input_userauth_pk_ok: type mismatch "
61118de8d7fSPeter Avalos 		    "for decoded key (received %d, expected %d)",
61218de8d7fSPeter Avalos 		    key->type, pktype);
61318de8d7fSPeter Avalos 		goto done;
61418de8d7fSPeter Avalos 	}
615*e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
616*e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL)
617*e9778795SPeter Avalos 		goto done;
61818de8d7fSPeter Avalos 	debug2("input_userauth_pk_ok: fp %s", fp);
61936e94dc5SPeter Avalos 	free(fp);
62018de8d7fSPeter Avalos 
62118de8d7fSPeter Avalos 	/*
62218de8d7fSPeter Avalos 	 * search keys in the reverse order, because last candidate has been
62318de8d7fSPeter Avalos 	 * moved to the end of the queue.  this also avoids confusion by
62418de8d7fSPeter Avalos 	 * duplicate keys
62518de8d7fSPeter Avalos 	 */
62618de8d7fSPeter Avalos 	TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
62718de8d7fSPeter Avalos 		if (key_equal(key, id->key)) {
62818de8d7fSPeter Avalos 			sent = sign_and_send_pubkey(authctxt, id);
62918de8d7fSPeter Avalos 			break;
63018de8d7fSPeter Avalos 		}
63118de8d7fSPeter Avalos 	}
63218de8d7fSPeter Avalos done:
63318de8d7fSPeter Avalos 	if (key != NULL)
63418de8d7fSPeter Avalos 		key_free(key);
63536e94dc5SPeter Avalos 	free(pkalg);
63636e94dc5SPeter Avalos 	free(pkblob);
63718de8d7fSPeter Avalos 
63818de8d7fSPeter Avalos 	/* try another method if we did not send a packet */
63918de8d7fSPeter Avalos 	if (sent == 0)
64018de8d7fSPeter Avalos 		userauth(authctxt, NULL);
641*e9778795SPeter Avalos 	return 0;
64218de8d7fSPeter Avalos }
64318de8d7fSPeter Avalos 
64418de8d7fSPeter Avalos #ifdef GSSAPI
64518de8d7fSPeter Avalos int
64618de8d7fSPeter Avalos userauth_gssapi(Authctxt *authctxt)
64718de8d7fSPeter Avalos {
64818de8d7fSPeter Avalos 	Gssctxt *gssctxt = NULL;
64918de8d7fSPeter Avalos 	static gss_OID_set gss_supported = NULL;
65018de8d7fSPeter Avalos 	static u_int mech = 0;
65118de8d7fSPeter Avalos 	OM_uint32 min;
65218de8d7fSPeter Avalos 	int ok = 0;
65318de8d7fSPeter Avalos 
65418de8d7fSPeter Avalos 	/* Try one GSSAPI method at a time, rather than sending them all at
65518de8d7fSPeter Avalos 	 * once. */
65618de8d7fSPeter Avalos 
65718de8d7fSPeter Avalos 	if (gss_supported == NULL)
65818de8d7fSPeter Avalos 		gss_indicate_mechs(&min, &gss_supported);
65918de8d7fSPeter Avalos 
66018de8d7fSPeter Avalos 	/* Check to see if the mechanism is usable before we offer it */
66118de8d7fSPeter Avalos 	while (mech < gss_supported->count && !ok) {
66218de8d7fSPeter Avalos 		/* My DER encoding requires length<128 */
66318de8d7fSPeter Avalos 		if (gss_supported->elements[mech].length < 128 &&
66418de8d7fSPeter Avalos 		    ssh_gssapi_check_mechanism(&gssctxt,
66518de8d7fSPeter Avalos 		    &gss_supported->elements[mech], authctxt->host)) {
66618de8d7fSPeter Avalos 			ok = 1; /* Mechanism works */
66718de8d7fSPeter Avalos 		} else {
66818de8d7fSPeter Avalos 			mech++;
66918de8d7fSPeter Avalos 		}
67018de8d7fSPeter Avalos 	}
67118de8d7fSPeter Avalos 
67218de8d7fSPeter Avalos 	if (!ok)
67318de8d7fSPeter Avalos 		return 0;
67418de8d7fSPeter Avalos 
67518de8d7fSPeter Avalos 	authctxt->methoddata=(void *)gssctxt;
67618de8d7fSPeter Avalos 
67718de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
67818de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
67918de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
68018de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
68118de8d7fSPeter Avalos 
68218de8d7fSPeter Avalos 	packet_put_int(1);
68318de8d7fSPeter Avalos 
68418de8d7fSPeter Avalos 	packet_put_int((gss_supported->elements[mech].length) + 2);
68518de8d7fSPeter Avalos 	packet_put_char(SSH_GSS_OIDTYPE);
68618de8d7fSPeter Avalos 	packet_put_char(gss_supported->elements[mech].length);
68718de8d7fSPeter Avalos 	packet_put_raw(gss_supported->elements[mech].elements,
68818de8d7fSPeter Avalos 	    gss_supported->elements[mech].length);
68918de8d7fSPeter Avalos 
69018de8d7fSPeter Avalos 	packet_send();
69118de8d7fSPeter Avalos 
69218de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
69318de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
69418de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
69518de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
69618de8d7fSPeter Avalos 
69718de8d7fSPeter Avalos 	mech++; /* Move along to next candidate */
69818de8d7fSPeter Avalos 
69918de8d7fSPeter Avalos 	return 1;
70018de8d7fSPeter Avalos }
70118de8d7fSPeter Avalos 
70218de8d7fSPeter Avalos static OM_uint32
70318de8d7fSPeter Avalos process_gssapi_token(void *ctxt, gss_buffer_t recv_tok)
70418de8d7fSPeter Avalos {
70518de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
70618de8d7fSPeter Avalos 	Gssctxt *gssctxt = authctxt->methoddata;
70718de8d7fSPeter Avalos 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
70818de8d7fSPeter Avalos 	gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
70918de8d7fSPeter Avalos 	gss_buffer_desc gssbuf;
71018de8d7fSPeter Avalos 	OM_uint32 status, ms, flags;
71118de8d7fSPeter Avalos 	Buffer b;
71218de8d7fSPeter Avalos 
71318de8d7fSPeter Avalos 	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
71418de8d7fSPeter Avalos 	    recv_tok, &send_tok, &flags);
71518de8d7fSPeter Avalos 
71618de8d7fSPeter Avalos 	if (send_tok.length > 0) {
71718de8d7fSPeter Avalos 		if (GSS_ERROR(status))
71818de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
71918de8d7fSPeter Avalos 		else
72018de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
72118de8d7fSPeter Avalos 
72218de8d7fSPeter Avalos 		packet_put_string(send_tok.value, send_tok.length);
72318de8d7fSPeter Avalos 		packet_send();
72418de8d7fSPeter Avalos 		gss_release_buffer(&ms, &send_tok);
72518de8d7fSPeter Avalos 	}
72618de8d7fSPeter Avalos 
72718de8d7fSPeter Avalos 	if (status == GSS_S_COMPLETE) {
72818de8d7fSPeter Avalos 		/* send either complete or MIC, depending on mechanism */
72918de8d7fSPeter Avalos 		if (!(flags & GSS_C_INTEG_FLAG)) {
73018de8d7fSPeter Avalos 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
73118de8d7fSPeter Avalos 			packet_send();
73218de8d7fSPeter Avalos 		} else {
73318de8d7fSPeter Avalos 			ssh_gssapi_buildmic(&b, authctxt->server_user,
73418de8d7fSPeter Avalos 			    authctxt->service, "gssapi-with-mic");
73518de8d7fSPeter Avalos 
73618de8d7fSPeter Avalos 			gssbuf.value = buffer_ptr(&b);
73718de8d7fSPeter Avalos 			gssbuf.length = buffer_len(&b);
73818de8d7fSPeter Avalos 
73918de8d7fSPeter Avalos 			status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);
74018de8d7fSPeter Avalos 
74118de8d7fSPeter Avalos 			if (!GSS_ERROR(status)) {
74218de8d7fSPeter Avalos 				packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);
74318de8d7fSPeter Avalos 				packet_put_string(mic.value, mic.length);
74418de8d7fSPeter Avalos 
74518de8d7fSPeter Avalos 				packet_send();
74618de8d7fSPeter Avalos 			}
74718de8d7fSPeter Avalos 
74818de8d7fSPeter Avalos 			buffer_free(&b);
74918de8d7fSPeter Avalos 			gss_release_buffer(&ms, &mic);
75018de8d7fSPeter Avalos 		}
75118de8d7fSPeter Avalos 	}
75218de8d7fSPeter Avalos 
75318de8d7fSPeter Avalos 	return status;
75418de8d7fSPeter Avalos }
75518de8d7fSPeter Avalos 
756cb5eb4f1SPeter Avalos /* ARGSUSED */
757*e9778795SPeter Avalos int
75818de8d7fSPeter Avalos input_gssapi_response(int type, u_int32_t plen, void *ctxt)
75918de8d7fSPeter Avalos {
76018de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
76118de8d7fSPeter Avalos 	Gssctxt *gssctxt;
76218de8d7fSPeter Avalos 	int oidlen;
76318de8d7fSPeter Avalos 	char *oidv;
76418de8d7fSPeter Avalos 
76518de8d7fSPeter Avalos 	if (authctxt == NULL)
76618de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
76718de8d7fSPeter Avalos 	gssctxt = authctxt->methoddata;
76818de8d7fSPeter Avalos 
76918de8d7fSPeter Avalos 	/* Setup our OID */
77018de8d7fSPeter Avalos 	oidv = packet_get_string(&oidlen);
77118de8d7fSPeter Avalos 
77218de8d7fSPeter Avalos 	if (oidlen <= 2 ||
77318de8d7fSPeter Avalos 	    oidv[0] != SSH_GSS_OIDTYPE ||
77418de8d7fSPeter Avalos 	    oidv[1] != oidlen - 2) {
77536e94dc5SPeter Avalos 		free(oidv);
77618de8d7fSPeter Avalos 		debug("Badly encoded mechanism OID received");
77718de8d7fSPeter Avalos 		userauth(authctxt, NULL);
778*e9778795SPeter Avalos 		return 0;
77918de8d7fSPeter Avalos 	}
78018de8d7fSPeter Avalos 
78118de8d7fSPeter Avalos 	if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
78218de8d7fSPeter Avalos 		fatal("Server returned different OID than expected");
78318de8d7fSPeter Avalos 
78418de8d7fSPeter Avalos 	packet_check_eom();
78518de8d7fSPeter Avalos 
78636e94dc5SPeter Avalos 	free(oidv);
78718de8d7fSPeter Avalos 
78818de8d7fSPeter Avalos 	if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) {
78918de8d7fSPeter Avalos 		/* Start again with next method on list */
79018de8d7fSPeter Avalos 		debug("Trying to start again");
79118de8d7fSPeter Avalos 		userauth(authctxt, NULL);
792*e9778795SPeter Avalos 		return 0;
79318de8d7fSPeter Avalos 	}
794*e9778795SPeter Avalos 	return 0;
79518de8d7fSPeter Avalos }
79618de8d7fSPeter Avalos 
797cb5eb4f1SPeter Avalos /* ARGSUSED */
798*e9778795SPeter Avalos int
79918de8d7fSPeter Avalos input_gssapi_token(int type, u_int32_t plen, void *ctxt)
80018de8d7fSPeter Avalos {
80118de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
80218de8d7fSPeter Avalos 	gss_buffer_desc recv_tok;
80318de8d7fSPeter Avalos 	OM_uint32 status;
80418de8d7fSPeter Avalos 	u_int slen;
80518de8d7fSPeter Avalos 
80618de8d7fSPeter Avalos 	if (authctxt == NULL)
80718de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
80818de8d7fSPeter Avalos 
80918de8d7fSPeter Avalos 	recv_tok.value = packet_get_string(&slen);
81018de8d7fSPeter Avalos 	recv_tok.length = slen;	/* safe typecast */
81118de8d7fSPeter Avalos 
81218de8d7fSPeter Avalos 	packet_check_eom();
81318de8d7fSPeter Avalos 
81418de8d7fSPeter Avalos 	status = process_gssapi_token(ctxt, &recv_tok);
81518de8d7fSPeter Avalos 
81636e94dc5SPeter Avalos 	free(recv_tok.value);
81718de8d7fSPeter Avalos 
81818de8d7fSPeter Avalos 	if (GSS_ERROR(status)) {
81918de8d7fSPeter Avalos 		/* Start again with the next method in the list */
82018de8d7fSPeter Avalos 		userauth(authctxt, NULL);
821*e9778795SPeter Avalos 		return 0;
82218de8d7fSPeter Avalos 	}
823*e9778795SPeter Avalos 	return 0;
82418de8d7fSPeter Avalos }
82518de8d7fSPeter Avalos 
826cb5eb4f1SPeter Avalos /* ARGSUSED */
827*e9778795SPeter Avalos int
82818de8d7fSPeter Avalos input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
82918de8d7fSPeter Avalos {
83018de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
83118de8d7fSPeter Avalos 	Gssctxt *gssctxt;
83218de8d7fSPeter Avalos 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
83318de8d7fSPeter Avalos 	gss_buffer_desc recv_tok;
83436e94dc5SPeter Avalos 	OM_uint32 ms;
83518de8d7fSPeter Avalos 	u_int len;
83618de8d7fSPeter Avalos 
83718de8d7fSPeter Avalos 	if (authctxt == NULL)
83818de8d7fSPeter Avalos 		fatal("input_gssapi_response: no authentication context");
83918de8d7fSPeter Avalos 	gssctxt = authctxt->methoddata;
84018de8d7fSPeter Avalos 
84118de8d7fSPeter Avalos 	recv_tok.value = packet_get_string(&len);
84218de8d7fSPeter Avalos 	recv_tok.length = len;
84318de8d7fSPeter Avalos 
84418de8d7fSPeter Avalos 	packet_check_eom();
84518de8d7fSPeter Avalos 
84618de8d7fSPeter Avalos 	/* Stick it into GSSAPI and see what it says */
84736e94dc5SPeter Avalos 	(void)ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
84818de8d7fSPeter Avalos 	    &recv_tok, &send_tok, NULL);
84918de8d7fSPeter Avalos 
85036e94dc5SPeter Avalos 	free(recv_tok.value);
85118de8d7fSPeter Avalos 	gss_release_buffer(&ms, &send_tok);
85218de8d7fSPeter Avalos 
85318de8d7fSPeter Avalos 	/* Server will be returning a failed packet after this one */
854*e9778795SPeter Avalos 	return 0;
85518de8d7fSPeter Avalos }
85618de8d7fSPeter Avalos 
857cb5eb4f1SPeter Avalos /* ARGSUSED */
858*e9778795SPeter Avalos int
85918de8d7fSPeter Avalos input_gssapi_error(int type, u_int32_t plen, void *ctxt)
86018de8d7fSPeter Avalos {
86118de8d7fSPeter Avalos 	char *msg;
86218de8d7fSPeter Avalos 	char *lang;
86318de8d7fSPeter Avalos 
86436e94dc5SPeter Avalos 	/* maj */(void)packet_get_int();
86536e94dc5SPeter Avalos 	/* min */(void)packet_get_int();
86618de8d7fSPeter Avalos 	msg=packet_get_string(NULL);
86718de8d7fSPeter Avalos 	lang=packet_get_string(NULL);
86818de8d7fSPeter Avalos 
86918de8d7fSPeter Avalos 	packet_check_eom();
87018de8d7fSPeter Avalos 
87118de8d7fSPeter Avalos 	debug("Server GSSAPI Error:\n%s", msg);
87236e94dc5SPeter Avalos 	free(msg);
87336e94dc5SPeter Avalos 	free(lang);
874*e9778795SPeter Avalos 	return 0;
87518de8d7fSPeter Avalos }
87618de8d7fSPeter Avalos #endif /* GSSAPI */
87718de8d7fSPeter Avalos 
87818de8d7fSPeter Avalos int
87918de8d7fSPeter Avalos userauth_none(Authctxt *authctxt)
88018de8d7fSPeter Avalos {
88118de8d7fSPeter Avalos 	/* initial userauth request */
88218de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
88318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
88418de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
88518de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
88618de8d7fSPeter Avalos 	packet_send();
88718de8d7fSPeter Avalos 	return 1;
88818de8d7fSPeter Avalos }
88918de8d7fSPeter Avalos 
89018de8d7fSPeter Avalos int
89118de8d7fSPeter Avalos userauth_passwd(Authctxt *authctxt)
89218de8d7fSPeter Avalos {
89318de8d7fSPeter Avalos 	static int attempt = 0;
89418de8d7fSPeter Avalos 	char prompt[150];
89518de8d7fSPeter Avalos 	char *password;
896856ea928SPeter Avalos 	const char *host = options.host_key_alias ?  options.host_key_alias :
897856ea928SPeter Avalos 	    authctxt->host;
89818de8d7fSPeter Avalos 
89918de8d7fSPeter Avalos 	if (attempt++ >= options.number_of_password_prompts)
90018de8d7fSPeter Avalos 		return 0;
90118de8d7fSPeter Avalos 
90218de8d7fSPeter Avalos 	if (attempt != 1)
90318de8d7fSPeter Avalos 		error("Permission denied, please try again.");
90418de8d7fSPeter Avalos 
90518de8d7fSPeter Avalos 	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
906856ea928SPeter Avalos 	    authctxt->server_user, host);
90718de8d7fSPeter Avalos 	password = read_passphrase(prompt, 0);
90818de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
90918de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
91018de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
91118de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
91218de8d7fSPeter Avalos 	packet_put_char(0);
91318de8d7fSPeter Avalos 	packet_put_cstring(password);
91436e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
91536e94dc5SPeter Avalos 	free(password);
91618de8d7fSPeter Avalos 	packet_add_padding(64);
91718de8d7fSPeter Avalos 	packet_send();
91818de8d7fSPeter Avalos 
91918de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
92018de8d7fSPeter Avalos 	    &input_userauth_passwd_changereq);
92118de8d7fSPeter Avalos 
92218de8d7fSPeter Avalos 	return 1;
92318de8d7fSPeter Avalos }
924cb5eb4f1SPeter Avalos 
92518de8d7fSPeter Avalos /*
92618de8d7fSPeter Avalos  * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
92718de8d7fSPeter Avalos  */
928cb5eb4f1SPeter Avalos /* ARGSUSED */
929*e9778795SPeter Avalos int
93018de8d7fSPeter Avalos input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
93118de8d7fSPeter Avalos {
93218de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
93318de8d7fSPeter Avalos 	char *info, *lang, *password = NULL, *retype = NULL;
93418de8d7fSPeter Avalos 	char prompt[150];
935856ea928SPeter Avalos 	const char *host = options.host_key_alias ? options.host_key_alias :
936856ea928SPeter Avalos 	    authctxt->host;
93718de8d7fSPeter Avalos 
93818de8d7fSPeter Avalos 	debug2("input_userauth_passwd_changereq");
93918de8d7fSPeter Avalos 
94018de8d7fSPeter Avalos 	if (authctxt == NULL)
94118de8d7fSPeter Avalos 		fatal("input_userauth_passwd_changereq: "
94218de8d7fSPeter Avalos 		    "no authentication context");
94318de8d7fSPeter Avalos 
94418de8d7fSPeter Avalos 	info = packet_get_string(NULL);
94518de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
94618de8d7fSPeter Avalos 	if (strlen(info) > 0)
94718de8d7fSPeter Avalos 		logit("%s", info);
94836e94dc5SPeter Avalos 	free(info);
94936e94dc5SPeter Avalos 	free(lang);
95018de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
95118de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
95218de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
95318de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
95418de8d7fSPeter Avalos 	packet_put_char(1);			/* additional info */
95518de8d7fSPeter Avalos 	snprintf(prompt, sizeof(prompt),
95618de8d7fSPeter Avalos 	    "Enter %.30s@%.128s's old password: ",
957856ea928SPeter Avalos 	    authctxt->server_user, host);
95818de8d7fSPeter Avalos 	password = read_passphrase(prompt, 0);
95918de8d7fSPeter Avalos 	packet_put_cstring(password);
96036e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
96136e94dc5SPeter Avalos 	free(password);
96218de8d7fSPeter Avalos 	password = NULL;
96318de8d7fSPeter Avalos 	while (password == NULL) {
96418de8d7fSPeter Avalos 		snprintf(prompt, sizeof(prompt),
96518de8d7fSPeter Avalos 		    "Enter %.30s@%.128s's new password: ",
966856ea928SPeter Avalos 		    authctxt->server_user, host);
96718de8d7fSPeter Avalos 		password = read_passphrase(prompt, RP_ALLOW_EOF);
96818de8d7fSPeter Avalos 		if (password == NULL) {
96918de8d7fSPeter Avalos 			/* bail out */
970*e9778795SPeter Avalos 			return 0;
97118de8d7fSPeter Avalos 		}
97218de8d7fSPeter Avalos 		snprintf(prompt, sizeof(prompt),
97318de8d7fSPeter Avalos 		    "Retype %.30s@%.128s's new password: ",
974856ea928SPeter Avalos 		    authctxt->server_user, host);
97518de8d7fSPeter Avalos 		retype = read_passphrase(prompt, 0);
97618de8d7fSPeter Avalos 		if (strcmp(password, retype) != 0) {
97736e94dc5SPeter Avalos 			explicit_bzero(password, strlen(password));
97836e94dc5SPeter Avalos 			free(password);
97918de8d7fSPeter Avalos 			logit("Mismatch; try again, EOF to quit.");
98018de8d7fSPeter Avalos 			password = NULL;
98118de8d7fSPeter Avalos 		}
98236e94dc5SPeter Avalos 		explicit_bzero(retype, strlen(retype));
98336e94dc5SPeter Avalos 		free(retype);
98418de8d7fSPeter Avalos 	}
98518de8d7fSPeter Avalos 	packet_put_cstring(password);
98636e94dc5SPeter Avalos 	explicit_bzero(password, strlen(password));
98736e94dc5SPeter Avalos 	free(password);
98818de8d7fSPeter Avalos 	packet_add_padding(64);
98918de8d7fSPeter Avalos 	packet_send();
99018de8d7fSPeter Avalos 
99118de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
99218de8d7fSPeter Avalos 	    &input_userauth_passwd_changereq);
993*e9778795SPeter Avalos 	return 0;
994*e9778795SPeter Avalos }
995*e9778795SPeter Avalos 
996*e9778795SPeter Avalos static const char *
997*e9778795SPeter Avalos identity_sign_encode(struct identity *id)
998*e9778795SPeter Avalos {
999*e9778795SPeter Avalos 	struct ssh *ssh = active_state;
1000*e9778795SPeter Avalos 
1001*e9778795SPeter Avalos 	if (id->key->type == KEY_RSA) {
1002*e9778795SPeter Avalos 		switch (ssh->kex->rsa_sha2) {
1003*e9778795SPeter Avalos 		case 256:
1004*e9778795SPeter Avalos 			return "rsa-sha2-256";
1005*e9778795SPeter Avalos 		case 512:
1006*e9778795SPeter Avalos 			return "rsa-sha2-512";
1007*e9778795SPeter Avalos 		}
1008*e9778795SPeter Avalos 	}
1009*e9778795SPeter Avalos 	return key_ssh_name(id->key);
101018de8d7fSPeter Avalos }
101118de8d7fSPeter Avalos 
101218de8d7fSPeter Avalos static int
1013*e9778795SPeter Avalos identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1014*e9778795SPeter Avalos     const u_char *data, size_t datalen, u_int compat)
101518de8d7fSPeter Avalos {
101618de8d7fSPeter Avalos 	Key *prv;
101718de8d7fSPeter Avalos 	int ret;
1018*e9778795SPeter Avalos 	const char *alg;
1019*e9778795SPeter Avalos 
1020*e9778795SPeter Avalos 	alg = identity_sign_encode(id);
102118de8d7fSPeter Avalos 
102218de8d7fSPeter Avalos 	/* the agent supports this key */
1023*e9778795SPeter Avalos 	if (id->agent_fd != -1)
1024*e9778795SPeter Avalos 		return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
1025*e9778795SPeter Avalos 		    data, datalen, alg, compat);
1026*e9778795SPeter Avalos 
102718de8d7fSPeter Avalos 	/*
102818de8d7fSPeter Avalos 	 * we have already loaded the private key or
102918de8d7fSPeter Avalos 	 * the private key is stored in external hardware
103018de8d7fSPeter Avalos 	 */
103136e94dc5SPeter Avalos 	if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))
1032*e9778795SPeter Avalos 		return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg,
1033*e9778795SPeter Avalos 		    compat));
103418de8d7fSPeter Avalos 	/* load the private key from the file */
1035*e9778795SPeter Avalos 	if ((prv = load_identity_file(id)) == NULL)
1036*e9778795SPeter Avalos 		return SSH_ERR_KEY_NOT_FOUND;
1037*e9778795SPeter Avalos 	ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat);
1038*e9778795SPeter Avalos 	sshkey_free(prv);
103918de8d7fSPeter Avalos 	return (ret);
104018de8d7fSPeter Avalos }
104118de8d7fSPeter Avalos 
104218de8d7fSPeter Avalos static int
104318de8d7fSPeter Avalos sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
104418de8d7fSPeter Avalos {
104518de8d7fSPeter Avalos 	Buffer b;
1046*e9778795SPeter Avalos 	Identity *private_id;
104718de8d7fSPeter Avalos 	u_char *blob, *signature;
1048*e9778795SPeter Avalos 	size_t slen;
1049*e9778795SPeter Avalos 	u_int bloblen, skip = 0;
1050*e9778795SPeter Avalos 	int matched, ret = -1, have_sig = 1;
1051856ea928SPeter Avalos 	char *fp;
105218de8d7fSPeter Avalos 
1053*e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
1054*e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL)
1055*e9778795SPeter Avalos 		return 0;
1056*e9778795SPeter Avalos 	debug3("%s: %s %s", __func__, key_type(id->key), fp);
105736e94dc5SPeter Avalos 	free(fp);
105818de8d7fSPeter Avalos 
105918de8d7fSPeter Avalos 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
106018de8d7fSPeter Avalos 		/* we cannot handle this key */
106118de8d7fSPeter Avalos 		debug3("sign_and_send_pubkey: cannot handle key");
106218de8d7fSPeter Avalos 		return 0;
106318de8d7fSPeter Avalos 	}
106418de8d7fSPeter Avalos 	/* data to be signed */
106518de8d7fSPeter Avalos 	buffer_init(&b);
106618de8d7fSPeter Avalos 	if (datafellows & SSH_OLD_SESSIONID) {
106718de8d7fSPeter Avalos 		buffer_append(&b, session_id2, session_id2_len);
106818de8d7fSPeter Avalos 		skip = session_id2_len;
106918de8d7fSPeter Avalos 	} else {
107018de8d7fSPeter Avalos 		buffer_put_string(&b, session_id2, session_id2_len);
107118de8d7fSPeter Avalos 		skip = buffer_len(&b);
107218de8d7fSPeter Avalos 	}
107318de8d7fSPeter Avalos 	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
107418de8d7fSPeter Avalos 	buffer_put_cstring(&b, authctxt->server_user);
107518de8d7fSPeter Avalos 	buffer_put_cstring(&b,
107618de8d7fSPeter Avalos 	    datafellows & SSH_BUG_PKSERVICE ?
107718de8d7fSPeter Avalos 	    "ssh-userauth" :
107818de8d7fSPeter Avalos 	    authctxt->service);
107918de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKAUTH) {
108018de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
108118de8d7fSPeter Avalos 	} else {
108218de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->method->name);
108318de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
1084*e9778795SPeter Avalos 		buffer_put_cstring(&b, identity_sign_encode(id));
108518de8d7fSPeter Avalos 	}
108618de8d7fSPeter Avalos 	buffer_put_string(&b, blob, bloblen);
108718de8d7fSPeter Avalos 
1088*e9778795SPeter Avalos 	/*
1089*e9778795SPeter Avalos 	 * If the key is an certificate, try to find a matching private key
1090*e9778795SPeter Avalos 	 * and use it to complete the signature.
1091*e9778795SPeter Avalos 	 * If no such private key exists, fall back to trying the certificate
1092*e9778795SPeter Avalos 	 * key itself in case it has a private half already loaded.
1093*e9778795SPeter Avalos 	 */
1094*e9778795SPeter Avalos 	if (key_is_cert(id->key)) {
1095*e9778795SPeter Avalos 		matched = 0;
1096*e9778795SPeter Avalos 		TAILQ_FOREACH(private_id, &authctxt->keys, next) {
1097*e9778795SPeter Avalos 			if (sshkey_equal_public(id->key, private_id->key) &&
1098*e9778795SPeter Avalos 			    id->key->type != private_id->key->type) {
1099*e9778795SPeter Avalos 				id = private_id;
1100*e9778795SPeter Avalos 				matched = 1;
1101*e9778795SPeter Avalos 				break;
1102*e9778795SPeter Avalos 			}
1103*e9778795SPeter Avalos 		}
1104*e9778795SPeter Avalos 		if (matched) {
1105*e9778795SPeter Avalos 			debug2("%s: using private key \"%s\"%s for "
1106*e9778795SPeter Avalos 			    "certificate", __func__, id->filename,
1107*e9778795SPeter Avalos 			    id->agent_fd != -1 ? " from agent" : "");
1108*e9778795SPeter Avalos 		} else {
1109*e9778795SPeter Avalos 			debug("%s: no separate private key for certificate "
1110*e9778795SPeter Avalos 			    "\"%s\"", __func__, id->filename);
1111*e9778795SPeter Avalos 		}
1112*e9778795SPeter Avalos 	}
1113*e9778795SPeter Avalos 
111418de8d7fSPeter Avalos 	/* generate signature */
111518de8d7fSPeter Avalos 	ret = identity_sign(id, &signature, &slen,
1116*e9778795SPeter Avalos 	    buffer_ptr(&b), buffer_len(&b), datafellows);
1117*e9778795SPeter Avalos 	if (ret != 0) {
1118*e9778795SPeter Avalos 		if (ret != SSH_ERR_KEY_NOT_FOUND)
1119*e9778795SPeter Avalos 			error("%s: signing failed: %s", __func__, ssh_err(ret));
112036e94dc5SPeter Avalos 		free(blob);
112118de8d7fSPeter Avalos 		buffer_free(&b);
112218de8d7fSPeter Avalos 		return 0;
112318de8d7fSPeter Avalos 	}
112418de8d7fSPeter Avalos #ifdef DEBUG_PK
112518de8d7fSPeter Avalos 	buffer_dump(&b);
112618de8d7fSPeter Avalos #endif
112718de8d7fSPeter Avalos 	if (datafellows & SSH_BUG_PKSERVICE) {
112818de8d7fSPeter Avalos 		buffer_clear(&b);
112918de8d7fSPeter Avalos 		buffer_append(&b, session_id2, session_id2_len);
113018de8d7fSPeter Avalos 		skip = session_id2_len;
113118de8d7fSPeter Avalos 		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
113218de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->server_user);
113318de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->service);
113418de8d7fSPeter Avalos 		buffer_put_cstring(&b, authctxt->method->name);
113518de8d7fSPeter Avalos 		buffer_put_char(&b, have_sig);
113618de8d7fSPeter Avalos 		if (!(datafellows & SSH_BUG_PKAUTH))
113718de8d7fSPeter Avalos 			buffer_put_cstring(&b, key_ssh_name(id->key));
113818de8d7fSPeter Avalos 		buffer_put_string(&b, blob, bloblen);
113918de8d7fSPeter Avalos 	}
114036e94dc5SPeter Avalos 	free(blob);
114118de8d7fSPeter Avalos 
114218de8d7fSPeter Avalos 	/* append signature */
114318de8d7fSPeter Avalos 	buffer_put_string(&b, signature, slen);
114436e94dc5SPeter Avalos 	free(signature);
114518de8d7fSPeter Avalos 
114618de8d7fSPeter Avalos 	/* skip session id and packet type */
114718de8d7fSPeter Avalos 	if (buffer_len(&b) < skip + 1)
114818de8d7fSPeter Avalos 		fatal("userauth_pubkey: internal error");
114918de8d7fSPeter Avalos 	buffer_consume(&b, skip + 1);
115018de8d7fSPeter Avalos 
115118de8d7fSPeter Avalos 	/* put remaining data from buffer into packet */
115218de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
115318de8d7fSPeter Avalos 	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
115418de8d7fSPeter Avalos 	buffer_free(&b);
115518de8d7fSPeter Avalos 	packet_send();
115618de8d7fSPeter Avalos 
115718de8d7fSPeter Avalos 	return 1;
115818de8d7fSPeter Avalos }
115918de8d7fSPeter Avalos 
116018de8d7fSPeter Avalos static int
116118de8d7fSPeter Avalos send_pubkey_test(Authctxt *authctxt, Identity *id)
116218de8d7fSPeter Avalos {
116318de8d7fSPeter Avalos 	u_char *blob;
116418de8d7fSPeter Avalos 	u_int bloblen, have_sig = 0;
116518de8d7fSPeter Avalos 
116618de8d7fSPeter Avalos 	debug3("send_pubkey_test");
116718de8d7fSPeter Avalos 
116818de8d7fSPeter Avalos 	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
116918de8d7fSPeter Avalos 		/* we cannot handle this key */
117018de8d7fSPeter Avalos 		debug3("send_pubkey_test: cannot handle key");
117118de8d7fSPeter Avalos 		return 0;
117218de8d7fSPeter Avalos 	}
117318de8d7fSPeter Avalos 	/* register callback for USERAUTH_PK_OK message */
117418de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
117518de8d7fSPeter Avalos 
117618de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
117718de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
117818de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
117918de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
118018de8d7fSPeter Avalos 	packet_put_char(have_sig);
118118de8d7fSPeter Avalos 	if (!(datafellows & SSH_BUG_PKAUTH))
1182*e9778795SPeter Avalos 		packet_put_cstring(identity_sign_encode(id));
118318de8d7fSPeter Avalos 	packet_put_string(blob, bloblen);
118436e94dc5SPeter Avalos 	free(blob);
118518de8d7fSPeter Avalos 	packet_send();
118618de8d7fSPeter Avalos 	return 1;
118718de8d7fSPeter Avalos }
118818de8d7fSPeter Avalos 
118918de8d7fSPeter Avalos static Key *
1190*e9778795SPeter Avalos load_identity_file(Identity *id)
119118de8d7fSPeter Avalos {
1192*e9778795SPeter Avalos 	Key *private = NULL;
1193*e9778795SPeter Avalos 	char prompt[300], *passphrase, *comment;
1194*e9778795SPeter Avalos 	int r, perm_ok = 0, quit = 0, i;
119518de8d7fSPeter Avalos 	struct stat st;
119618de8d7fSPeter Avalos 
1197*e9778795SPeter Avalos 	if (stat(id->filename, &st) < 0) {
1198*e9778795SPeter Avalos 		(id->userprovided ? logit : debug3)("no such identity: %s: %s",
1199*e9778795SPeter Avalos 		    id->filename, strerror(errno));
120018de8d7fSPeter Avalos 		return NULL;
120118de8d7fSPeter Avalos 	}
120218de8d7fSPeter Avalos 	snprintf(prompt, sizeof prompt,
1203*e9778795SPeter Avalos 	    "Enter passphrase for key '%.100s': ", id->filename);
1204*e9778795SPeter Avalos 	for (i = 0; i <= options.number_of_password_prompts; i++) {
1205*e9778795SPeter Avalos 		if (i == 0)
1206*e9778795SPeter Avalos 			passphrase = "";
1207*e9778795SPeter Avalos 		else {
120818de8d7fSPeter Avalos 			passphrase = read_passphrase(prompt, 0);
1209*e9778795SPeter Avalos 			if (*passphrase == '\0') {
121018de8d7fSPeter Avalos 				debug2("no passphrase given, try next key");
1211*e9778795SPeter Avalos 				free(passphrase);
1212*e9778795SPeter Avalos 				break;
121318de8d7fSPeter Avalos 			}
1214*e9778795SPeter Avalos 		}
1215*e9778795SPeter Avalos 		switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename,
1216*e9778795SPeter Avalos 		    passphrase, &private, &comment, &perm_ok))) {
1217*e9778795SPeter Avalos 		case 0:
1218*e9778795SPeter Avalos 			break;
1219*e9778795SPeter Avalos 		case SSH_ERR_KEY_WRONG_PASSPHRASE:
1220*e9778795SPeter Avalos 			if (options.batch_mode) {
1221*e9778795SPeter Avalos 				quit = 1;
1222*e9778795SPeter Avalos 				break;
1223*e9778795SPeter Avalos 			}
1224*e9778795SPeter Avalos 			if (i != 0)
1225*e9778795SPeter Avalos 				debug2("bad passphrase given, try again...");
1226*e9778795SPeter Avalos 			break;
1227*e9778795SPeter Avalos 		case SSH_ERR_SYSTEM_ERROR:
1228*e9778795SPeter Avalos 			if (errno == ENOENT) {
1229*e9778795SPeter Avalos 				debug2("Load key \"%s\": %s",
1230*e9778795SPeter Avalos 				    id->filename, ssh_err(r));
1231*e9778795SPeter Avalos 				quit = 1;
1232*e9778795SPeter Avalos 				break;
1233*e9778795SPeter Avalos 			}
1234*e9778795SPeter Avalos 			/* FALLTHROUGH */
1235*e9778795SPeter Avalos 		default:
1236*e9778795SPeter Avalos 			error("Load key \"%s\": %s", id->filename, ssh_err(r));
1237*e9778795SPeter Avalos 			quit = 1;
1238*e9778795SPeter Avalos 			break;
1239*e9778795SPeter Avalos 		}
1240*e9778795SPeter Avalos 		if (!quit && private != NULL && id->agent_fd == -1 &&
1241*e9778795SPeter Avalos 		    !(id->key && id->isprivate))
1242*e9778795SPeter Avalos 			maybe_add_key_to_agent(id->filename, private, comment,
1243*e9778795SPeter Avalos 			    passphrase);
1244*e9778795SPeter Avalos 		if (i > 0) {
124536e94dc5SPeter Avalos 			explicit_bzero(passphrase, strlen(passphrase));
124636e94dc5SPeter Avalos 			free(passphrase);
1247*e9778795SPeter Avalos 		}
1248*e9778795SPeter Avalos 		free(comment);
124918de8d7fSPeter Avalos 		if (private != NULL || quit)
125018de8d7fSPeter Avalos 			break;
125118de8d7fSPeter Avalos 	}
125218de8d7fSPeter Avalos 	return private;
125318de8d7fSPeter Avalos }
125418de8d7fSPeter Avalos 
125518de8d7fSPeter Avalos /*
125618de8d7fSPeter Avalos  * try keys in the following order:
1257*e9778795SPeter Avalos  * 	1. certificates listed in the config file
1258*e9778795SPeter Avalos  * 	2. other input certificates
1259*e9778795SPeter Avalos  *	3. agent keys that are found in the config file
1260*e9778795SPeter Avalos  *	4. other agent keys
1261*e9778795SPeter Avalos  *	5. keys that are only listed in the config file
126218de8d7fSPeter Avalos  */
126318de8d7fSPeter Avalos static void
126418de8d7fSPeter Avalos pubkey_prepare(Authctxt *authctxt)
126518de8d7fSPeter Avalos {
1266*e9778795SPeter Avalos 	struct identity *id, *id2, *tmp;
1267*e9778795SPeter Avalos 	struct idlist agent, files, *preferred;
1268*e9778795SPeter Avalos 	struct sshkey *key;
1269*e9778795SPeter Avalos 	int agent_fd = -1, i, r, found;
1270*e9778795SPeter Avalos 	size_t j;
1271*e9778795SPeter Avalos 	struct ssh_identitylist *idlist;
127218de8d7fSPeter Avalos 
127318de8d7fSPeter Avalos 	TAILQ_INIT(&agent);	/* keys from the agent */
127418de8d7fSPeter Avalos 	TAILQ_INIT(&files);	/* keys from the config file */
127518de8d7fSPeter Avalos 	preferred = &authctxt->keys;
127618de8d7fSPeter Avalos 	TAILQ_INIT(preferred);	/* preferred order of keys */
127718de8d7fSPeter Avalos 
127836e94dc5SPeter Avalos 	/* list of keys stored in the filesystem and PKCS#11 */
127918de8d7fSPeter Avalos 	for (i = 0; i < options.num_identity_files; i++) {
128018de8d7fSPeter Avalos 		key = options.identity_keys[i];
128118de8d7fSPeter Avalos 		if (key && key->type == KEY_RSA1)
128218de8d7fSPeter Avalos 			continue;
1283856ea928SPeter Avalos 		if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER)
1284856ea928SPeter Avalos 			continue;
128518de8d7fSPeter Avalos 		options.identity_keys[i] = NULL;
128618de8d7fSPeter Avalos 		id = xcalloc(1, sizeof(*id));
1287*e9778795SPeter Avalos 		id->agent_fd = -1;
128818de8d7fSPeter Avalos 		id->key = key;
128918de8d7fSPeter Avalos 		id->filename = xstrdup(options.identity_files[i]);
129036e94dc5SPeter Avalos 		id->userprovided = options.identity_file_userprovided[i];
129118de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(&files, id, next);
129218de8d7fSPeter Avalos 	}
1293*e9778795SPeter Avalos 	/* list of certificates specified by user */
1294*e9778795SPeter Avalos 	for (i = 0; i < options.num_certificate_files; i++) {
1295*e9778795SPeter Avalos 		key = options.certificates[i];
1296*e9778795SPeter Avalos 		if (!key_is_cert(key) || key->cert == NULL ||
1297*e9778795SPeter Avalos 		    key->cert->type != SSH2_CERT_TYPE_USER)
1298*e9778795SPeter Avalos 			continue;
1299*e9778795SPeter Avalos 		id = xcalloc(1, sizeof(*id));
1300*e9778795SPeter Avalos 		id->agent_fd = -1;
1301*e9778795SPeter Avalos 		id->key = key;
1302*e9778795SPeter Avalos 		id->filename = xstrdup(options.certificate_files[i]);
1303*e9778795SPeter Avalos 		id->userprovided = options.certificate_file_userprovided[i];
1304*e9778795SPeter Avalos 		TAILQ_INSERT_TAIL(preferred, id, next);
1305*e9778795SPeter Avalos 	}
1306*e9778795SPeter Avalos 	/* list of keys supported by the agent */
1307*e9778795SPeter Avalos 	if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
1308*e9778795SPeter Avalos 		if (r != SSH_ERR_AGENT_NOT_PRESENT)
1309*e9778795SPeter Avalos 			debug("%s: ssh_get_authentication_socket: %s",
1310*e9778795SPeter Avalos 			    __func__, ssh_err(r));
1311*e9778795SPeter Avalos 	} else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) {
1312*e9778795SPeter Avalos 		if (r != SSH_ERR_AGENT_NO_IDENTITIES)
1313*e9778795SPeter Avalos 			debug("%s: ssh_fetch_identitylist: %s",
1314*e9778795SPeter Avalos 			    __func__, ssh_err(r));
1315*e9778795SPeter Avalos 		close(agent_fd);
1316*e9778795SPeter Avalos 	} else {
1317*e9778795SPeter Avalos 		for (j = 0; j < idlist->nkeys; j++) {
1318*e9778795SPeter Avalos 			found = 0;
1319*e9778795SPeter Avalos 			TAILQ_FOREACH(id, &files, next) {
1320*e9778795SPeter Avalos 				/*
1321*e9778795SPeter Avalos 				 * agent keys from the config file are
1322*e9778795SPeter Avalos 				 * preferred
1323*e9778795SPeter Avalos 				 */
1324*e9778795SPeter Avalos 				if (sshkey_equal(idlist->keys[j], id->key)) {
1325*e9778795SPeter Avalos 					TAILQ_REMOVE(&files, id, next);
1326*e9778795SPeter Avalos 					TAILQ_INSERT_TAIL(preferred, id, next);
1327*e9778795SPeter Avalos 					id->agent_fd = agent_fd;
1328*e9778795SPeter Avalos 					found = 1;
1329*e9778795SPeter Avalos 					break;
1330*e9778795SPeter Avalos 				}
1331*e9778795SPeter Avalos 			}
1332*e9778795SPeter Avalos 			if (!found && !options.identities_only) {
1333*e9778795SPeter Avalos 				id = xcalloc(1, sizeof(*id));
1334*e9778795SPeter Avalos 				/* XXX "steals" key/comment from idlist */
1335*e9778795SPeter Avalos 				id->key = idlist->keys[j];
1336*e9778795SPeter Avalos 				id->filename = idlist->comments[j];
1337*e9778795SPeter Avalos 				idlist->keys[j] = NULL;
1338*e9778795SPeter Avalos 				idlist->comments[j] = NULL;
1339*e9778795SPeter Avalos 				id->agent_fd = agent_fd;
1340*e9778795SPeter Avalos 				TAILQ_INSERT_TAIL(&agent, id, next);
1341*e9778795SPeter Avalos 			}
1342*e9778795SPeter Avalos 		}
1343*e9778795SPeter Avalos 		ssh_free_identitylist(idlist);
1344*e9778795SPeter Avalos 		/* append remaining agent keys */
1345*e9778795SPeter Avalos 		for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
1346*e9778795SPeter Avalos 			TAILQ_REMOVE(&agent, id, next);
1347*e9778795SPeter Avalos 			TAILQ_INSERT_TAIL(preferred, id, next);
1348*e9778795SPeter Avalos 		}
1349*e9778795SPeter Avalos 		authctxt->agent_fd = agent_fd;
1350*e9778795SPeter Avalos 	}
135136e94dc5SPeter Avalos 	/* Prefer PKCS11 keys that are explicitly listed */
135236e94dc5SPeter Avalos 	TAILQ_FOREACH_SAFE(id, &files, next, tmp) {
135336e94dc5SPeter Avalos 		if (id->key == NULL || (id->key->flags & SSHKEY_FLAG_EXT) == 0)
135436e94dc5SPeter Avalos 			continue;
135536e94dc5SPeter Avalos 		found = 0;
135636e94dc5SPeter Avalos 		TAILQ_FOREACH(id2, &files, next) {
135736e94dc5SPeter Avalos 			if (id2->key == NULL ||
135836e94dc5SPeter Avalos 			    (id2->key->flags & SSHKEY_FLAG_EXT) == 0)
135936e94dc5SPeter Avalos 				continue;
1360*e9778795SPeter Avalos 			if (sshkey_equal(id->key, id2->key)) {
136136e94dc5SPeter Avalos 				TAILQ_REMOVE(&files, id, next);
136236e94dc5SPeter Avalos 				TAILQ_INSERT_TAIL(preferred, id, next);
136336e94dc5SPeter Avalos 				found = 1;
136436e94dc5SPeter Avalos 				break;
136536e94dc5SPeter Avalos 			}
136636e94dc5SPeter Avalos 		}
136736e94dc5SPeter Avalos 		/* If IdentitiesOnly set and key not found then don't use it */
136836e94dc5SPeter Avalos 		if (!found && options.identities_only) {
136936e94dc5SPeter Avalos 			TAILQ_REMOVE(&files, id, next);
137036e94dc5SPeter Avalos 			explicit_bzero(id, sizeof(*id));
137136e94dc5SPeter Avalos 			free(id);
137236e94dc5SPeter Avalos 		}
137336e94dc5SPeter Avalos 	}
137418de8d7fSPeter Avalos 	/* append remaining keys from the config file */
137518de8d7fSPeter Avalos 	for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
137618de8d7fSPeter Avalos 		TAILQ_REMOVE(&files, id, next);
137718de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(preferred, id, next);
137818de8d7fSPeter Avalos 	}
1379*e9778795SPeter Avalos 	/* finally, filter by PubkeyAcceptedKeyTypes */
1380*e9778795SPeter Avalos 	TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
1381*e9778795SPeter Avalos 		if (id->key != NULL &&
1382*e9778795SPeter Avalos 		    match_pattern_list(sshkey_ssh_name(id->key),
1383*e9778795SPeter Avalos 		    options.pubkey_key_types, 0) != 1) {
1384*e9778795SPeter Avalos 			debug("Skipping %s key %s - "
1385*e9778795SPeter Avalos 			    "not in PubkeyAcceptedKeyTypes",
1386*e9778795SPeter Avalos 			    sshkey_ssh_name(id->key), id->filename);
1387*e9778795SPeter Avalos 			TAILQ_REMOVE(preferred, id, next);
1388*e9778795SPeter Avalos 			sshkey_free(id->key);
1389*e9778795SPeter Avalos 			free(id->filename);
1390*e9778795SPeter Avalos 			memset(id, 0, sizeof(*id));
1391*e9778795SPeter Avalos 			continue;
1392*e9778795SPeter Avalos 		}
1393*e9778795SPeter Avalos 		debug2("key: %s (%p)%s%s", id->filename, id->key,
1394*e9778795SPeter Avalos 		    id->userprovided ? ", explicit" : "",
1395*e9778795SPeter Avalos 		    id->agent_fd != -1 ? ", agent" : "");
139618de8d7fSPeter Avalos 	}
139718de8d7fSPeter Avalos }
139818de8d7fSPeter Avalos 
139918de8d7fSPeter Avalos static void
140018de8d7fSPeter Avalos pubkey_cleanup(Authctxt *authctxt)
140118de8d7fSPeter Avalos {
140218de8d7fSPeter Avalos 	Identity *id;
140318de8d7fSPeter Avalos 
1404*e9778795SPeter Avalos 	if (authctxt->agent_fd != -1)
1405*e9778795SPeter Avalos 		ssh_close_authentication_socket(authctxt->agent_fd);
140618de8d7fSPeter Avalos 	for (id = TAILQ_FIRST(&authctxt->keys); id;
140718de8d7fSPeter Avalos 	    id = TAILQ_FIRST(&authctxt->keys)) {
140818de8d7fSPeter Avalos 		TAILQ_REMOVE(&authctxt->keys, id, next);
1409*e9778795SPeter Avalos 		sshkey_free(id->key);
141036e94dc5SPeter Avalos 		free(id->filename);
141136e94dc5SPeter Avalos 		free(id);
141218de8d7fSPeter Avalos 	}
141318de8d7fSPeter Avalos }
141418de8d7fSPeter Avalos 
1415*e9778795SPeter Avalos static int
1416*e9778795SPeter Avalos try_identity(Identity *id)
1417*e9778795SPeter Avalos {
1418*e9778795SPeter Avalos 	if (!id->key)
1419*e9778795SPeter Avalos 		return (0);
1420*e9778795SPeter Avalos 	if (key_type_plain(id->key->type) == KEY_RSA &&
1421*e9778795SPeter Avalos 	    (datafellows & SSH_BUG_RSASIGMD5) != 0) {
1422*e9778795SPeter Avalos 		debug("Skipped %s key %s for RSA/MD5 server",
1423*e9778795SPeter Avalos 		    key_type(id->key), id->filename);
1424*e9778795SPeter Avalos 		return (0);
1425*e9778795SPeter Avalos 	}
1426*e9778795SPeter Avalos 	return (id->key->type != KEY_RSA1);
1427*e9778795SPeter Avalos }
1428*e9778795SPeter Avalos 
142918de8d7fSPeter Avalos int
143018de8d7fSPeter Avalos userauth_pubkey(Authctxt *authctxt)
143118de8d7fSPeter Avalos {
143218de8d7fSPeter Avalos 	Identity *id;
143318de8d7fSPeter Avalos 	int sent = 0;
143418de8d7fSPeter Avalos 
143518de8d7fSPeter Avalos 	while ((id = TAILQ_FIRST(&authctxt->keys))) {
143618de8d7fSPeter Avalos 		if (id->tried++)
143718de8d7fSPeter Avalos 			return (0);
143818de8d7fSPeter Avalos 		/* move key to the end of the queue */
143918de8d7fSPeter Avalos 		TAILQ_REMOVE(&authctxt->keys, id, next);
144018de8d7fSPeter Avalos 		TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
144118de8d7fSPeter Avalos 		/*
144218de8d7fSPeter Avalos 		 * send a test message if we have the public key. for
144318de8d7fSPeter Avalos 		 * encrypted keys we cannot do this and have to load the
144418de8d7fSPeter Avalos 		 * private key instead
144518de8d7fSPeter Avalos 		 */
144636e94dc5SPeter Avalos 		if (id->key != NULL) {
1447*e9778795SPeter Avalos 			if (try_identity(id)) {
144836e94dc5SPeter Avalos 				debug("Offering %s public key: %s",
144936e94dc5SPeter Avalos 				    key_type(id->key), id->filename);
145018de8d7fSPeter Avalos 				sent = send_pubkey_test(authctxt, id);
145136e94dc5SPeter Avalos 			}
145236e94dc5SPeter Avalos 		} else {
145318de8d7fSPeter Avalos 			debug("Trying private key: %s", id->filename);
1454*e9778795SPeter Avalos 			id->key = load_identity_file(id);
145518de8d7fSPeter Avalos 			if (id->key != NULL) {
1456*e9778795SPeter Avalos 				if (try_identity(id)) {
145718de8d7fSPeter Avalos 					id->isprivate = 1;
145836e94dc5SPeter Avalos 					sent = sign_and_send_pubkey(
145936e94dc5SPeter Avalos 					    authctxt, id);
146036e94dc5SPeter Avalos 				}
146118de8d7fSPeter Avalos 				key_free(id->key);
146218de8d7fSPeter Avalos 				id->key = NULL;
146318de8d7fSPeter Avalos 			}
146418de8d7fSPeter Avalos 		}
146518de8d7fSPeter Avalos 		if (sent)
146618de8d7fSPeter Avalos 			return (sent);
146718de8d7fSPeter Avalos 	}
146818de8d7fSPeter Avalos 	return (0);
146918de8d7fSPeter Avalos }
147018de8d7fSPeter Avalos 
147118de8d7fSPeter Avalos /*
147218de8d7fSPeter Avalos  * Send userauth request message specifying keyboard-interactive method.
147318de8d7fSPeter Avalos  */
147418de8d7fSPeter Avalos int
147518de8d7fSPeter Avalos userauth_kbdint(Authctxt *authctxt)
147618de8d7fSPeter Avalos {
147718de8d7fSPeter Avalos 	static int attempt = 0;
147818de8d7fSPeter Avalos 
147918de8d7fSPeter Avalos 	if (attempt++ >= options.number_of_password_prompts)
148018de8d7fSPeter Avalos 		return 0;
148118de8d7fSPeter Avalos 	/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
148218de8d7fSPeter Avalos 	if (attempt > 1 && !authctxt->info_req_seen) {
148318de8d7fSPeter Avalos 		debug3("userauth_kbdint: disable: no info_req_seen");
148418de8d7fSPeter Avalos 		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
148518de8d7fSPeter Avalos 		return 0;
148618de8d7fSPeter Avalos 	}
148718de8d7fSPeter Avalos 
148818de8d7fSPeter Avalos 	debug2("userauth_kbdint");
148918de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
149018de8d7fSPeter Avalos 	packet_put_cstring(authctxt->server_user);
149118de8d7fSPeter Avalos 	packet_put_cstring(authctxt->service);
149218de8d7fSPeter Avalos 	packet_put_cstring(authctxt->method->name);
149318de8d7fSPeter Avalos 	packet_put_cstring("");					/* lang */
149418de8d7fSPeter Avalos 	packet_put_cstring(options.kbd_interactive_devices ?
149518de8d7fSPeter Avalos 	    options.kbd_interactive_devices : "");
149618de8d7fSPeter Avalos 	packet_send();
149718de8d7fSPeter Avalos 
149818de8d7fSPeter Avalos 	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
149918de8d7fSPeter Avalos 	return 1;
150018de8d7fSPeter Avalos }
150118de8d7fSPeter Avalos 
150218de8d7fSPeter Avalos /*
150318de8d7fSPeter Avalos  * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
150418de8d7fSPeter Avalos  */
1505*e9778795SPeter Avalos int
150618de8d7fSPeter Avalos input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
150718de8d7fSPeter Avalos {
150818de8d7fSPeter Avalos 	Authctxt *authctxt = ctxt;
150918de8d7fSPeter Avalos 	char *name, *inst, *lang, *prompt, *response;
151018de8d7fSPeter Avalos 	u_int num_prompts, i;
151118de8d7fSPeter Avalos 	int echo = 0;
151218de8d7fSPeter Avalos 
151318de8d7fSPeter Avalos 	debug2("input_userauth_info_req");
151418de8d7fSPeter Avalos 
151518de8d7fSPeter Avalos 	if (authctxt == NULL)
151618de8d7fSPeter Avalos 		fatal("input_userauth_info_req: no authentication context");
151718de8d7fSPeter Avalos 
151818de8d7fSPeter Avalos 	authctxt->info_req_seen = 1;
151918de8d7fSPeter Avalos 
152018de8d7fSPeter Avalos 	name = packet_get_string(NULL);
152118de8d7fSPeter Avalos 	inst = packet_get_string(NULL);
152218de8d7fSPeter Avalos 	lang = packet_get_string(NULL);
152318de8d7fSPeter Avalos 	if (strlen(name) > 0)
152418de8d7fSPeter Avalos 		logit("%s", name);
152518de8d7fSPeter Avalos 	if (strlen(inst) > 0)
152618de8d7fSPeter Avalos 		logit("%s", inst);
152736e94dc5SPeter Avalos 	free(name);
152836e94dc5SPeter Avalos 	free(inst);
152936e94dc5SPeter Avalos 	free(lang);
153018de8d7fSPeter Avalos 
153118de8d7fSPeter Avalos 	num_prompts = packet_get_int();
153218de8d7fSPeter Avalos 	/*
153318de8d7fSPeter Avalos 	 * Begin to build info response packet based on prompts requested.
153418de8d7fSPeter Avalos 	 * We commit to providing the correct number of responses, so if
153518de8d7fSPeter Avalos 	 * further on we run into a problem that prevents this, we have to
153618de8d7fSPeter Avalos 	 * be sure and clean this up and send a correct error response.
153718de8d7fSPeter Avalos 	 */
153818de8d7fSPeter Avalos 	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
153918de8d7fSPeter Avalos 	packet_put_int(num_prompts);
154018de8d7fSPeter Avalos 
154118de8d7fSPeter Avalos 	debug2("input_userauth_info_req: num_prompts %d", num_prompts);
154218de8d7fSPeter Avalos 	for (i = 0; i < num_prompts; i++) {
154318de8d7fSPeter Avalos 		prompt = packet_get_string(NULL);
154418de8d7fSPeter Avalos 		echo = packet_get_char();
154518de8d7fSPeter Avalos 
154618de8d7fSPeter Avalos 		response = read_passphrase(prompt, echo ? RP_ECHO : 0);
154718de8d7fSPeter Avalos 
154818de8d7fSPeter Avalos 		packet_put_cstring(response);
154936e94dc5SPeter Avalos 		explicit_bzero(response, strlen(response));
155036e94dc5SPeter Avalos 		free(response);
155136e94dc5SPeter Avalos 		free(prompt);
155218de8d7fSPeter Avalos 	}
155318de8d7fSPeter Avalos 	packet_check_eom(); /* done with parsing incoming message. */
155418de8d7fSPeter Avalos 
155518de8d7fSPeter Avalos 	packet_add_padding(64);
155618de8d7fSPeter Avalos 	packet_send();
1557*e9778795SPeter Avalos 	return 0;
155818de8d7fSPeter Avalos }
155918de8d7fSPeter Avalos 
156018de8d7fSPeter Avalos static int
1561*e9778795SPeter Avalos ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp,
1562*e9778795SPeter Avalos     const u_char *data, size_t datalen)
156318de8d7fSPeter Avalos {
1564*e9778795SPeter Avalos 	struct sshbuf *b;
156518de8d7fSPeter Avalos 	struct stat st;
156618de8d7fSPeter Avalos 	pid_t pid;
1567*e9778795SPeter Avalos 	int i, r, to[2], from[2], status, sock = packet_get_connection_in();
1568*e9778795SPeter Avalos 	u_char rversion = 0, version = 2;
1569*e9778795SPeter Avalos 	void (*osigchld)(int);
157018de8d7fSPeter Avalos 
1571*e9778795SPeter Avalos 	*sigp = NULL;
1572*e9778795SPeter Avalos 	*lenp = 0;
157318de8d7fSPeter Avalos 
157418de8d7fSPeter Avalos 	if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1575*e9778795SPeter Avalos 		error("%s: not installed: %s", __func__, strerror(errno));
157618de8d7fSPeter Avalos 		return -1;
157718de8d7fSPeter Avalos 	}
1578*e9778795SPeter Avalos 	if (fflush(stdout) != 0) {
1579*e9778795SPeter Avalos 		error("%s: fflush: %s", __func__, strerror(errno));
1580*e9778795SPeter Avalos 		return -1;
1581*e9778795SPeter Avalos 	}
158218de8d7fSPeter Avalos 	if (pipe(to) < 0) {
1583*e9778795SPeter Avalos 		error("%s: pipe: %s", __func__, strerror(errno));
158418de8d7fSPeter Avalos 		return -1;
158518de8d7fSPeter Avalos 	}
158618de8d7fSPeter Avalos 	if (pipe(from) < 0) {
1587*e9778795SPeter Avalos 		error("%s: pipe: %s", __func__, strerror(errno));
158818de8d7fSPeter Avalos 		return -1;
158918de8d7fSPeter Avalos 	}
159018de8d7fSPeter Avalos 	if ((pid = fork()) < 0) {
1591*e9778795SPeter Avalos 		error("%s: fork: %s", __func__, strerror(errno));
159218de8d7fSPeter Avalos 		return -1;
159318de8d7fSPeter Avalos 	}
1594*e9778795SPeter Avalos 	osigchld = signal(SIGCHLD, SIG_DFL);
159518de8d7fSPeter Avalos 	if (pid == 0) {
1596856ea928SPeter Avalos 		/* keep the socket on exec */
1597*e9778795SPeter Avalos 		fcntl(sock, F_SETFD, 0);
159818de8d7fSPeter Avalos 		permanently_drop_suid(getuid());
159918de8d7fSPeter Avalos 		close(from[0]);
160018de8d7fSPeter Avalos 		if (dup2(from[1], STDOUT_FILENO) < 0)
1601*e9778795SPeter Avalos 			fatal("%s: dup2: %s", __func__, strerror(errno));
160218de8d7fSPeter Avalos 		close(to[1]);
160318de8d7fSPeter Avalos 		if (dup2(to[0], STDIN_FILENO) < 0)
1604*e9778795SPeter Avalos 			fatal("%s: dup2: %s", __func__, strerror(errno));
160518de8d7fSPeter Avalos 		close(from[1]);
160618de8d7fSPeter Avalos 		close(to[0]);
1607*e9778795SPeter Avalos 		/* Close everything but stdio and the socket */
1608*e9778795SPeter Avalos 		for (i = STDERR_FILENO + 1; i < sock; i++)
1609*e9778795SPeter Avalos 			close(i);
1610*e9778795SPeter Avalos 		closefrom(sock + 1);
1611*e9778795SPeter Avalos 		debug3("%s: [child] pid=%ld, exec %s",
1612*e9778795SPeter Avalos 		    __func__, (long)getpid(), _PATH_SSH_KEY_SIGN);
1613*e9778795SPeter Avalos 		execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL);
1614*e9778795SPeter Avalos 		fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN,
161518de8d7fSPeter Avalos 		    strerror(errno));
161618de8d7fSPeter Avalos 	}
161718de8d7fSPeter Avalos 	close(from[1]);
161818de8d7fSPeter Avalos 	close(to[0]);
161918de8d7fSPeter Avalos 
1620*e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL)
1621*e9778795SPeter Avalos 		fatal("%s: sshbuf_new failed", __func__);
1622*e9778795SPeter Avalos 	/* send # of sock, data to be signed */
1623*e9778795SPeter Avalos 	if ((r = sshbuf_put_u32(b, sock) != 0) ||
1624*e9778795SPeter Avalos 	    (r = sshbuf_put_string(b, data, datalen)) != 0)
1625*e9778795SPeter Avalos 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1626*e9778795SPeter Avalos 	if (ssh_msg_send(to[1], version, b) == -1)
1627*e9778795SPeter Avalos 		fatal("%s: couldn't send request", __func__);
1628*e9778795SPeter Avalos 	sshbuf_reset(b);
1629*e9778795SPeter Avalos 	r = ssh_msg_recv(from[0], b);
163018de8d7fSPeter Avalos 	close(from[0]);
163118de8d7fSPeter Avalos 	close(to[1]);
1632*e9778795SPeter Avalos 	if (r < 0) {
1633*e9778795SPeter Avalos 		error("%s: no reply", __func__);
1634*e9778795SPeter Avalos 		goto fail;
1635*e9778795SPeter Avalos 	}
163618de8d7fSPeter Avalos 
1637*e9778795SPeter Avalos 	errno = 0;
1638*e9778795SPeter Avalos 	while (waitpid(pid, &status, 0) < 0) {
1639*e9778795SPeter Avalos 		if (errno != EINTR) {
1640*e9778795SPeter Avalos 			error("%s: waitpid %ld: %s",
1641*e9778795SPeter Avalos 			    __func__, (long)pid, strerror(errno));
1642*e9778795SPeter Avalos 			goto fail;
1643*e9778795SPeter Avalos 		}
1644*e9778795SPeter Avalos 	}
1645*e9778795SPeter Avalos 	if (!WIFEXITED(status)) {
1646*e9778795SPeter Avalos 		error("%s: exited abnormally", __func__);
1647*e9778795SPeter Avalos 		goto fail;
1648*e9778795SPeter Avalos 	}
1649*e9778795SPeter Avalos 	if (WEXITSTATUS(status) != 0) {
1650*e9778795SPeter Avalos 		error("%s: exited with status %d",
1651*e9778795SPeter Avalos 		    __func__, WEXITSTATUS(status));
1652*e9778795SPeter Avalos 		goto fail;
1653*e9778795SPeter Avalos 	}
1654*e9778795SPeter Avalos 	if ((r = sshbuf_get_u8(b, &rversion)) != 0) {
1655*e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1656*e9778795SPeter Avalos 		goto fail;
1657*e9778795SPeter Avalos 	}
1658*e9778795SPeter Avalos 	if (rversion != version) {
1659*e9778795SPeter Avalos 		error("%s: bad version", __func__);
1660*e9778795SPeter Avalos 		goto fail;
1661*e9778795SPeter Avalos 	}
1662*e9778795SPeter Avalos 	if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) {
1663*e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1664*e9778795SPeter Avalos  fail:
1665*e9778795SPeter Avalos 		signal(SIGCHLD, osigchld);
1666*e9778795SPeter Avalos 		sshbuf_free(b);
166718de8d7fSPeter Avalos 		return -1;
166818de8d7fSPeter Avalos 	}
1669*e9778795SPeter Avalos 	signal(SIGCHLD, osigchld);
1670*e9778795SPeter Avalos 	sshbuf_free(b);
167118de8d7fSPeter Avalos 
167218de8d7fSPeter Avalos 	return 0;
167318de8d7fSPeter Avalos }
167418de8d7fSPeter Avalos 
167518de8d7fSPeter Avalos int
167618de8d7fSPeter Avalos userauth_hostbased(Authctxt *authctxt)
167718de8d7fSPeter Avalos {
1678*e9778795SPeter Avalos 	struct ssh *ssh = active_state;
1679*e9778795SPeter Avalos 	struct sshkey *private = NULL;
1680*e9778795SPeter Avalos 	struct sshbuf *b = NULL;
168118de8d7fSPeter Avalos 	const char *service;
1682*e9778795SPeter Avalos 	u_char *sig = NULL, *keyblob = NULL;
1683*e9778795SPeter Avalos 	char *fp = NULL, *chost = NULL, *lname = NULL;
1684*e9778795SPeter Avalos 	size_t siglen = 0, keylen = 0;
1685*e9778795SPeter Avalos 	int i, r, success = 0;
1686*e9778795SPeter Avalos 
1687*e9778795SPeter Avalos 	if (authctxt->ktypes == NULL) {
1688*e9778795SPeter Avalos 		authctxt->oktypes = xstrdup(options.hostbased_key_types);
1689*e9778795SPeter Avalos 		authctxt->ktypes = authctxt->oktypes;
1690*e9778795SPeter Avalos 	}
1691*e9778795SPeter Avalos 
1692*e9778795SPeter Avalos 	/*
1693*e9778795SPeter Avalos 	 * Work through each listed type pattern in HostbasedKeyTypes,
1694*e9778795SPeter Avalos 	 * trying each hostkey that matches the type in turn.
1695*e9778795SPeter Avalos 	 */
1696*e9778795SPeter Avalos 	for (;;) {
1697*e9778795SPeter Avalos 		if (authctxt->active_ktype == NULL)
1698*e9778795SPeter Avalos 			authctxt->active_ktype = strsep(&authctxt->ktypes, ",");
1699*e9778795SPeter Avalos 		if (authctxt->active_ktype == NULL ||
1700*e9778795SPeter Avalos 		    *authctxt->active_ktype == '\0')
1701*e9778795SPeter Avalos 			break;
1702*e9778795SPeter Avalos 		debug3("%s: trying key type %s", __func__,
1703*e9778795SPeter Avalos 		    authctxt->active_ktype);
170418de8d7fSPeter Avalos 
170518de8d7fSPeter Avalos 		/* check for a useful key */
1706*e9778795SPeter Avalos 		private = NULL;
1707*e9778795SPeter Avalos 		for (i = 0; i < authctxt->sensitive->nkeys; i++) {
1708*e9778795SPeter Avalos 			if (authctxt->sensitive->keys[i] == NULL ||
1709*e9778795SPeter Avalos 			    authctxt->sensitive->keys[i]->type == KEY_RSA1 ||
1710*e9778795SPeter Avalos 			    authctxt->sensitive->keys[i]->type == KEY_UNSPEC)
1711*e9778795SPeter Avalos 				continue;
1712*e9778795SPeter Avalos 			if (match_pattern_list(
1713*e9778795SPeter Avalos 			    sshkey_ssh_name(authctxt->sensitive->keys[i]),
1714*e9778795SPeter Avalos 			    authctxt->active_ktype, 0) != 1)
1715*e9778795SPeter Avalos 				continue;
171618de8d7fSPeter Avalos 			/* we take and free the key */
1717*e9778795SPeter Avalos 			private = authctxt->sensitive->keys[i];
1718*e9778795SPeter Avalos 			authctxt->sensitive->keys[i] = NULL;
171918de8d7fSPeter Avalos 			break;
172018de8d7fSPeter Avalos 		}
1721*e9778795SPeter Avalos 		/* Found one */
1722*e9778795SPeter Avalos 		if (private != NULL)
1723*e9778795SPeter Avalos 			break;
1724*e9778795SPeter Avalos 		/* No more keys of this type; advance */
1725*e9778795SPeter Avalos 		authctxt->active_ktype = NULL;
172618de8d7fSPeter Avalos 	}
1727*e9778795SPeter Avalos 	if (private == NULL) {
1728*e9778795SPeter Avalos 		free(authctxt->oktypes);
1729*e9778795SPeter Avalos 		authctxt->oktypes = authctxt->ktypes = NULL;
1730*e9778795SPeter Avalos 		authctxt->active_ktype = NULL;
173118de8d7fSPeter Avalos 		debug("No more client hostkeys for hostbased authentication.");
1732*e9778795SPeter Avalos 		goto out;
173318de8d7fSPeter Avalos 	}
1734*e9778795SPeter Avalos 
1735*e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(private, options.fingerprint_hash,
1736*e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL) {
1737*e9778795SPeter Avalos 		error("%s: sshkey_fingerprint failed", __func__);
1738*e9778795SPeter Avalos 		goto out;
173918de8d7fSPeter Avalos 	}
1740*e9778795SPeter Avalos 	debug("%s: trying hostkey %s %s",
1741*e9778795SPeter Avalos 	    __func__, sshkey_ssh_name(private), fp);
1742*e9778795SPeter Avalos 
174318de8d7fSPeter Avalos 	/* figure out a name for the client host */
1744*e9778795SPeter Avalos 	if ((lname = get_local_name(packet_get_connection_in())) == NULL) {
1745*e9778795SPeter Avalos 		error("%s: cannot get local ipaddr/name", __func__);
1746*e9778795SPeter Avalos 		goto out;
174718de8d7fSPeter Avalos 	}
1748*e9778795SPeter Avalos 
1749*e9778795SPeter Avalos 	/* XXX sshbuf_put_stringf? */
1750*e9778795SPeter Avalos 	xasprintf(&chost, "%s.", lname);
1751*e9778795SPeter Avalos 	debug2("%s: chost %s", __func__, chost);
175218de8d7fSPeter Avalos 
175318de8d7fSPeter Avalos 	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
175418de8d7fSPeter Avalos 	    authctxt->service;
175518de8d7fSPeter Avalos 
1756*e9778795SPeter Avalos 	/* construct data */
1757*e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL) {
1758*e9778795SPeter Avalos 		error("%s: sshbuf_new failed", __func__);
1759*e9778795SPeter Avalos 		goto out;
1760*e9778795SPeter Avalos 	}
1761*e9778795SPeter Avalos 	if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) {
1762*e9778795SPeter Avalos 		error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
1763*e9778795SPeter Avalos 		goto out;
1764*e9778795SPeter Avalos 	}
1765*e9778795SPeter Avalos 	if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
1766*e9778795SPeter Avalos 	    (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1767*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 ||
1768*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, service)) != 0 ||
1769*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 ||
1770*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 ||
1771*e9778795SPeter Avalos 	    (r = sshbuf_put_string(b, keyblob, keylen)) != 0 ||
1772*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, chost)) != 0 ||
1773*e9778795SPeter Avalos 	    (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) {
1774*e9778795SPeter Avalos 		error("%s: buffer error: %s", __func__, ssh_err(r));
1775*e9778795SPeter Avalos 		goto out;
1776*e9778795SPeter Avalos 	}
1777*e9778795SPeter Avalos 
1778*e9778795SPeter Avalos #ifdef DEBUG_PK
1779*e9778795SPeter Avalos 	sshbuf_dump(b, stderr);
1780*e9778795SPeter Avalos #endif
1781*e9778795SPeter Avalos 	if (authctxt->sensitive->external_keysign)
1782*e9778795SPeter Avalos 		r = ssh_keysign(private, &sig, &siglen,
1783*e9778795SPeter Avalos 		    sshbuf_ptr(b), sshbuf_len(b));
1784*e9778795SPeter Avalos 	else if ((r = sshkey_sign(private, &sig, &siglen,
1785*e9778795SPeter Avalos 	    sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0)
1786*e9778795SPeter Avalos 		debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1787*e9778795SPeter Avalos 	if (r != 0) {
1788*e9778795SPeter Avalos 		error("sign using hostkey %s %s failed",
1789*e9778795SPeter Avalos 		    sshkey_ssh_name(private), fp);
1790*e9778795SPeter Avalos 		goto out;
1791*e9778795SPeter Avalos 	}
1792*e9778795SPeter Avalos 	if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
1793*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 ||
1794*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 ||
1795*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 ||
1796*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 ||
1797*e9778795SPeter Avalos 	    (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 ||
1798*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, chost)) != 0 ||
1799*e9778795SPeter Avalos 	    (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 ||
1800*e9778795SPeter Avalos 	    (r = sshpkt_put_string(ssh, sig, siglen)) != 0 ||
1801*e9778795SPeter Avalos 	    (r = sshpkt_send(ssh)) != 0) {
1802*e9778795SPeter Avalos 		error("%s: packet error: %s", __func__, ssh_err(r));
1803*e9778795SPeter Avalos 		goto out;
1804*e9778795SPeter Avalos 	}
1805*e9778795SPeter Avalos 	success = 1;
1806*e9778795SPeter Avalos 
1807*e9778795SPeter Avalos  out:
1808*e9778795SPeter Avalos 	if (sig != NULL) {
1809*e9778795SPeter Avalos 		explicit_bzero(sig, siglen);
1810*e9778795SPeter Avalos 		free(sig);
1811*e9778795SPeter Avalos 	}
1812*e9778795SPeter Avalos 	free(keyblob);
1813*e9778795SPeter Avalos 	free(lname);
1814*e9778795SPeter Avalos 	free(fp);
1815*e9778795SPeter Avalos 	free(chost);
1816*e9778795SPeter Avalos 	sshkey_free(private);
1817*e9778795SPeter Avalos 	sshbuf_free(b);
1818*e9778795SPeter Avalos 
1819*e9778795SPeter Avalos 	return success;
182018de8d7fSPeter Avalos }
182118de8d7fSPeter Avalos 
182218de8d7fSPeter Avalos /* find auth method */
182318de8d7fSPeter Avalos 
182418de8d7fSPeter Avalos /*
182518de8d7fSPeter Avalos  * given auth method name, if configurable options permit this method fill
182618de8d7fSPeter Avalos  * in auth_ident field and return true, otherwise return false.
182718de8d7fSPeter Avalos  */
182818de8d7fSPeter Avalos static int
182918de8d7fSPeter Avalos authmethod_is_enabled(Authmethod *method)
183018de8d7fSPeter Avalos {
183118de8d7fSPeter Avalos 	if (method == NULL)
183218de8d7fSPeter Avalos 		return 0;
183318de8d7fSPeter Avalos 	/* return false if options indicate this method is disabled */
183418de8d7fSPeter Avalos 	if  (method->enabled == NULL || *method->enabled == 0)
183518de8d7fSPeter Avalos 		return 0;
183618de8d7fSPeter Avalos 	/* return false if batch mode is enabled but method needs interactive mode */
183718de8d7fSPeter Avalos 	if  (method->batch_flag != NULL && *method->batch_flag != 0)
183818de8d7fSPeter Avalos 		return 0;
183918de8d7fSPeter Avalos 	return 1;
184018de8d7fSPeter Avalos }
184118de8d7fSPeter Avalos 
184218de8d7fSPeter Avalos static Authmethod *
184318de8d7fSPeter Avalos authmethod_lookup(const char *name)
184418de8d7fSPeter Avalos {
184518de8d7fSPeter Avalos 	Authmethod *method = NULL;
184618de8d7fSPeter Avalos 	if (name != NULL)
184718de8d7fSPeter Avalos 		for (method = authmethods; method->name != NULL; method++)
184818de8d7fSPeter Avalos 			if (strcmp(name, method->name) == 0)
184918de8d7fSPeter Avalos 				return method;
185018de8d7fSPeter Avalos 	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
185118de8d7fSPeter Avalos 	return NULL;
185218de8d7fSPeter Avalos }
185318de8d7fSPeter Avalos 
185418de8d7fSPeter Avalos /* XXX internal state */
185518de8d7fSPeter Avalos static Authmethod *current = NULL;
185618de8d7fSPeter Avalos static char *supported = NULL;
185718de8d7fSPeter Avalos static char *preferred = NULL;
185818de8d7fSPeter Avalos 
185918de8d7fSPeter Avalos /*
186018de8d7fSPeter Avalos  * Given the authentication method list sent by the server, return the
186118de8d7fSPeter Avalos  * next method we should try.  If the server initially sends a nil list,
186218de8d7fSPeter Avalos  * use a built-in default list.
186318de8d7fSPeter Avalos  */
186418de8d7fSPeter Avalos static Authmethod *
186518de8d7fSPeter Avalos authmethod_get(char *authlist)
186618de8d7fSPeter Avalos {
186718de8d7fSPeter Avalos 	char *name = NULL;
186818de8d7fSPeter Avalos 	u_int next;
186918de8d7fSPeter Avalos 
187018de8d7fSPeter Avalos 	/* Use a suitable default if we're passed a nil list.  */
187118de8d7fSPeter Avalos 	if (authlist == NULL || strlen(authlist) == 0)
187218de8d7fSPeter Avalos 		authlist = options.preferred_authentications;
187318de8d7fSPeter Avalos 
187418de8d7fSPeter Avalos 	if (supported == NULL || strcmp(authlist, supported) != 0) {
187518de8d7fSPeter Avalos 		debug3("start over, passed a different list %s", authlist);
187636e94dc5SPeter Avalos 		free(supported);
187718de8d7fSPeter Avalos 		supported = xstrdup(authlist);
187818de8d7fSPeter Avalos 		preferred = options.preferred_authentications;
187918de8d7fSPeter Avalos 		debug3("preferred %s", preferred);
188018de8d7fSPeter Avalos 		current = NULL;
188118de8d7fSPeter Avalos 	} else if (current != NULL && authmethod_is_enabled(current))
188218de8d7fSPeter Avalos 		return current;
188318de8d7fSPeter Avalos 
188418de8d7fSPeter Avalos 	for (;;) {
188518de8d7fSPeter Avalos 		if ((name = match_list(preferred, supported, &next)) == NULL) {
188618de8d7fSPeter Avalos 			debug("No more authentication methods to try.");
188718de8d7fSPeter Avalos 			current = NULL;
188818de8d7fSPeter Avalos 			return NULL;
188918de8d7fSPeter Avalos 		}
189018de8d7fSPeter Avalos 		preferred += next;
189118de8d7fSPeter Avalos 		debug3("authmethod_lookup %s", name);
189218de8d7fSPeter Avalos 		debug3("remaining preferred: %s", preferred);
189318de8d7fSPeter Avalos 		if ((current = authmethod_lookup(name)) != NULL &&
189418de8d7fSPeter Avalos 		    authmethod_is_enabled(current)) {
189518de8d7fSPeter Avalos 			debug3("authmethod_is_enabled %s", name);
189618de8d7fSPeter Avalos 			debug("Next authentication method: %s", name);
189736e94dc5SPeter Avalos 			free(name);
189818de8d7fSPeter Avalos 			return current;
189918de8d7fSPeter Avalos 		}
190036e94dc5SPeter Avalos 		free(name);
190118de8d7fSPeter Avalos 	}
190218de8d7fSPeter Avalos }
190318de8d7fSPeter Avalos 
190418de8d7fSPeter Avalos static char *
190518de8d7fSPeter Avalos authmethods_get(void)
190618de8d7fSPeter Avalos {
190718de8d7fSPeter Avalos 	Authmethod *method = NULL;
190818de8d7fSPeter Avalos 	Buffer b;
190918de8d7fSPeter Avalos 	char *list;
191018de8d7fSPeter Avalos 
191118de8d7fSPeter Avalos 	buffer_init(&b);
191218de8d7fSPeter Avalos 	for (method = authmethods; method->name != NULL; method++) {
191318de8d7fSPeter Avalos 		if (authmethod_is_enabled(method)) {
191418de8d7fSPeter Avalos 			if (buffer_len(&b) > 0)
191518de8d7fSPeter Avalos 				buffer_append(&b, ",", 1);
191618de8d7fSPeter Avalos 			buffer_append(&b, method->name, strlen(method->name));
191718de8d7fSPeter Avalos 		}
191818de8d7fSPeter Avalos 	}
1919*e9778795SPeter Avalos 	if ((list = sshbuf_dup_string(&b)) == NULL)
1920*e9778795SPeter Avalos 		fatal("%s: sshbuf_dup_string failed", __func__);
192118de8d7fSPeter Avalos 	buffer_free(&b);
192218de8d7fSPeter Avalos 	return list;
192318de8d7fSPeter Avalos }
1924cb5eb4f1SPeter Avalos 
1925