sshconnect2.c revision 215116
1215116Sdes/* $OpenBSD: sshconnect2.c,v 1.183 2010/04/26 22:28:24 djm Exp $ */
260573Skris/*
360573Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4192595Sdes * Copyright (c) 2008 Damien Miller.  All rights reserved.
560573Skris *
660573Skris * Redistribution and use in source and binary forms, with or without
760573Skris * modification, are permitted provided that the following conditions
860573Skris * are met:
960573Skris * 1. Redistributions of source code must retain the above copyright
1060573Skris *    notice, this list of conditions and the following disclaimer.
1160573Skris * 2. Redistributions in binary form must reproduce the above copyright
1260573Skris *    notice, this list of conditions and the following disclaimer in the
1360573Skris *    documentation and/or other materials provided with the distribution.
1460573Skris *
1560573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1660573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1760573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1860573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1960573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2060573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2160573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2260573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2360573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2460573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2560573Skris */
2660573Skris
2760573Skris#include "includes.h"
2860573Skris
29162856Sdes#include <sys/types.h>
30162856Sdes#include <sys/socket.h>
31162856Sdes#include <sys/wait.h>
32162856Sdes#include <sys/stat.h>
33162856Sdes
34162856Sdes#include <errno.h>
35204917Sdes#include <fcntl.h>
36181111Sdes#include <netdb.h>
37162856Sdes#include <pwd.h>
38162856Sdes#include <signal.h>
39162856Sdes#include <stdarg.h>
40162856Sdes#include <stdio.h>
41162856Sdes#include <string.h>
42162856Sdes#include <unistd.h>
43181111Sdes#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
44181111Sdes#include <vis.h>
45181111Sdes#endif
46162856Sdes
47124211Sdes#include "openbsd-compat/sys-queue.h"
48124211Sdes
49162856Sdes#include "xmalloc.h"
5060573Skris#include "ssh.h"
5176262Sgreen#include "ssh2.h"
5260573Skris#include "buffer.h"
5360573Skris#include "packet.h"
5460573Skris#include "compat.h"
5576262Sgreen#include "cipher.h"
56162856Sdes#include "key.h"
5760573Skris#include "kex.h"
5860573Skris#include "myproposal.h"
5960573Skris#include "sshconnect.h"
6060573Skris#include "authfile.h"
6176262Sgreen#include "dh.h"
6276262Sgreen#include "authfd.h"
6376262Sgreen#include "log.h"
6476262Sgreen#include "readconf.h"
65137019Sdes#include "misc.h"
6676262Sgreen#include "match.h"
6769587Sgreen#include "dispatch.h"
6876262Sgreen#include "canohost.h"
6998684Sdes#include "msg.h"
7098684Sdes#include "pathnames.h"
71162856Sdes#include "uidswap.h"
72197679Sdes#include "schnorr.h"
73192595Sdes#include "jpake.h"
7460573Skris
75124211Sdes#ifdef GSSAPI
76124211Sdes#include "ssh-gss.h"
77124211Sdes#endif
78124211Sdes
7960573Skris/* import */
8060573Skrisextern char *client_version_string;
8160573Skrisextern char *server_version_string;
8260573Skrisextern Options options;
8360573Skris
8460573Skris/*
8560573Skris * SSH2 key exchange
8660573Skris */
8760573Skris
8876262Sgreenu_char *session_id2 = NULL;
89124211Sdesu_int session_id2_len = 0;
9060573Skris
9176262Sgreenchar *xxx_host;
9276262Sgreenstruct sockaddr *xxx_hostaddr;
9376262Sgreen
9476262SgreenKex *xxx_kex = NULL;
9576262Sgreen
9692559Sdesstatic int
9792559Sdesverify_host_key_callback(Key *hostkey)
9876262Sgreen{
9992559Sdes	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
10092559Sdes		fatal("Host key verification failed.");
10176262Sgreen	return 0;
10276262Sgreen}
10376262Sgreen
10460573Skrisvoid
10569587Sgreenssh_kex2(char *host, struct sockaddr *hostaddr)
10660573Skris{
10769587Sgreen	Kex *kex;
10869587Sgreen
10976262Sgreen	xxx_host = host;
11076262Sgreen	xxx_hostaddr = hostaddr;
11176262Sgreen
11276262Sgreen	if (options.ciphers == (char *)-1) {
113124211Sdes		logit("No valid ciphers for protocol version 2 given, using defaults.");
11476262Sgreen		options.ciphers = NULL;
11569587Sgreen	}
11669587Sgreen	if (options.ciphers != NULL) {
11769587Sgreen		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
11869587Sgreen		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
11969587Sgreen	}
12076262Sgreen	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
12176262Sgreen	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
12276262Sgreen	myproposal[PROPOSAL_ENC_ALGS_STOC] =
12376262Sgreen	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
12469587Sgreen	if (options.compression) {
12576262Sgreen		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
126149753Sdes		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none";
12769587Sgreen	} else {
12876262Sgreen		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
129149753Sdes		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib";
13069587Sgreen	}
13176262Sgreen	if (options.macs != NULL) {
13276262Sgreen		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
13376262Sgreen		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
13476262Sgreen	}
13576262Sgreen	if (options.hostkeyalgorithms != NULL)
13692559Sdes		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
13776262Sgreen		    options.hostkeyalgorithms;
13869587Sgreen
139124211Sdes	if (options.rekey_limit)
140181111Sdes		packet_set_rekey_limit((u_int32_t)options.rekey_limit);
141124211Sdes
14276262Sgreen	/* start key exchange */
14376262Sgreen	kex = kex_setup(myproposal);
144113911Sdes	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
145137019Sdes	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
146113911Sdes	kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
147162856Sdes	kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
14876262Sgreen	kex->client_version_string=client_version_string;
14976262Sgreen	kex->server_version_string=server_version_string;
15092559Sdes	kex->verify_host_key=&verify_host_key_callback;
15169587Sgreen
15276262Sgreen	xxx_kex = kex;
15369587Sgreen
15476262Sgreen	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
15569587Sgreen
156204917Sdes	if (options.use_roaming && !kex->roaming) {
157204917Sdes		debug("Roaming not allowed by server");
158204917Sdes		options.use_roaming = 0;
159204917Sdes	}
160204917Sdes
16176262Sgreen	session_id2 = kex->session_id;
16276262Sgreen	session_id2_len = kex->session_id_len;
16369587Sgreen
16469587Sgreen#ifdef DEBUG_KEXDH
16569587Sgreen	/* send 1st encrypted/maced/compressed message */
16669587Sgreen	packet_start(SSH2_MSG_IGNORE);
16769587Sgreen	packet_put_cstring("markus");
16869587Sgreen	packet_send();
16969587Sgreen	packet_write_wait();
17069587Sgreen#endif
17169587Sgreen}
17269587Sgreen
17369587Sgreen/*
17460573Skris * Authenticate user
17560573Skris */
17669587Sgreen
17769587Sgreentypedef struct Authctxt Authctxt;
17869587Sgreentypedef struct Authmethod Authmethod;
179124211Sdestypedef struct identity Identity;
180124211Sdestypedef struct idlist Idlist;
18169587Sgreen
182124211Sdesstruct identity {
183124211Sdes	TAILQ_ENTRY(identity) next;
184124211Sdes	AuthenticationConnection *ac;	/* set if agent supports key */
185124211Sdes	Key	*key;			/* public/private key */
186124211Sdes	char	*filename;		/* comment for agent-only keys */
187124211Sdes	int	tried;
188124211Sdes	int	isprivate;		/* key points to the private key */
189124211Sdes};
190124211SdesTAILQ_HEAD(idlist, identity);
19169587Sgreen
19269587Sgreenstruct Authctxt {
19369587Sgreen	const char *server_user;
19476262Sgreen	const char *local_user;
19569587Sgreen	const char *host;
19669587Sgreen	const char *service;
19769587Sgreen	Authmethod *method;
198215116Sdes	sig_atomic_t success;
19976262Sgreen	char *authlist;
20076262Sgreen	/* pubkey */
201124211Sdes	Idlist keys;
20276262Sgreen	AuthenticationConnection *agent;
20376262Sgreen	/* hostbased */
20498684Sdes	Sensitive *sensitive;
20592559Sdes	/* kbd-interactive */
20692559Sdes	int info_req_seen;
207124211Sdes	/* generic */
208124211Sdes	void *methoddata;
20969587Sgreen};
21069587Sgreenstruct Authmethod {
21169587Sgreen	char	*name;		/* string to compare against server's list */
21269587Sgreen	int	(*userauth)(Authctxt *authctxt);
213192595Sdes	void	(*cleanup)(Authctxt *authctxt);
21469587Sgreen	int	*enabled;	/* flag in option struct that enables method */
21569587Sgreen	int	*batch_flag;	/* flag in option struct that disables method */
21669587Sgreen};
21769587Sgreen
21892559Sdesvoid	input_userauth_success(int, u_int32_t, void *);
219204917Sdesvoid	input_userauth_success_unexpected(int, u_int32_t, void *);
22092559Sdesvoid	input_userauth_failure(int, u_int32_t, void *);
22192559Sdesvoid	input_userauth_banner(int, u_int32_t, void *);
22292559Sdesvoid	input_userauth_error(int, u_int32_t, void *);
22392559Sdesvoid	input_userauth_info_req(int, u_int32_t, void *);
22492559Sdesvoid	input_userauth_pk_ok(int, u_int32_t, void *);
22598684Sdesvoid	input_userauth_passwd_changereq(int, u_int32_t, void *);
226192595Sdesvoid	input_userauth_jpake_server_step1(int, u_int32_t, void *);
227192595Sdesvoid	input_userauth_jpake_server_step2(int, u_int32_t, void *);
228192595Sdesvoid	input_userauth_jpake_server_confirm(int, u_int32_t, void *);
22969587Sgreen
23092559Sdesint	userauth_none(Authctxt *);
23192559Sdesint	userauth_pubkey(Authctxt *);
23292559Sdesint	userauth_passwd(Authctxt *);
23392559Sdesint	userauth_kbdint(Authctxt *);
23492559Sdesint	userauth_hostbased(Authctxt *);
235192595Sdesint	userauth_jpake(Authctxt *);
23669587Sgreen
237192595Sdesvoid	userauth_jpake_cleanup(Authctxt *);
238192595Sdes
239124211Sdes#ifdef GSSAPI
240124211Sdesint	userauth_gssapi(Authctxt *authctxt);
241124211Sdesvoid	input_gssapi_response(int type, u_int32_t, void *);
242124211Sdesvoid	input_gssapi_token(int type, u_int32_t, void *);
243124211Sdesvoid	input_gssapi_hash(int type, u_int32_t, void *);
244124211Sdesvoid	input_gssapi_error(int, u_int32_t, void *);
245124211Sdesvoid	input_gssapi_errtok(int, u_int32_t, void *);
246124211Sdes#endif
247124211Sdes
24892559Sdesvoid	userauth(Authctxt *, char *);
24976262Sgreen
250124211Sdesstatic int sign_and_send_pubkey(Authctxt *, Identity *);
251124211Sdesstatic void pubkey_prepare(Authctxt *);
252124211Sdesstatic void pubkey_cleanup(Authctxt *);
253124211Sdesstatic Key *load_identity_file(char *);
25476262Sgreen
25592559Sdesstatic Authmethod *authmethod_get(char *authlist);
25692559Sdesstatic Authmethod *authmethod_lookup(const char *name);
25792559Sdesstatic char *authmethods_get(void);
25869587Sgreen
25969587SgreenAuthmethod authmethods[] = {
260124211Sdes#ifdef GSSAPI
261126277Sdes	{"gssapi-with-mic",
262124211Sdes		userauth_gssapi,
263192595Sdes		NULL,
264124211Sdes		&options.gss_authentication,
265124211Sdes		NULL},
266124211Sdes#endif
26792559Sdes	{"hostbased",
26892559Sdes		userauth_hostbased,
269192595Sdes		NULL,
27092559Sdes		&options.hostbased_authentication,
27192559Sdes		NULL},
27269587Sgreen	{"publickey",
27369587Sgreen		userauth_pubkey,
274192595Sdes		NULL,
27576262Sgreen		&options.pubkey_authentication,
27669587Sgreen		NULL},
277192595Sdes#ifdef JPAKE
278192595Sdes	{"jpake-01@openssh.com",
279192595Sdes		userauth_jpake,
280192595Sdes		userauth_jpake_cleanup,
281192595Sdes		&options.zero_knowledge_password_authentication,
282192595Sdes		&options.batch_mode},
283192595Sdes#endif
28492559Sdes	{"keyboard-interactive",
28592559Sdes		userauth_kbdint,
286192595Sdes		NULL,
28792559Sdes		&options.kbd_interactive_authentication,
28892559Sdes		&options.batch_mode},
28969587Sgreen	{"password",
29069587Sgreen		userauth_passwd,
291192595Sdes		NULL,
29269587Sgreen		&options.password_authentication,
29369587Sgreen		&options.batch_mode},
29469587Sgreen	{"none",
29569587Sgreen		userauth_none,
29669587Sgreen		NULL,
297192595Sdes		NULL,
29869587Sgreen		NULL},
299192595Sdes	{NULL, NULL, NULL, NULL, NULL}
30069587Sgreen};
30169587Sgreen
30269587Sgreenvoid
30376262Sgreenssh_userauth2(const char *local_user, const char *server_user, char *host,
30498684Sdes    Sensitive *sensitive)
30569587Sgreen{
30669587Sgreen	Authctxt authctxt;
30769587Sgreen	int type;
30869587Sgreen
30992559Sdes	if (options.challenge_response_authentication)
31076262Sgreen		options.kbd_interactive_authentication = 1;
31176262Sgreen
31269587Sgreen	packet_start(SSH2_MSG_SERVICE_REQUEST);
31369587Sgreen	packet_put_cstring("ssh-userauth");
31469587Sgreen	packet_send();
315113911Sdes	debug("SSH2_MSG_SERVICE_REQUEST sent");
31669587Sgreen	packet_write_wait();
31792559Sdes	type = packet_read();
318113911Sdes	if (type != SSH2_MSG_SERVICE_ACCEPT)
319113911Sdes		fatal("Server denied authentication request: %d", type);
32069587Sgreen	if (packet_remaining() > 0) {
32192559Sdes		char *reply = packet_get_string(NULL);
322113911Sdes		debug2("service_accept: %s", reply);
32369587Sgreen		xfree(reply);
32469587Sgreen	} else {
325113911Sdes		debug2("buggy server: service_accept w/o service");
32669587Sgreen	}
32792559Sdes	packet_check_eom();
328113911Sdes	debug("SSH2_MSG_SERVICE_ACCEPT received");
32969587Sgreen
33076262Sgreen	if (options.preferred_authentications == NULL)
33176262Sgreen		options.preferred_authentications = authmethods_get();
33276262Sgreen
33369587Sgreen	/* setup authentication context */
33492559Sdes	memset(&authctxt, 0, sizeof(authctxt));
335124211Sdes	pubkey_prepare(&authctxt);
33669587Sgreen	authctxt.server_user = server_user;
33776262Sgreen	authctxt.local_user = local_user;
33869587Sgreen	authctxt.host = host;
33969587Sgreen	authctxt.service = "ssh-connection";		/* service name */
34069587Sgreen	authctxt.success = 0;
34169587Sgreen	authctxt.method = authmethod_lookup("none");
34276262Sgreen	authctxt.authlist = NULL;
343124211Sdes	authctxt.methoddata = NULL;
34498684Sdes	authctxt.sensitive = sensitive;
34592559Sdes	authctxt.info_req_seen = 0;
34669587Sgreen	if (authctxt.method == NULL)
34769587Sgreen		fatal("ssh_userauth2: internal error: cannot send userauth none request");
34869587Sgreen
34969587Sgreen	/* initial userauth request */
35069587Sgreen	userauth_none(&authctxt);
35169587Sgreen
35269587Sgreen	dispatch_init(&input_userauth_error);
35369587Sgreen	dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
35469587Sgreen	dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
35576262Sgreen	dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
35669587Sgreen	dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);	/* loop until success */
35769587Sgreen
358124211Sdes	pubkey_cleanup(&authctxt);
359124211Sdes	dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
36069587Sgreen
361113911Sdes	debug("Authentication succeeded (%s).", authctxt.method->name);
36269587Sgreen}
363124211Sdes
36469587Sgreenvoid
36576262Sgreenuserauth(Authctxt *authctxt, char *authlist)
36676262Sgreen{
367192595Sdes	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
368192595Sdes		authctxt->method->cleanup(authctxt);
369192595Sdes
370124211Sdes	if (authctxt->methoddata) {
371124211Sdes		xfree(authctxt->methoddata);
372124211Sdes		authctxt->methoddata = NULL;
373124211Sdes	}
37476262Sgreen	if (authlist == NULL) {
37576262Sgreen		authlist = authctxt->authlist;
37676262Sgreen	} else {
37776262Sgreen		if (authctxt->authlist)
37876262Sgreen			xfree(authctxt->authlist);
37976262Sgreen		authctxt->authlist = authlist;
38076262Sgreen	}
38176262Sgreen	for (;;) {
38276262Sgreen		Authmethod *method = authmethod_get(authlist);
38376262Sgreen		if (method == NULL)
38476262Sgreen			fatal("Permission denied (%s).", authlist);
38576262Sgreen		authctxt->method = method;
386124211Sdes
387124211Sdes		/* reset the per method handler */
388124211Sdes		dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
389124211Sdes		    SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
390124211Sdes
391124211Sdes		/* and try new method */
39276262Sgreen		if (method->userauth(authctxt) != 0) {
39376262Sgreen			debug2("we sent a %s packet, wait for reply", method->name);
39476262Sgreen			break;
39576262Sgreen		} else {
39676262Sgreen			debug2("we did not send a packet, disable method");
39776262Sgreen			method->enabled = NULL;
39876262Sgreen		}
39976262Sgreen	}
40076262Sgreen}
40199063Sdes
402192595Sdes/* ARGSUSED */
40376262Sgreenvoid
40492559Sdesinput_userauth_error(int type, u_int32_t seq, void *ctxt)
40569587Sgreen{
40676262Sgreen	fatal("input_userauth_error: bad message during authentication: "
407149753Sdes	    "type %d", type);
40869587Sgreen}
40999063Sdes
410192595Sdes/* ARGSUSED */
41169587Sgreenvoid
41292559Sdesinput_userauth_banner(int type, u_int32_t seq, void *ctxt)
41376262Sgreen{
414181111Sdes	char *msg, *raw, *lang;
415181111Sdes	u_int len;
416126277Sdes
41776262Sgreen	debug3("input_userauth_banner");
418181111Sdes	raw = packet_get_string(&len);
41976262Sgreen	lang = packet_get_string(NULL);
420192595Sdes	if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) {
421181111Sdes		if (len > 65536)
422181111Sdes			len = 65536;
423183336Sdes		msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */
424204917Sdes		strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH);
425126277Sdes		fprintf(stderr, "%s", msg);
426181111Sdes		xfree(msg);
427181111Sdes	}
428181111Sdes	xfree(raw);
42976262Sgreen	xfree(lang);
43076262Sgreen}
43199063Sdes
432192595Sdes/* ARGSUSED */
43376262Sgreenvoid
43492559Sdesinput_userauth_success(int type, u_int32_t seq, void *ctxt)
43569587Sgreen{
43669587Sgreen	Authctxt *authctxt = ctxt;
437204917Sdes
43869587Sgreen	if (authctxt == NULL)
43969587Sgreen		fatal("input_userauth_success: no authentication context");
440126277Sdes	if (authctxt->authlist) {
44176262Sgreen		xfree(authctxt->authlist);
442126277Sdes		authctxt->authlist = NULL;
443126277Sdes	}
444204917Sdes	if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
445204917Sdes		authctxt->method->cleanup(authctxt);
446126277Sdes	if (authctxt->methoddata) {
447124211Sdes		xfree(authctxt->methoddata);
448126277Sdes		authctxt->methoddata = NULL;
449126277Sdes	}
45069587Sgreen	authctxt->success = 1;			/* break out */
45169587Sgreen}
45299063Sdes
453204917Sdesvoid
454204917Sdesinput_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt)
455204917Sdes{
456204917Sdes	Authctxt *authctxt = ctxt;
457204917Sdes
458204917Sdes	if (authctxt == NULL)
459204917Sdes		fatal("%s: no authentication context", __func__);
460204917Sdes
461204917Sdes	fatal("Unexpected authentication success during %s.",
462204917Sdes	    authctxt->method->name);
463204917Sdes}
464204917Sdes
465192595Sdes/* ARGSUSED */
46669587Sgreenvoid
46792559Sdesinput_userauth_failure(int type, u_int32_t seq, void *ctxt)
46869587Sgreen{
46969587Sgreen	Authctxt *authctxt = ctxt;
47069587Sgreen	char *authlist = NULL;
47169587Sgreen	int partial;
47269587Sgreen
47369587Sgreen	if (authctxt == NULL)
47469587Sgreen		fatal("input_userauth_failure: no authentication context");
47569587Sgreen
47669587Sgreen	authlist = packet_get_string(NULL);
47769587Sgreen	partial = packet_get_char();
47892559Sdes	packet_check_eom();
47969587Sgreen
48069587Sgreen	if (partial != 0)
481124211Sdes		logit("Authenticated with partial success.");
482113911Sdes	debug("Authentications that can continue: %s", authlist);
48369587Sgreen
48476262Sgreen	userauth(authctxt, authlist);
48576262Sgreen}
486192595Sdes
487192595Sdes/* ARGSUSED */
48876262Sgreenvoid
48992559Sdesinput_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
49076262Sgreen{
49176262Sgreen	Authctxt *authctxt = ctxt;
49276262Sgreen	Key *key = NULL;
493124211Sdes	Identity *id = NULL;
49476262Sgreen	Buffer b;
49592559Sdes	int pktype, sent = 0;
49692559Sdes	u_int alen, blen;
49792559Sdes	char *pkalg, *fp;
49892559Sdes	u_char *pkblob;
49976262Sgreen
50076262Sgreen	if (authctxt == NULL)
50176262Sgreen		fatal("input_userauth_pk_ok: no authentication context");
50276262Sgreen	if (datafellows & SSH_BUG_PKOK) {
50376262Sgreen		/* this is similar to SSH_BUG_PKAUTH */
50476262Sgreen		debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
50576262Sgreen		pkblob = packet_get_string(&blen);
50676262Sgreen		buffer_init(&b);
50776262Sgreen		buffer_append(&b, pkblob, blen);
50876262Sgreen		pkalg = buffer_get_string(&b, &alen);
50976262Sgreen		buffer_free(&b);
51076262Sgreen	} else {
51176262Sgreen		pkalg = packet_get_string(&alen);
51276262Sgreen		pkblob = packet_get_string(&blen);
51376262Sgreen	}
51492559Sdes	packet_check_eom();
51576262Sgreen
516124211Sdes	debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
51776262Sgreen
518124211Sdes	if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
519124211Sdes		debug("unknown pkalg %s", pkalg);
520124211Sdes		goto done;
521124211Sdes	}
522124211Sdes	if ((key = key_from_blob(pkblob, blen)) == NULL) {
523124211Sdes		debug("no key from blob. pkalg %s", pkalg);
524124211Sdes		goto done;
525124211Sdes	}
526124211Sdes	if (key->type != pktype) {
527124211Sdes		error("input_userauth_pk_ok: type mismatch "
528124211Sdes		    "for decoded key (received %d, expected %d)",
529124211Sdes		    key->type, pktype);
530124211Sdes		goto done;
531124211Sdes	}
532124211Sdes	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
533124211Sdes	debug2("input_userauth_pk_ok: fp %s", fp);
534124211Sdes	xfree(fp);
535124211Sdes
536126277Sdes	/*
537126277Sdes	 * search keys in the reverse order, because last candidate has been
538126277Sdes	 * moved to the end of the queue.  this also avoids confusion by
539126277Sdes	 * duplicate keys
540126277Sdes	 */
541137019Sdes	TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
542124211Sdes		if (key_equal(key, id->key)) {
543124211Sdes			sent = sign_and_send_pubkey(authctxt, id);
54469587Sgreen			break;
54569587Sgreen		}
546124211Sdes	}
547124211Sdesdone:
54876262Sgreen	if (key != NULL)
54976262Sgreen		key_free(key);
55076262Sgreen	xfree(pkalg);
55176262Sgreen	xfree(pkblob);
55276262Sgreen
553106130Sdes	/* try another method if we did not send a packet */
55476262Sgreen	if (sent == 0)
55576262Sgreen		userauth(authctxt, NULL);
556124211Sdes}
55776262Sgreen
558124211Sdes#ifdef GSSAPI
559126277Sdesint
560124211Sdesuserauth_gssapi(Authctxt *authctxt)
561124211Sdes{
562124211Sdes	Gssctxt *gssctxt = NULL;
563126277Sdes	static gss_OID_set gss_supported = NULL;
564149753Sdes	static u_int mech = 0;
565124211Sdes	OM_uint32 min;
566124211Sdes	int ok = 0;
567124211Sdes
568124211Sdes	/* Try one GSSAPI method at a time, rather than sending them all at
569124211Sdes	 * once. */
570124211Sdes
571126277Sdes	if (gss_supported == NULL)
572126277Sdes		gss_indicate_mechs(&min, &gss_supported);
573124211Sdes
574124211Sdes	/* Check to see if the mechanism is usable before we offer it */
575126277Sdes	while (mech < gss_supported->count && !ok) {
576124211Sdes		/* My DER encoding requires length<128 */
577126277Sdes		if (gss_supported->elements[mech].length < 128 &&
578162856Sdes		    ssh_gssapi_check_mechanism(&gssctxt,
579162856Sdes		    &gss_supported->elements[mech], authctxt->host)) {
580124211Sdes			ok = 1; /* Mechanism works */
581124211Sdes		} else {
582124211Sdes			mech++;
583124211Sdes		}
584124211Sdes	}
585124211Sdes
586149753Sdes	if (!ok)
587149753Sdes		return 0;
588124211Sdes
589124211Sdes	authctxt->methoddata=(void *)gssctxt;
590124211Sdes
591124211Sdes	packet_start(SSH2_MSG_USERAUTH_REQUEST);
592124211Sdes	packet_put_cstring(authctxt->server_user);
593124211Sdes	packet_put_cstring(authctxt->service);
594124211Sdes	packet_put_cstring(authctxt->method->name);
595124211Sdes
596124211Sdes	packet_put_int(1);
597124211Sdes
598126277Sdes	packet_put_int((gss_supported->elements[mech].length) + 2);
599126277Sdes	packet_put_char(SSH_GSS_OIDTYPE);
600126277Sdes	packet_put_char(gss_supported->elements[mech].length);
601126277Sdes	packet_put_raw(gss_supported->elements[mech].elements,
602126277Sdes	    gss_supported->elements[mech].length);
603124211Sdes
604124211Sdes	packet_send();
605124211Sdes
606124211Sdes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
607124211Sdes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
608124211Sdes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
609124211Sdes	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
610124211Sdes
611124211Sdes	mech++; /* Move along to next candidate */
612124211Sdes
613124211Sdes	return 1;
61469587Sgreen}
61569587Sgreen
616126277Sdesstatic OM_uint32
617126277Sdesprocess_gssapi_token(void *ctxt, gss_buffer_t recv_tok)
618126277Sdes{
619126277Sdes	Authctxt *authctxt = ctxt;
620126277Sdes	Gssctxt *gssctxt = authctxt->methoddata;
621126277Sdes	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
622149753Sdes	gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
623149753Sdes	gss_buffer_desc gssbuf;
624126277Sdes	OM_uint32 status, ms, flags;
625126277Sdes	Buffer b;
626126277Sdes
627126277Sdes	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
628126277Sdes	    recv_tok, &send_tok, &flags);
629126277Sdes
630126277Sdes	if (send_tok.length > 0) {
631126277Sdes		if (GSS_ERROR(status))
632126277Sdes			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
633126277Sdes		else
634126277Sdes			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
635126277Sdes
636126277Sdes		packet_put_string(send_tok.value, send_tok.length);
637126277Sdes		packet_send();
638126277Sdes		gss_release_buffer(&ms, &send_tok);
639126277Sdes	}
640126277Sdes
641126277Sdes	if (status == GSS_S_COMPLETE) {
642126277Sdes		/* send either complete or MIC, depending on mechanism */
643126277Sdes		if (!(flags & GSS_C_INTEG_FLAG)) {
644126277Sdes			packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
645126277Sdes			packet_send();
646126277Sdes		} else {
647126277Sdes			ssh_gssapi_buildmic(&b, authctxt->server_user,
648126277Sdes			    authctxt->service, "gssapi-with-mic");
649126277Sdes
650126277Sdes			gssbuf.value = buffer_ptr(&b);
651126277Sdes			gssbuf.length = buffer_len(&b);
652126277Sdes
653126277Sdes			status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);
654126277Sdes
655126277Sdes			if (!GSS_ERROR(status)) {
656126277Sdes				packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);
657126277Sdes				packet_put_string(mic.value, mic.length);
658126277Sdes
659126277Sdes				packet_send();
660126277Sdes			}
661126277Sdes
662126277Sdes			buffer_free(&b);
663126277Sdes			gss_release_buffer(&ms, &mic);
664126277Sdes		}
665126277Sdes	}
666126277Sdes
667126277Sdes	return status;
668126277Sdes}
669126277Sdes
670192595Sdes/* ARGSUSED */
671124211Sdesvoid
672124211Sdesinput_gssapi_response(int type, u_int32_t plen, void *ctxt)
673124211Sdes{
674124211Sdes	Authctxt *authctxt = ctxt;
675124211Sdes	Gssctxt *gssctxt;
676124211Sdes	int oidlen;
677124211Sdes	char *oidv;
678124211Sdes
679124211Sdes	if (authctxt == NULL)
680124211Sdes		fatal("input_gssapi_response: no authentication context");
681124211Sdes	gssctxt = authctxt->methoddata;
682124211Sdes
683124211Sdes	/* Setup our OID */
684124211Sdes	oidv = packet_get_string(&oidlen);
685124211Sdes
686126277Sdes	if (oidlen <= 2 ||
687126277Sdes	    oidv[0] != SSH_GSS_OIDTYPE ||
688126277Sdes	    oidv[1] != oidlen - 2) {
689126277Sdes		xfree(oidv);
690126277Sdes		debug("Badly encoded mechanism OID received");
691126277Sdes		userauth(authctxt, NULL);
692126277Sdes		return;
693124211Sdes	}
694124211Sdes
695126277Sdes	if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
696126277Sdes		fatal("Server returned different OID than expected");
697126277Sdes
698124211Sdes	packet_check_eom();
699124211Sdes
700124211Sdes	xfree(oidv);
701124211Sdes
702126277Sdes	if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) {
703124211Sdes		/* Start again with next method on list */
704124211Sdes		debug("Trying to start again");
705124211Sdes		userauth(authctxt, NULL);
706124211Sdes		return;
707124211Sdes	}
708124211Sdes}
709124211Sdes
710192595Sdes/* ARGSUSED */
711124211Sdesvoid
712124211Sdesinput_gssapi_token(int type, u_int32_t plen, void *ctxt)
713124211Sdes{
714124211Sdes	Authctxt *authctxt = ctxt;
715124211Sdes	gss_buffer_desc recv_tok;
716126277Sdes	OM_uint32 status;
717124211Sdes	u_int slen;
718124211Sdes
719124211Sdes	if (authctxt == NULL)
720124211Sdes		fatal("input_gssapi_response: no authentication context");
721124211Sdes
722124211Sdes	recv_tok.value = packet_get_string(&slen);
723124211Sdes	recv_tok.length = slen;	/* safe typecast */
724124211Sdes
725124211Sdes	packet_check_eom();
726124211Sdes
727126277Sdes	status = process_gssapi_token(ctxt, &recv_tok);
728124211Sdes
729124211Sdes	xfree(recv_tok.value);
730124211Sdes
731124211Sdes	if (GSS_ERROR(status)) {
732124211Sdes		/* Start again with the next method in the list */
733124211Sdes		userauth(authctxt, NULL);
734124211Sdes		return;
735124211Sdes	}
736124211Sdes}
737124211Sdes
738192595Sdes/* ARGSUSED */
739124211Sdesvoid
740124211Sdesinput_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
741124211Sdes{
742124211Sdes	Authctxt *authctxt = ctxt;
743124211Sdes	Gssctxt *gssctxt;
744124211Sdes	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
745124211Sdes	gss_buffer_desc recv_tok;
746124211Sdes	OM_uint32 status, ms;
747124211Sdes	u_int len;
748124211Sdes
749124211Sdes	if (authctxt == NULL)
750124211Sdes		fatal("input_gssapi_response: no authentication context");
751124211Sdes	gssctxt = authctxt->methoddata;
752124211Sdes
753124211Sdes	recv_tok.value = packet_get_string(&len);
754124211Sdes	recv_tok.length = len;
755124211Sdes
756124211Sdes	packet_check_eom();
757124211Sdes
758124211Sdes	/* Stick it into GSSAPI and see what it says */
759124211Sdes	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
760149753Sdes	    &recv_tok, &send_tok, NULL);
761124211Sdes
762124211Sdes	xfree(recv_tok.value);
763124211Sdes	gss_release_buffer(&ms, &send_tok);
764124211Sdes
765124211Sdes	/* Server will be returning a failed packet after this one */
766124211Sdes}
767124211Sdes
768192595Sdes/* ARGSUSED */
769124211Sdesvoid
770124211Sdesinput_gssapi_error(int type, u_int32_t plen, void *ctxt)
771124211Sdes{
772124211Sdes	OM_uint32 maj, min;
773124211Sdes	char *msg;
774124211Sdes	char *lang;
775124211Sdes
776124211Sdes	maj=packet_get_int();
777124211Sdes	min=packet_get_int();
778124211Sdes	msg=packet_get_string(NULL);
779124211Sdes	lang=packet_get_string(NULL);
780124211Sdes
781124211Sdes	packet_check_eom();
782124211Sdes
783157019Sdes	debug("Server GSSAPI Error:\n%s", msg);
784124211Sdes	xfree(msg);
785124211Sdes	xfree(lang);
786124211Sdes}
787124211Sdes#endif /* GSSAPI */
788124211Sdes
78960573Skrisint
79069587Sgreenuserauth_none(Authctxt *authctxt)
79160573Skris{
79269587Sgreen	/* initial userauth request */
79369587Sgreen	packet_start(SSH2_MSG_USERAUTH_REQUEST);
79469587Sgreen	packet_put_cstring(authctxt->server_user);
79569587Sgreen	packet_put_cstring(authctxt->service);
79669587Sgreen	packet_put_cstring(authctxt->method->name);
79769587Sgreen	packet_send();
79869587Sgreen	return 1;
79969587Sgreen}
80069587Sgreen
80169587Sgreenint
80269587Sgreenuserauth_passwd(Authctxt *authctxt)
80369587Sgreen{
80460573Skris	static int attempt = 0;
80598684Sdes	char prompt[150];
80660573Skris	char *password;
807204917Sdes	const char *host = options.host_key_alias ?  options.host_key_alias :
808204917Sdes	    authctxt->host;
80960573Skris
81065668Skris	if (attempt++ >= options.number_of_password_prompts)
81160573Skris		return 0;
81260573Skris
81392559Sdes	if (attempt != 1)
81465668Skris		error("Permission denied, please try again.");
81565668Skris
81676262Sgreen	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
817204917Sdes	    authctxt->server_user, host);
81860573Skris	password = read_passphrase(prompt, 0);
81960573Skris	packet_start(SSH2_MSG_USERAUTH_REQUEST);
82069587Sgreen	packet_put_cstring(authctxt->server_user);
82169587Sgreen	packet_put_cstring(authctxt->service);
82269587Sgreen	packet_put_cstring(authctxt->method->name);
82360573Skris	packet_put_char(0);
82493704Sdes	packet_put_cstring(password);
82560573Skris	memset(password, 0, strlen(password));
82660573Skris	xfree(password);
82792559Sdes	packet_add_padding(64);
82860573Skris	packet_send();
82998684Sdes
83098684Sdes	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
83198684Sdes	    &input_userauth_passwd_changereq);
83298684Sdes
83360573Skris	return 1;
83460573Skris}
835192595Sdes
83698684Sdes/*
83798684Sdes * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
83898684Sdes */
839192595Sdes/* ARGSUSED */
84098684Sdesvoid
84198941Sdesinput_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
84298684Sdes{
84398684Sdes	Authctxt *authctxt = ctxt;
84498684Sdes	char *info, *lang, *password = NULL, *retype = NULL;
84598684Sdes	char prompt[150];
846204917Sdes	const char *host = options.host_key_alias ? options.host_key_alias :
847204917Sdes	    authctxt->host;
84860573Skris
84998684Sdes	debug2("input_userauth_passwd_changereq");
85098684Sdes
85198684Sdes	if (authctxt == NULL)
85298684Sdes		fatal("input_userauth_passwd_changereq: "
85398684Sdes		    "no authentication context");
85498684Sdes
85598684Sdes	info = packet_get_string(NULL);
85698684Sdes	lang = packet_get_string(NULL);
85798684Sdes	if (strlen(info) > 0)
858124211Sdes		logit("%s", info);
85998684Sdes	xfree(info);
86098684Sdes	xfree(lang);
86198684Sdes	packet_start(SSH2_MSG_USERAUTH_REQUEST);
86298684Sdes	packet_put_cstring(authctxt->server_user);
86398684Sdes	packet_put_cstring(authctxt->service);
86498684Sdes	packet_put_cstring(authctxt->method->name);
86598684Sdes	packet_put_char(1);			/* additional info */
86698684Sdes	snprintf(prompt, sizeof(prompt),
86798684Sdes	    "Enter %.30s@%.128s's old password: ",
868204917Sdes	    authctxt->server_user, host);
86998684Sdes	password = read_passphrase(prompt, 0);
87098684Sdes	packet_put_cstring(password);
87198684Sdes	memset(password, 0, strlen(password));
87298684Sdes	xfree(password);
87398684Sdes	password = NULL;
87498684Sdes	while (password == NULL) {
87598684Sdes		snprintf(prompt, sizeof(prompt),
87698684Sdes		    "Enter %.30s@%.128s's new password: ",
877204917Sdes		    authctxt->server_user, host);
87898684Sdes		password = read_passphrase(prompt, RP_ALLOW_EOF);
87998684Sdes		if (password == NULL) {
88098684Sdes			/* bail out */
88198684Sdes			return;
88298684Sdes		}
88398684Sdes		snprintf(prompt, sizeof(prompt),
88498684Sdes		    "Retype %.30s@%.128s's new password: ",
885204917Sdes		    authctxt->server_user, host);
88698684Sdes		retype = read_passphrase(prompt, 0);
88798684Sdes		if (strcmp(password, retype) != 0) {
88898684Sdes			memset(password, 0, strlen(password));
88998684Sdes			xfree(password);
890124211Sdes			logit("Mismatch; try again, EOF to quit.");
89198684Sdes			password = NULL;
89298684Sdes		}
89398684Sdes		memset(retype, 0, strlen(retype));
89498684Sdes		xfree(retype);
89598684Sdes	}
89698684Sdes	packet_put_cstring(password);
89798684Sdes	memset(password, 0, strlen(password));
89898684Sdes	xfree(password);
89998684Sdes	packet_add_padding(64);
90098684Sdes	packet_send();
90198684Sdes
90298684Sdes	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
90398684Sdes	    &input_userauth_passwd_changereq);
90498684Sdes}
90598684Sdes
906192595Sdes#ifdef JPAKE
907192595Sdesstatic char *
908192595Sdespw_encrypt(const char *password, const char *crypt_scheme, const char *salt)
909192595Sdes{
910192595Sdes	/* OpenBSD crypt(3) handles all of these */
911192595Sdes	if (strcmp(crypt_scheme, "crypt") == 0 ||
912192595Sdes	    strcmp(crypt_scheme, "bcrypt") == 0 ||
913192595Sdes	    strcmp(crypt_scheme, "md5crypt") == 0 ||
914192595Sdes	    strcmp(crypt_scheme, "crypt-extended") == 0)
915192595Sdes		return xstrdup(crypt(password, salt));
916192595Sdes	error("%s: unsupported password encryption scheme \"%.100s\"",
917192595Sdes	    __func__, crypt_scheme);
918192595Sdes	return NULL;
919192595Sdes}
920192595Sdes
921192595Sdesstatic BIGNUM *
922192595Sdesjpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme,
923192595Sdes    const char *salt)
924192595Sdes{
925192595Sdes	char prompt[256], *password, *crypted;
926192595Sdes	u_char *secret;
927192595Sdes	u_int secret_len;
928192595Sdes	BIGNUM *ret;
929192595Sdes
930192595Sdes	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ",
931192595Sdes	    authctxt->server_user, authctxt->host);
932192595Sdes	password = read_passphrase(prompt, 0);
933192595Sdes
934192595Sdes	if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) {
935192595Sdes		logit("Disabling %s authentication", authctxt->method->name);
936192595Sdes		authctxt->method->enabled = NULL;
937192595Sdes		/* Continue with an empty password to fail gracefully */
938192595Sdes		crypted = xstrdup("");
939192595Sdes	}
940192595Sdes
941192595Sdes#ifdef JPAKE_DEBUG
942192595Sdes	debug3("%s: salt = %s", __func__, salt);
943192595Sdes	debug3("%s: scheme = %s", __func__, crypt_scheme);
944192595Sdes	debug3("%s: crypted = %s", __func__, crypted);
945192595Sdes#endif
946192595Sdes
947192595Sdes	if (hash_buffer(crypted, strlen(crypted), EVP_sha256(),
948192595Sdes	    &secret, &secret_len) != 0)
949192595Sdes		fatal("%s: hash_buffer", __func__);
950192595Sdes
951192595Sdes	bzero(password, strlen(password));
952192595Sdes	bzero(crypted, strlen(crypted));
953192595Sdes	xfree(password);
954192595Sdes	xfree(crypted);
955192595Sdes
956192595Sdes	if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL)
957192595Sdes		fatal("%s: BN_bin2bn (secret)", __func__);
958192595Sdes	bzero(secret, secret_len);
959192595Sdes	xfree(secret);
960192595Sdes
961192595Sdes	return ret;
962192595Sdes}
963192595Sdes
964192595Sdes/* ARGSUSED */
965192595Sdesvoid
966192595Sdesinput_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt)
967192595Sdes{
968192595Sdes	Authctxt *authctxt = ctxt;
969192595Sdes	struct jpake_ctx *pctx = authctxt->methoddata;
970192595Sdes	u_char *x3_proof, *x4_proof, *x2_s_proof;
971192595Sdes	u_int x3_proof_len, x4_proof_len, x2_s_proof_len;
972192595Sdes	char *crypt_scheme, *salt;
973192595Sdes
974192595Sdes	/* Disable this message */
975192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL);
976192595Sdes
977192595Sdes	if ((pctx->g_x3 = BN_new()) == NULL ||
978192595Sdes	    (pctx->g_x4 = BN_new()) == NULL)
979192595Sdes		fatal("%s: BN_new", __func__);
980192595Sdes
981192595Sdes	/* Fetch step 1 values */
982192595Sdes	crypt_scheme = packet_get_string(NULL);
983192595Sdes	salt = packet_get_string(NULL);
984192595Sdes	pctx->server_id = packet_get_string(&pctx->server_id_len);
985192595Sdes	packet_get_bignum2(pctx->g_x3);
986192595Sdes	packet_get_bignum2(pctx->g_x4);
987192595Sdes	x3_proof = packet_get_string(&x3_proof_len);
988192595Sdes	x4_proof = packet_get_string(&x4_proof_len);
989192595Sdes	packet_check_eom();
990192595Sdes
991192595Sdes	JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
992192595Sdes
993192595Sdes	/* Obtain password and derive secret */
994192595Sdes	pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt);
995192595Sdes	bzero(crypt_scheme, strlen(crypt_scheme));
996192595Sdes	bzero(salt, strlen(salt));
997192595Sdes	xfree(crypt_scheme);
998192595Sdes	xfree(salt);
999192595Sdes	JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__));
1000192595Sdes
1001192595Sdes	/* Calculate step 2 values */
1002192595Sdes	jpake_step2(pctx->grp, pctx->s, pctx->g_x1,
1003192595Sdes	    pctx->g_x3, pctx->g_x4, pctx->x2,
1004192595Sdes	    pctx->server_id, pctx->server_id_len,
1005192595Sdes	    pctx->client_id, pctx->client_id_len,
1006192595Sdes	    x3_proof, x3_proof_len,
1007192595Sdes	    x4_proof, x4_proof_len,
1008192595Sdes	    &pctx->a,
1009192595Sdes	    &x2_s_proof, &x2_s_proof_len);
1010192595Sdes
1011192595Sdes	bzero(x3_proof, x3_proof_len);
1012192595Sdes	bzero(x4_proof, x4_proof_len);
1013192595Sdes	xfree(x3_proof);
1014192595Sdes	xfree(x4_proof);
1015192595Sdes
1016192595Sdes	JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
1017192595Sdes
1018192595Sdes	/* Send values for step 2 */
1019192595Sdes	packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2);
1020192595Sdes	packet_put_bignum2(pctx->a);
1021192595Sdes	packet_put_string(x2_s_proof, x2_s_proof_len);
1022192595Sdes	packet_send();
1023192595Sdes
1024192595Sdes	bzero(x2_s_proof, x2_s_proof_len);
1025192595Sdes	xfree(x2_s_proof);
1026192595Sdes
1027192595Sdes	/* Expect step 2 packet from peer */
1028192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2,
1029192595Sdes	    input_userauth_jpake_server_step2);
1030192595Sdes}
1031192595Sdes
1032192595Sdes/* ARGSUSED */
1033192595Sdesvoid
1034192595Sdesinput_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt)
1035192595Sdes{
1036192595Sdes	Authctxt *authctxt = ctxt;
1037192595Sdes	struct jpake_ctx *pctx = authctxt->methoddata;
1038192595Sdes	u_char *x4_s_proof;
1039192595Sdes	u_int x4_s_proof_len;
1040192595Sdes
1041192595Sdes	/* Disable this message */
1042192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL);
1043192595Sdes
1044192595Sdes	if ((pctx->b = BN_new()) == NULL)
1045192595Sdes		fatal("%s: BN_new", __func__);
1046192595Sdes
1047192595Sdes	/* Fetch step 2 values */
1048192595Sdes	packet_get_bignum2(pctx->b);
1049192595Sdes	x4_s_proof = packet_get_string(&x4_s_proof_len);
1050192595Sdes	packet_check_eom();
1051192595Sdes
1052192595Sdes	JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
1053192595Sdes
1054192595Sdes	/* Derive shared key and calculate confirmation hash */
1055192595Sdes	jpake_key_confirm(pctx->grp, pctx->s, pctx->b,
1056192595Sdes	    pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4,
1057192595Sdes	    pctx->client_id, pctx->client_id_len,
1058192595Sdes	    pctx->server_id, pctx->server_id_len,
1059192595Sdes	    session_id2, session_id2_len,
1060192595Sdes	    x4_s_proof, x4_s_proof_len,
1061192595Sdes	    &pctx->k,
1062192595Sdes	    &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len);
1063192595Sdes
1064192595Sdes	bzero(x4_s_proof, x4_s_proof_len);
1065192595Sdes	xfree(x4_s_proof);
1066192595Sdes
1067192595Sdes	JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
1068192595Sdes
1069192595Sdes	/* Send key confirmation proof */
1070192595Sdes	packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM);
1071192595Sdes	packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len);
1072192595Sdes	packet_send();
1073192595Sdes
1074192595Sdes	/* Expect confirmation from peer */
1075192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM,
1076192595Sdes	    input_userauth_jpake_server_confirm);
1077192595Sdes}
1078192595Sdes
1079192595Sdes/* ARGSUSED */
1080192595Sdesvoid
1081192595Sdesinput_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt)
1082192595Sdes{
1083192595Sdes	Authctxt *authctxt = ctxt;
1084192595Sdes	struct jpake_ctx *pctx = authctxt->methoddata;
1085192595Sdes
1086192595Sdes	/* Disable this message */
1087192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL);
1088192595Sdes
1089192595Sdes	pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len);
1090192595Sdes	packet_check_eom();
1091192595Sdes
1092192595Sdes	JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
1093192595Sdes
1094192595Sdes	/* Verify expected confirmation hash */
1095192595Sdes	if (jpake_check_confirm(pctx->k,
1096192595Sdes	    pctx->server_id, pctx->server_id_len,
1097192595Sdes	    session_id2, session_id2_len,
1098192595Sdes	    pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1)
1099192595Sdes		debug("%s: %s success", __func__, authctxt->method->name);
1100192595Sdes	else {
1101192595Sdes		debug("%s: confirmation mismatch", __func__);
1102192595Sdes		/* XXX stash this so if auth succeeds then we can warn/kill */
1103192595Sdes	}
1104192595Sdes
1105192595Sdes	userauth_jpake_cleanup(authctxt);
1106192595Sdes}
1107192595Sdes#endif /* JPAKE */
1108192595Sdes
1109124211Sdesstatic int
1110124211Sdesidentity_sign(Identity *id, u_char **sigp, u_int *lenp,
1111124211Sdes    u_char *data, u_int datalen)
111276262Sgreen{
1113124211Sdes	Key *prv;
1114124211Sdes	int ret;
111598684Sdes
1116124211Sdes	/* the agent supports this key */
1117124211Sdes	if (id->ac)
1118124211Sdes		return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
1119124211Sdes		    data, datalen));
1120124211Sdes	/*
1121124211Sdes	 * we have already loaded the private key or
1122124211Sdes	 * the private key is stored in external hardware
1123124211Sdes	 */
1124124211Sdes	if (id->isprivate || (id->key->flags & KEY_FLAG_EXT))
1125124211Sdes		return (key_sign(id->key, sigp, lenp, data, datalen));
1126124211Sdes	/* load the private key from the file */
1127124211Sdes	if ((prv = load_identity_file(id->filename)) == NULL)
1128124211Sdes		return (-1);
1129124211Sdes	ret = key_sign(prv, sigp, lenp, data, datalen);
1130124211Sdes	key_free(prv);
1131124211Sdes	return (ret);
113276262Sgreen}
113376262Sgreen
113492559Sdesstatic int
1135124211Sdessign_and_send_pubkey(Authctxt *authctxt, Identity *id)
113660573Skris{
113760573Skris	Buffer b;
113876262Sgreen	u_char *blob, *signature;
113992559Sdes	u_int bloblen, slen;
1140124211Sdes	u_int skip = 0;
114165668Skris	int ret = -1;
114269587Sgreen	int have_sig = 1;
1143215116Sdes	char *fp;
114460573Skris
1145215116Sdes	fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
1146215116Sdes	debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
1147215116Sdes	xfree(fp);
114860573Skris
1149124211Sdes	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
115076262Sgreen		/* we cannot handle this key */
115176262Sgreen		debug3("sign_and_send_pubkey: cannot handle key");
115276262Sgreen		return 0;
115376262Sgreen	}
115460573Skris	/* data to be signed */
115560573Skris	buffer_init(&b);
115669587Sgreen	if (datafellows & SSH_OLD_SESSIONID) {
115769587Sgreen		buffer_append(&b, session_id2, session_id2_len);
115876262Sgreen		skip = session_id2_len;
115969587Sgreen	} else {
116065668Skris		buffer_put_string(&b, session_id2, session_id2_len);
116165668Skris		skip = buffer_len(&b);
116265668Skris	}
116360573Skris	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
116469587Sgreen	buffer_put_cstring(&b, authctxt->server_user);
116560573Skris	buffer_put_cstring(&b,
116676262Sgreen	    datafellows & SSH_BUG_PKSERVICE ?
116760573Skris	    "ssh-userauth" :
116869587Sgreen	    authctxt->service);
116976262Sgreen	if (datafellows & SSH_BUG_PKAUTH) {
117076262Sgreen		buffer_put_char(&b, have_sig);
117176262Sgreen	} else {
117276262Sgreen		buffer_put_cstring(&b, authctxt->method->name);
117376262Sgreen		buffer_put_char(&b, have_sig);
1174124211Sdes		buffer_put_cstring(&b, key_ssh_name(id->key));
117576262Sgreen	}
117660573Skris	buffer_put_string(&b, blob, bloblen);
117760573Skris
117860573Skris	/* generate signature */
1179124211Sdes	ret = identity_sign(id, &signature, &slen,
118076262Sgreen	    buffer_ptr(&b), buffer_len(&b));
118165668Skris	if (ret == -1) {
118265668Skris		xfree(blob);
118365668Skris		buffer_free(&b);
118465668Skris		return 0;
118565668Skris	}
118676262Sgreen#ifdef DEBUG_PK
118760573Skris	buffer_dump(&b);
118860573Skris#endif
118976262Sgreen	if (datafellows & SSH_BUG_PKSERVICE) {
119060573Skris		buffer_clear(&b);
119160573Skris		buffer_append(&b, session_id2, session_id2_len);
119276262Sgreen		skip = session_id2_len;
119360573Skris		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
119469587Sgreen		buffer_put_cstring(&b, authctxt->server_user);
119569587Sgreen		buffer_put_cstring(&b, authctxt->service);
119669587Sgreen		buffer_put_cstring(&b, authctxt->method->name);
119769587Sgreen		buffer_put_char(&b, have_sig);
119876262Sgreen		if (!(datafellows & SSH_BUG_PKAUTH))
1199124211Sdes			buffer_put_cstring(&b, key_ssh_name(id->key));
120060573Skris		buffer_put_string(&b, blob, bloblen);
120160573Skris	}
120260573Skris	xfree(blob);
120376262Sgreen
120460573Skris	/* append signature */
120560573Skris	buffer_put_string(&b, signature, slen);
120660573Skris	xfree(signature);
120760573Skris
120860573Skris	/* skip session id and packet type */
120965668Skris	if (buffer_len(&b) < skip + 1)
121069587Sgreen		fatal("userauth_pubkey: internal error");
121165668Skris	buffer_consume(&b, skip + 1);
121260573Skris
121360573Skris	/* put remaining data from buffer into packet */
121460573Skris	packet_start(SSH2_MSG_USERAUTH_REQUEST);
121560573Skris	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
121660573Skris	buffer_free(&b);
121760573Skris	packet_send();
121865668Skris
121960573Skris	return 1;
122060573Skris}
122160573Skris
122292559Sdesstatic int
1223124211Sdessend_pubkey_test(Authctxt *authctxt, Identity *id)
122469587Sgreen{
122576262Sgreen	u_char *blob;
122692559Sdes	u_int bloblen, have_sig = 0;
122776262Sgreen
122876262Sgreen	debug3("send_pubkey_test");
122976262Sgreen
1230124211Sdes	if (key_to_blob(id->key, &blob, &bloblen) == 0) {
123176262Sgreen		/* we cannot handle this key */
123276262Sgreen		debug3("send_pubkey_test: cannot handle key");
123376262Sgreen		return 0;
123476262Sgreen	}
123576262Sgreen	/* register callback for USERAUTH_PK_OK message */
123676262Sgreen	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
123776262Sgreen
123876262Sgreen	packet_start(SSH2_MSG_USERAUTH_REQUEST);
123976262Sgreen	packet_put_cstring(authctxt->server_user);
124076262Sgreen	packet_put_cstring(authctxt->service);
124176262Sgreen	packet_put_cstring(authctxt->method->name);
124276262Sgreen	packet_put_char(have_sig);
124376262Sgreen	if (!(datafellows & SSH_BUG_PKAUTH))
1244124211Sdes		packet_put_cstring(key_ssh_name(id->key));
124576262Sgreen	packet_put_string(blob, bloblen);
124676262Sgreen	xfree(blob);
124776262Sgreen	packet_send();
124876262Sgreen	return 1;
124969587Sgreen}
125069587Sgreen
125192559Sdesstatic Key *
125276262Sgreenload_identity_file(char *filename)
125365668Skris{
125476262Sgreen	Key *private;
125576262Sgreen	char prompt[300], *passphrase;
1256204917Sdes	int perm_ok = 0, quit, i;
125765668Skris	struct stat st;
125865668Skris
125976262Sgreen	if (stat(filename, &st) < 0) {
126076262Sgreen		debug3("no such identity: %s", filename);
126176262Sgreen		return NULL;
126265668Skris	}
1263162856Sdes	private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok);
1264162856Sdes	if (!perm_ok)
1265162856Sdes		return NULL;
126676262Sgreen	if (private == NULL) {
126776262Sgreen		if (options.batch_mode)
126876262Sgreen			return NULL;
126965668Skris		snprintf(prompt, sizeof prompt,
127092559Sdes		    "Enter passphrase for key '%.100s': ", filename);
127169587Sgreen		for (i = 0; i < options.number_of_password_prompts; i++) {
127269587Sgreen			passphrase = read_passphrase(prompt, 0);
127369587Sgreen			if (strcmp(passphrase, "") != 0) {
1274162856Sdes				private = key_load_private_type(KEY_UNSPEC,
1275162856Sdes				    filename, passphrase, NULL, NULL);
127676262Sgreen				quit = 0;
127769587Sgreen			} else {
127869587Sgreen				debug2("no passphrase given, try next key");
127976262Sgreen				quit = 1;
128069587Sgreen			}
128169587Sgreen			memset(passphrase, 0, strlen(passphrase));
128269587Sgreen			xfree(passphrase);
128376262Sgreen			if (private != NULL || quit)
128469587Sgreen				break;
128569587Sgreen			debug2("bad passphrase given, try again...");
128669587Sgreen		}
128765668Skris	}
128876262Sgreen	return private;
128976262Sgreen}
129076262Sgreen
1291124211Sdes/*
1292124211Sdes * try keys in the following order:
1293124211Sdes *	1. agent keys that are found in the config file
1294124211Sdes *	2. other agent keys
1295124211Sdes *	3. keys that are only listed in the config file
1296124211Sdes */
1297124211Sdesstatic void
1298124211Sdespubkey_prepare(Authctxt *authctxt)
129976262Sgreen{
1300124211Sdes	Identity *id;
1301124211Sdes	Idlist agent, files, *preferred;
1302124211Sdes	Key *key;
1303124211Sdes	AuthenticationConnection *ac;
1304124211Sdes	char *comment;
1305124211Sdes	int i, found;
130676262Sgreen
1307124211Sdes	TAILQ_INIT(&agent);	/* keys from the agent */
1308124211Sdes	TAILQ_INIT(&files);	/* keys from the config file */
1309124211Sdes	preferred = &authctxt->keys;
1310124211Sdes	TAILQ_INIT(preferred);	/* preferred order of keys */
131192559Sdes
1312124211Sdes	/* list of keys stored in the filesystem */
1313124211Sdes	for (i = 0; i < options.num_identity_files; i++) {
1314124211Sdes		key = options.identity_keys[i];
1315124211Sdes		if (key && key->type == KEY_RSA1)
1316124211Sdes			continue;
1317204917Sdes		if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER)
1318204917Sdes			continue;
1319124211Sdes		options.identity_keys[i] = NULL;
1320162856Sdes		id = xcalloc(1, sizeof(*id));
1321124211Sdes		id->key = key;
1322124211Sdes		id->filename = xstrdup(options.identity_files[i]);
1323124211Sdes		TAILQ_INSERT_TAIL(&files, id, next);
1324124211Sdes	}
1325124211Sdes	/* list of keys supported by the agent */
1326124211Sdes	if ((ac = ssh_get_authentication_connection())) {
1327124211Sdes		for (key = ssh_get_first_identity(ac, &comment, 2);
1328124211Sdes		    key != NULL;
1329124211Sdes		    key = ssh_get_next_identity(ac, &comment, 2)) {
1330124211Sdes			found = 0;
1331124211Sdes			TAILQ_FOREACH(id, &files, next) {
1332126277Sdes				/* agent keys from the config file are preferred */
1333124211Sdes				if (key_equal(key, id->key)) {
1334124211Sdes					key_free(key);
1335124211Sdes					xfree(comment);
1336124211Sdes					TAILQ_REMOVE(&files, id, next);
1337124211Sdes					TAILQ_INSERT_TAIL(preferred, id, next);
1338124211Sdes					id->ac = ac;
1339124211Sdes					found = 1;
1340124211Sdes					break;
1341124211Sdes				}
1342124211Sdes			}
1343128460Sdes			if (!found && !options.identities_only) {
1344162856Sdes				id = xcalloc(1, sizeof(*id));
1345124211Sdes				id->key = key;
1346124211Sdes				id->filename = comment;
1347124211Sdes				id->ac = ac;
1348124211Sdes				TAILQ_INSERT_TAIL(&agent, id, next);
1349124211Sdes			}
1350124211Sdes		}
1351124211Sdes		/* append remaining agent keys */
1352124211Sdes		for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
1353124211Sdes			TAILQ_REMOVE(&agent, id, next);
1354124211Sdes			TAILQ_INSERT_TAIL(preferred, id, next);
1355124211Sdes		}
1356124211Sdes		authctxt->agent = ac;
1357124211Sdes	}
1358124211Sdes	/* append remaining keys from the config file */
1359124211Sdes	for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
1360124211Sdes		TAILQ_REMOVE(&files, id, next);
1361124211Sdes		TAILQ_INSERT_TAIL(preferred, id, next);
1362124211Sdes	}
1363124211Sdes	TAILQ_FOREACH(id, preferred, next) {
1364124211Sdes		debug2("key: %s (%p)", id->filename, id->key);
1365124211Sdes	}
136665668Skris}
136765668Skris
1368124211Sdesstatic void
1369124211Sdespubkey_cleanup(Authctxt *authctxt)
137065668Skris{
1371124211Sdes	Identity *id;
137265668Skris
1373124211Sdes	if (authctxt->agent != NULL)
1374124211Sdes		ssh_close_authentication_connection(authctxt->agent);
1375124211Sdes	for (id = TAILQ_FIRST(&authctxt->keys); id;
1376124211Sdes	    id = TAILQ_FIRST(&authctxt->keys)) {
1377124211Sdes		TAILQ_REMOVE(&authctxt->keys, id, next);
1378124211Sdes		if (id->key)
1379124211Sdes			key_free(id->key);
1380124211Sdes		if (id->filename)
1381124211Sdes			xfree(id->filename);
1382124211Sdes		xfree(id);
138365668Skris	}
138465668Skris}
138565668Skris
138669587Sgreenint
138769587Sgreenuserauth_pubkey(Authctxt *authctxt)
138869587Sgreen{
1389124211Sdes	Identity *id;
139069587Sgreen	int sent = 0;
139169587Sgreen
1392124211Sdes	while ((id = TAILQ_FIRST(&authctxt->keys))) {
1393124211Sdes		if (id->tried++)
1394124211Sdes			return (0);
1395126277Sdes		/* move key to the end of the queue */
1396124211Sdes		TAILQ_REMOVE(&authctxt->keys, id, next);
1397124211Sdes		TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
1398124211Sdes		/*
1399124211Sdes		 * send a test message if we have the public key. for
1400124211Sdes		 * encrypted keys we cannot do this and have to load the
1401124211Sdes		 * private key instead
1402124211Sdes		 */
1403124211Sdes		if (id->key && id->key->type != KEY_RSA1) {
1404215116Sdes			debug("Offering %s public key: %s", key_type(id->key),
1405215116Sdes			    id->filename);
1406124211Sdes			sent = send_pubkey_test(authctxt, id);
1407124211Sdes		} else if (id->key == NULL) {
1408124211Sdes			debug("Trying private key: %s", id->filename);
1409124211Sdes			id->key = load_identity_file(id->filename);
1410124211Sdes			if (id->key != NULL) {
1411124211Sdes				id->isprivate = 1;
1412124211Sdes				sent = sign_and_send_pubkey(authctxt, id);
1413124211Sdes				key_free(id->key);
1414124211Sdes				id->key = NULL;
141576262Sgreen			}
141676262Sgreen		}
1417124211Sdes		if (sent)
1418124211Sdes			return (sent);
141976262Sgreen	}
1420124211Sdes	return (0);
142169587Sgreen}
142269587Sgreen
142369587Sgreen/*
142469587Sgreen * Send userauth request message specifying keyboard-interactive method.
142569587Sgreen */
142669587Sgreenint
142769587Sgreenuserauth_kbdint(Authctxt *authctxt)
142869587Sgreen{
142969587Sgreen	static int attempt = 0;
143069587Sgreen
143169587Sgreen	if (attempt++ >= options.number_of_password_prompts)
143269587Sgreen		return 0;
143392559Sdes	/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
143492559Sdes	if (attempt > 1 && !authctxt->info_req_seen) {
143592559Sdes		debug3("userauth_kbdint: disable: no info_req_seen");
143692559Sdes		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
143792559Sdes		return 0;
143892559Sdes	}
143969587Sgreen
144069587Sgreen	debug2("userauth_kbdint");
144169587Sgreen	packet_start(SSH2_MSG_USERAUTH_REQUEST);
144269587Sgreen	packet_put_cstring(authctxt->server_user);
144369587Sgreen	packet_put_cstring(authctxt->service);
144469587Sgreen	packet_put_cstring(authctxt->method->name);
144569587Sgreen	packet_put_cstring("");					/* lang */
144669587Sgreen	packet_put_cstring(options.kbd_interactive_devices ?
144769587Sgreen	    options.kbd_interactive_devices : "");
144869587Sgreen	packet_send();
144969587Sgreen
145069587Sgreen	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
145169587Sgreen	return 1;
145269587Sgreen}
145369587Sgreen
145469587Sgreen/*
145576262Sgreen * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
145669587Sgreen */
145760573Skrisvoid
145892559Sdesinput_userauth_info_req(int type, u_int32_t seq, void *ctxt)
145960573Skris{
146069587Sgreen	Authctxt *authctxt = ctxt;
146176262Sgreen	char *name, *inst, *lang, *prompt, *response;
146276262Sgreen	u_int num_prompts, i;
146369587Sgreen	int echo = 0;
146460573Skris
146569587Sgreen	debug2("input_userauth_info_req");
146669587Sgreen
146769587Sgreen	if (authctxt == NULL)
146869587Sgreen		fatal("input_userauth_info_req: no authentication context");
146969587Sgreen
147092559Sdes	authctxt->info_req_seen = 1;
147192559Sdes
147269587Sgreen	name = packet_get_string(NULL);
147369587Sgreen	inst = packet_get_string(NULL);
147469587Sgreen	lang = packet_get_string(NULL);
147569587Sgreen	if (strlen(name) > 0)
1476124211Sdes		logit("%s", name);
147769587Sgreen	if (strlen(inst) > 0)
1478124211Sdes		logit("%s", inst);
147976262Sgreen	xfree(name);
148069587Sgreen	xfree(inst);
148176262Sgreen	xfree(lang);
148269587Sgreen
148369587Sgreen	num_prompts = packet_get_int();
148469587Sgreen	/*
148569587Sgreen	 * Begin to build info response packet based on prompts requested.
148669587Sgreen	 * We commit to providing the correct number of responses, so if
148769587Sgreen	 * further on we run into a problem that prevents this, we have to
148869587Sgreen	 * be sure and clean this up and send a correct error response.
148969587Sgreen	 */
149069587Sgreen	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
149169587Sgreen	packet_put_int(num_prompts);
149269587Sgreen
149392559Sdes	debug2("input_userauth_info_req: num_prompts %d", num_prompts);
149469587Sgreen	for (i = 0; i < num_prompts; i++) {
149569587Sgreen		prompt = packet_get_string(NULL);
149669587Sgreen		echo = packet_get_char();
149769587Sgreen
149892559Sdes		response = read_passphrase(prompt, echo ? RP_ECHO : 0);
149969587Sgreen
150093704Sdes		packet_put_cstring(response);
150169587Sgreen		memset(response, 0, strlen(response));
150269587Sgreen		xfree(response);
150369587Sgreen		xfree(prompt);
150469587Sgreen	}
150592559Sdes	packet_check_eom(); /* done with parsing incoming message. */
150669587Sgreen
150792559Sdes	packet_add_padding(64);
150860573Skris	packet_send();
150969587Sgreen}
151060573Skris
151198684Sdesstatic int
151299063Sdesssh_keysign(Key *key, u_char **sigp, u_int *lenp,
151398684Sdes    u_char *data, u_int datalen)
151498684Sdes{
151598684Sdes	Buffer b;
151698684Sdes	struct stat st;
151798684Sdes	pid_t pid;
151898684Sdes	int to[2], from[2], status, version = 2;
151998684Sdes
1520113911Sdes	debug2("ssh_keysign called");
152198684Sdes
152298684Sdes	if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1523204917Sdes		error("ssh_keysign: not installed: %s", strerror(errno));
152498684Sdes		return -1;
152598684Sdes	}
152698684Sdes	if (fflush(stdout) != 0)
152798684Sdes		error("ssh_keysign: fflush: %s", strerror(errno));
152898684Sdes	if (pipe(to) < 0) {
152998684Sdes		error("ssh_keysign: pipe: %s", strerror(errno));
153098684Sdes		return -1;
153198684Sdes	}
153298684Sdes	if (pipe(from) < 0) {
153398684Sdes		error("ssh_keysign: pipe: %s", strerror(errno));
153498684Sdes		return -1;
153598684Sdes	}
153698684Sdes	if ((pid = fork()) < 0) {
153798684Sdes		error("ssh_keysign: fork: %s", strerror(errno));
153898684Sdes		return -1;
153998684Sdes	}
154098684Sdes	if (pid == 0) {
1541204917Sdes		/* keep the socket on exec */
1542204917Sdes		fcntl(packet_get_connection_in(), F_SETFD, 0);
1543162856Sdes		permanently_drop_suid(getuid());
154498684Sdes		close(from[0]);
154598684Sdes		if (dup2(from[1], STDOUT_FILENO) < 0)
154698684Sdes			fatal("ssh_keysign: dup2: %s", strerror(errno));
154798684Sdes		close(to[1]);
154898684Sdes		if (dup2(to[0], STDIN_FILENO) < 0)
154998684Sdes			fatal("ssh_keysign: dup2: %s", strerror(errno));
155098684Sdes		close(from[1]);
155198684Sdes		close(to[0]);
155298684Sdes		execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
155398684Sdes		fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
155498684Sdes		    strerror(errno));
155598684Sdes	}
155698684Sdes	close(from[1]);
155798684Sdes	close(to[0]);
155898684Sdes
155998684Sdes	buffer_init(&b);
156098684Sdes	buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
156198684Sdes	buffer_put_string(&b, data, datalen);
1562126277Sdes	if (ssh_msg_send(to[1], version, &b) == -1)
1563126277Sdes		fatal("ssh_keysign: couldn't send request");
156498684Sdes
1565106130Sdes	if (ssh_msg_recv(from[0], &b) < 0) {
156698684Sdes		error("ssh_keysign: no reply");
1567126277Sdes		buffer_free(&b);
156898684Sdes		return -1;
156998684Sdes	}
157098684Sdes	close(from[0]);
157198684Sdes	close(to[1]);
157298684Sdes
157398684Sdes	while (waitpid(pid, &status, 0) < 0)
157498684Sdes		if (errno != EINTR)
157598684Sdes			break;
157698684Sdes
157798684Sdes	if (buffer_get_char(&b) != version) {
157898684Sdes		error("ssh_keysign: bad version");
1579126277Sdes		buffer_free(&b);
158098684Sdes		return -1;
158198684Sdes	}
158298684Sdes	*sigp = buffer_get_string(&b, lenp);
1583126277Sdes	buffer_free(&b);
158498684Sdes
158598684Sdes	return 0;
158698684Sdes}
158798684Sdes
158876262Sgreenint
158976262Sgreenuserauth_hostbased(Authctxt *authctxt)
159069587Sgreen{
159176262Sgreen	Key *private = NULL;
159298684Sdes	Sensitive *sensitive = authctxt->sensitive;
159376262Sgreen	Buffer b;
159476262Sgreen	u_char *signature, *blob;
1595204917Sdes	char *chost, *pkalg, *p;
159676262Sgreen	const char *service;
159776262Sgreen	u_int blen, slen;
1598204917Sdes	int ok, i, found = 0;
159976262Sgreen
160076262Sgreen	/* check for a useful key */
160198684Sdes	for (i = 0; i < sensitive->nkeys; i++) {
160298684Sdes		private = sensitive->keys[i];
160376262Sgreen		if (private && private->type != KEY_RSA1) {
160476262Sgreen			found = 1;
160576262Sgreen			/* we take and free the key */
160698684Sdes			sensitive->keys[i] = NULL;
160776262Sgreen			break;
160876262Sgreen		}
160969587Sgreen	}
161076262Sgreen	if (!found) {
1611113911Sdes		debug("No more client hostkeys for hostbased authentication.");
161276262Sgreen		return 0;
161369587Sgreen	}
161476262Sgreen	if (key_to_blob(private, &blob, &blen) == 0) {
161576262Sgreen		key_free(private);
161676262Sgreen		return 0;
161776262Sgreen	}
161892559Sdes	/* figure out a name for the client host */
1619204917Sdes	p = get_local_name(packet_get_connection_in());
162092559Sdes	if (p == NULL) {
162192559Sdes		error("userauth_hostbased: cannot get local ipaddr/name");
162292559Sdes		key_free(private);
1623162856Sdes		xfree(blob);
162492559Sdes		return 0;
162592559Sdes	}
1626162856Sdes	xasprintf(&chost, "%s.", p);
162792559Sdes	debug2("userauth_hostbased: chost %s", chost);
1628113911Sdes	xfree(p);
162992559Sdes
163076262Sgreen	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
163176262Sgreen	    authctxt->service;
163276262Sgreen	pkalg = xstrdup(key_ssh_name(private));
163376262Sgreen	buffer_init(&b);
163476262Sgreen	/* construct data */
163576262Sgreen	buffer_put_string(&b, session_id2, session_id2_len);
163676262Sgreen	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
163776262Sgreen	buffer_put_cstring(&b, authctxt->server_user);
163876262Sgreen	buffer_put_cstring(&b, service);
163976262Sgreen	buffer_put_cstring(&b, authctxt->method->name);
164076262Sgreen	buffer_put_cstring(&b, pkalg);
164176262Sgreen	buffer_put_string(&b, blob, blen);
164276262Sgreen	buffer_put_cstring(&b, chost);
164376262Sgreen	buffer_put_cstring(&b, authctxt->local_user);
164476262Sgreen#ifdef DEBUG_PK
164576262Sgreen	buffer_dump(&b);
164676262Sgreen#endif
164798684Sdes	if (sensitive->external_keysign)
164898684Sdes		ok = ssh_keysign(private, &signature, &slen,
164998684Sdes		    buffer_ptr(&b), buffer_len(&b));
165098684Sdes	else
165198684Sdes		ok = key_sign(private, &signature, &slen,
165298684Sdes		    buffer_ptr(&b), buffer_len(&b));
165376262Sgreen	key_free(private);
165476262Sgreen	buffer_free(&b);
165576262Sgreen	if (ok != 0) {
165676262Sgreen		error("key_sign failed");
165776262Sgreen		xfree(chost);
165876262Sgreen		xfree(pkalg);
1659162856Sdes		xfree(blob);
166076262Sgreen		return 0;
166176262Sgreen	}
166276262Sgreen	packet_start(SSH2_MSG_USERAUTH_REQUEST);
166376262Sgreen	packet_put_cstring(authctxt->server_user);
166476262Sgreen	packet_put_cstring(authctxt->service);
166576262Sgreen	packet_put_cstring(authctxt->method->name);
166676262Sgreen	packet_put_cstring(pkalg);
166776262Sgreen	packet_put_string(blob, blen);
166876262Sgreen	packet_put_cstring(chost);
166976262Sgreen	packet_put_cstring(authctxt->local_user);
167076262Sgreen	packet_put_string(signature, slen);
167176262Sgreen	memset(signature, 's', slen);
167276262Sgreen	xfree(signature);
167376262Sgreen	xfree(chost);
167476262Sgreen	xfree(pkalg);
1675162856Sdes	xfree(blob);
167676262Sgreen
167776262Sgreen	packet_send();
167876262Sgreen	return 1;
167969587Sgreen}
168069587Sgreen
1681192595Sdes#ifdef JPAKE
1682192595Sdesint
1683192595Sdesuserauth_jpake(Authctxt *authctxt)
1684192595Sdes{
1685192595Sdes	struct jpake_ctx *pctx;
1686192595Sdes	u_char *x1_proof, *x2_proof;
1687192595Sdes	u_int x1_proof_len, x2_proof_len;
1688192595Sdes	static int attempt = 0; /* XXX share with userauth_password's? */
1689192595Sdes
1690192595Sdes	if (attempt++ >= options.number_of_password_prompts)
1691192595Sdes		return 0;
1692192595Sdes	if (attempt != 1)
1693192595Sdes		error("Permission denied, please try again.");
1694192595Sdes
1695192595Sdes	if (authctxt->methoddata != NULL)
1696192595Sdes		fatal("%s: authctxt->methoddata already set (%p)",
1697192595Sdes		    __func__, authctxt->methoddata);
1698192595Sdes
1699192595Sdes	authctxt->methoddata = pctx = jpake_new();
1700192595Sdes
1701192595Sdes	/*
1702192595Sdes	 * Send request immediately, to get the protocol going while
1703192595Sdes	 * we do the initial computations.
1704192595Sdes	 */
1705192595Sdes	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1706192595Sdes	packet_put_cstring(authctxt->server_user);
1707192595Sdes	packet_put_cstring(authctxt->service);
1708192595Sdes	packet_put_cstring(authctxt->method->name);
1709192595Sdes	packet_send();
1710192595Sdes	packet_write_wait();
1711192595Sdes
1712192595Sdes	jpake_step1(pctx->grp,
1713192595Sdes	    &pctx->client_id, &pctx->client_id_len,
1714192595Sdes	    &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2,
1715192595Sdes	    &x1_proof, &x1_proof_len,
1716192595Sdes	    &x2_proof, &x2_proof_len);
1717192595Sdes
1718192595Sdes	JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
1719192595Sdes
1720192595Sdes	packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1);
1721192595Sdes	packet_put_string(pctx->client_id, pctx->client_id_len);
1722192595Sdes	packet_put_bignum2(pctx->g_x1);
1723192595Sdes	packet_put_bignum2(pctx->g_x2);
1724192595Sdes	packet_put_string(x1_proof, x1_proof_len);
1725192595Sdes	packet_put_string(x2_proof, x2_proof_len);
1726192595Sdes	packet_send();
1727192595Sdes
1728192595Sdes	bzero(x1_proof, x1_proof_len);
1729192595Sdes	bzero(x2_proof, x2_proof_len);
1730192595Sdes	xfree(x1_proof);
1731192595Sdes	xfree(x2_proof);
1732192595Sdes
1733192595Sdes	/* Expect step 1 packet from peer */
1734192595Sdes	dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1,
1735192595Sdes	    input_userauth_jpake_server_step1);
1736204917Sdes	dispatch_set(SSH2_MSG_USERAUTH_SUCCESS,
1737204917Sdes	    &input_userauth_success_unexpected);
1738192595Sdes
1739192595Sdes	return 1;
1740192595Sdes}
1741192595Sdes
1742192595Sdesvoid
1743192595Sdesuserauth_jpake_cleanup(Authctxt *authctxt)
1744192595Sdes{
1745192595Sdes	debug3("%s: clean up", __func__);
1746192595Sdes	if (authctxt->methoddata != NULL) {
1747192595Sdes		jpake_free(authctxt->methoddata);
1748192595Sdes		authctxt->methoddata = NULL;
1749192595Sdes	}
1750204917Sdes	dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
1751192595Sdes}
1752192595Sdes#endif /* JPAKE */
1753192595Sdes
175476262Sgreen/* find auth method */
175576262Sgreen
175669587Sgreen/*
175769587Sgreen * given auth method name, if configurable options permit this method fill
175869587Sgreen * in auth_ident field and return true, otherwise return false.
175969587Sgreen */
176092559Sdesstatic int
176169587Sgreenauthmethod_is_enabled(Authmethod *method)
176269587Sgreen{
176369587Sgreen	if (method == NULL)
176469587Sgreen		return 0;
176569587Sgreen	/* return false if options indicate this method is disabled */
176669587Sgreen	if  (method->enabled == NULL || *method->enabled == 0)
176769587Sgreen		return 0;
176869587Sgreen	/* return false if batch mode is enabled but method needs interactive mode */
176969587Sgreen	if  (method->batch_flag != NULL && *method->batch_flag != 0)
177069587Sgreen		return 0;
177169587Sgreen	return 1;
177269587Sgreen}
177369587Sgreen
177492559Sdesstatic Authmethod *
177569587Sgreenauthmethod_lookup(const char *name)
177669587Sgreen{
177769587Sgreen	Authmethod *method = NULL;
177869587Sgreen	if (name != NULL)
177969587Sgreen		for (method = authmethods; method->name != NULL; method++)
178069587Sgreen			if (strcmp(name, method->name) == 0)
178169587Sgreen				return method;
178269587Sgreen	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
178369587Sgreen	return NULL;
178469587Sgreen}
178569587Sgreen
178676262Sgreen/* XXX internal state */
178776262Sgreenstatic Authmethod *current = NULL;
178876262Sgreenstatic char *supported = NULL;
178976262Sgreenstatic char *preferred = NULL;
179099063Sdes
179169587Sgreen/*
179269587Sgreen * Given the authentication method list sent by the server, return the
179369587Sgreen * next method we should try.  If the server initially sends a nil list,
179476262Sgreen * use a built-in default list.
179576262Sgreen */
179692559Sdesstatic Authmethod *
179769587Sgreenauthmethod_get(char *authlist)
179869587Sgreen{
179976262Sgreen	char *name = NULL;
180092559Sdes	u_int next;
180176262Sgreen
180269587Sgreen	/* Use a suitable default if we're passed a nil list.  */
180369587Sgreen	if (authlist == NULL || strlen(authlist) == 0)
180476262Sgreen		authlist = options.preferred_authentications;
180569587Sgreen
180676262Sgreen	if (supported == NULL || strcmp(authlist, supported) != 0) {
180776262Sgreen		debug3("start over, passed a different list %s", authlist);
180876262Sgreen		if (supported != NULL)
180976262Sgreen			xfree(supported);
181076262Sgreen		supported = xstrdup(authlist);
181176262Sgreen		preferred = options.preferred_authentications;
181276262Sgreen		debug3("preferred %s", preferred);
181376262Sgreen		current = NULL;
181476262Sgreen	} else if (current != NULL && authmethod_is_enabled(current))
181576262Sgreen		return current;
181660573Skris
181776262Sgreen	for (;;) {
181876262Sgreen		if ((name = match_list(preferred, supported, &next)) == NULL) {
1819113911Sdes			debug("No more authentication methods to try.");
182076262Sgreen			current = NULL;
182176262Sgreen			return NULL;
182276262Sgreen		}
182376262Sgreen		preferred += next;
182469587Sgreen		debug3("authmethod_lookup %s", name);
182576262Sgreen		debug3("remaining preferred: %s", preferred);
182676262Sgreen		if ((current = authmethod_lookup(name)) != NULL &&
182776262Sgreen		    authmethod_is_enabled(current)) {
182869587Sgreen			debug3("authmethod_is_enabled %s", name);
1829113911Sdes			debug("Next authentication method: %s", name);
183076262Sgreen			return current;
183160573Skris		}
183260573Skris	}
183376262Sgreen}
183469587Sgreen
183592559Sdesstatic char *
183676262Sgreenauthmethods_get(void)
183776262Sgreen{
183876262Sgreen	Authmethod *method = NULL;
183992559Sdes	Buffer b;
184092559Sdes	char *list;
184169587Sgreen
184292559Sdes	buffer_init(&b);
184376262Sgreen	for (method = authmethods; method->name != NULL; method++) {
184476262Sgreen		if (authmethod_is_enabled(method)) {
184592559Sdes			if (buffer_len(&b) > 0)
184692559Sdes				buffer_append(&b, ",", 1);
184792559Sdes			buffer_append(&b, method->name, strlen(method->name));
184876262Sgreen		}
184976262Sgreen	}
185092559Sdes	buffer_append(&b, "\0", 1);
185192559Sdes	list = xstrdup(buffer_ptr(&b));
185292559Sdes	buffer_free(&b);
185392559Sdes	return list;
185460573Skris}
1855192595Sdes
1856