sshconnect2.c revision 99063
1170754Sdelphij/*
2170754Sdelphij * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3170754Sdelphij *
4170754Sdelphij * Redistribution and use in source and binary forms, with or without
5170754Sdelphij * modification, are permitted provided that the following conditions
6170754Sdelphij * are met:
7170754Sdelphij * 1. Redistributions of source code must retain the above copyright
8170754Sdelphij *    notice, this list of conditions and the following disclaimer.
9170754Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
10170754Sdelphij *    notice, this list of conditions and the following disclaimer in the
11170754Sdelphij *    documentation and/or other materials provided with the distribution.
12170754Sdelphij *
13170754Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14170754Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15170754Sdelphij * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16170754Sdelphij * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17170754Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18170754Sdelphij * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19170754Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20170754Sdelphij * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21170754Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22170754Sdelphij * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23170754Sdelphij */
24170754Sdelphij
25170754Sdelphij#include "includes.h"
26170754SdelphijRCSID("$OpenBSD: sshconnect2.c,v 1.105 2002/06/23 03:30:17 deraadt Exp $");
27170754SdelphijRCSID("$FreeBSD: head/crypto/openssh/sshconnect2.c 99063 2002-06-29 11:48:59Z des $");
28170754Sdelphij
29170754Sdelphij#include "ssh.h"
30170754Sdelphij#include "ssh2.h"
31170754Sdelphij#include "xmalloc.h"
32170754Sdelphij#include "buffer.h"
33170754Sdelphij#include "packet.h"
34170754Sdelphij#include "compat.h"
35170754Sdelphij#include "bufaux.h"
36170754Sdelphij#include "cipher.h"
37170754Sdelphij#include "kex.h"
38170754Sdelphij#include "myproposal.h"
39170754Sdelphij#include "sshconnect.h"
40170754Sdelphij#include "authfile.h"
41170754Sdelphij#include "dh.h"
42170754Sdelphij#include "authfd.h"
43170754Sdelphij#include "log.h"
44170754Sdelphij#include "readconf.h"
45170754Sdelphij#include "readpass.h"
46170754Sdelphij#include "match.h"
47170754Sdelphij#include "dispatch.h"
48170754Sdelphij#include "canohost.h"
49170754Sdelphij#include "msg.h"
50170754Sdelphij#include "pathnames.h"
51170754Sdelphij
52170754Sdelphij/* import */
53170754Sdelphijextern char *client_version_string;
54170754Sdelphijextern char *server_version_string;
55170754Sdelphijextern Options options;
56170754Sdelphij
57170754Sdelphij/*
58170754Sdelphij * SSH2 key exchange
59170754Sdelphij */
60170754Sdelphij
61170754Sdelphiju_char *session_id2 = NULL;
62170754Sdelphijint session_id2_len = 0;
63170754Sdelphij
64170754Sdelphijchar *xxx_host;
65170754Sdelphijstruct sockaddr *xxx_hostaddr;
66170754Sdelphij
67170754SdelphijKex *xxx_kex = NULL;
68170754Sdelphij
69170754Sdelphijstatic int
70170754Sdelphijverify_host_key_callback(Key *hostkey)
71170754Sdelphij{
72170754Sdelphij	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
73170754Sdelphij		fatal("Host key verification failed.");
74170754Sdelphij	return 0;
75170754Sdelphij}
76170754Sdelphij
77170754Sdelphijvoid
78170754Sdelphijssh_kex2(char *host, struct sockaddr *hostaddr)
79170754Sdelphij{
80170754Sdelphij	Kex *kex;
81170754Sdelphij
82170754Sdelphij	xxx_host = host;
83170754Sdelphij	xxx_hostaddr = hostaddr;
84170754Sdelphij
85170754Sdelphij	if (options.ciphers == (char *)-1) {
86170754Sdelphij		log("No valid ciphers for protocol version 2 given, using defaults.");
87170754Sdelphij		options.ciphers = NULL;
88170754Sdelphij	}
89170754Sdelphij	if (options.ciphers != NULL) {
90170754Sdelphij		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
91170754Sdelphij		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
92170754Sdelphij	}
93170754Sdelphij	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
94170754Sdelphij	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
95170754Sdelphij	myproposal[PROPOSAL_ENC_ALGS_STOC] =
96170754Sdelphij	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
97170754Sdelphij	if (options.compression) {
98170754Sdelphij		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
99170754Sdelphij		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
100170754Sdelphij	} else {
101170754Sdelphij		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
102170754Sdelphij		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
103170754Sdelphij	}
104170754Sdelphij	if (options.macs != NULL) {
105170754Sdelphij		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
106170754Sdelphij		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
107170754Sdelphij	}
108170754Sdelphij	if (options.hostkeyalgorithms != NULL)
109170754Sdelphij		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
110170754Sdelphij		    options.hostkeyalgorithms;
111170754Sdelphij
112170754Sdelphij	/* start key exchange */
113170754Sdelphij	kex = kex_setup(myproposal);
114170754Sdelphij	kex->client_version_string=client_version_string;
115170754Sdelphij	kex->server_version_string=server_version_string;
116170754Sdelphij	kex->verify_host_key=&verify_host_key_callback;
117170754Sdelphij
118170754Sdelphij	xxx_kex = kex;
119170754Sdelphij
120170754Sdelphij	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
121170754Sdelphij
122170754Sdelphij	session_id2 = kex->session_id;
123170754Sdelphij	session_id2_len = kex->session_id_len;
124170754Sdelphij
125170754Sdelphij#ifdef DEBUG_KEXDH
126170754Sdelphij	/* send 1st encrypted/maced/compressed message */
127170754Sdelphij	packet_start(SSH2_MSG_IGNORE);
128170754Sdelphij	packet_put_cstring("markus");
129170754Sdelphij	packet_send();
130170754Sdelphij	packet_write_wait();
131170754Sdelphij#endif
132170754Sdelphij	debug("done: ssh_kex2.");
133170754Sdelphij}
134170754Sdelphij
135170754Sdelphij/*
136170754Sdelphij * Authenticate user
137170754Sdelphij */
138170754Sdelphij
139170754Sdelphijtypedef struct Authctxt Authctxt;
140170754Sdelphijtypedef struct Authmethod Authmethod;
141170754Sdelphij
142170754Sdelphijtypedef int sign_cb_fn(
143170754Sdelphij    Authctxt *authctxt, Key *key,
144170754Sdelphij    u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
145170754Sdelphij
146170754Sdelphijstruct Authctxt {
147170754Sdelphij	const char *server_user;
148170754Sdelphij	const char *local_user;
149170754Sdelphij	const char *host;
150170754Sdelphij	const char *service;
151170754Sdelphij	Authmethod *method;
152170754Sdelphij	int success;
153170754Sdelphij	char *authlist;
154170754Sdelphij	/* pubkey */
155170754Sdelphij	Key *last_key;
156170754Sdelphij	sign_cb_fn *last_key_sign;
157170754Sdelphij	int last_key_hint;
158170754Sdelphij	AuthenticationConnection *agent;
159170754Sdelphij	/* hostbased */
160170754Sdelphij	Sensitive *sensitive;
161170754Sdelphij	/* kbd-interactive */
162170754Sdelphij	int info_req_seen;
163170754Sdelphij};
164170754Sdelphijstruct Authmethod {
165170754Sdelphij	char	*name;		/* string to compare against server's list */
166170754Sdelphij	int	(*userauth)(Authctxt *authctxt);
167170754Sdelphij	int	*enabled;	/* flag in option struct that enables method */
168170754Sdelphij	int	*batch_flag;	/* flag in option struct that disables method */
169170754Sdelphij};
170170754Sdelphij
171170754Sdelphijvoid	input_userauth_success(int, u_int32_t, void *);
172170754Sdelphijvoid	input_userauth_failure(int, u_int32_t, void *);
173170754Sdelphijvoid	input_userauth_banner(int, u_int32_t, void *);
174170754Sdelphijvoid	input_userauth_error(int, u_int32_t, void *);
175170754Sdelphijvoid	input_userauth_info_req(int, u_int32_t, void *);
176170754Sdelphijvoid	input_userauth_pk_ok(int, u_int32_t, void *);
177170754Sdelphijvoid	input_userauth_passwd_changereq(int, u_int32_t, void *);
178170754Sdelphij
179170754Sdelphijint	userauth_none(Authctxt *);
180170754Sdelphijint	userauth_pubkey(Authctxt *);
181170754Sdelphijint	userauth_passwd(Authctxt *);
182170754Sdelphijint	userauth_kbdint(Authctxt *);
183170754Sdelphijint	userauth_hostbased(Authctxt *);
184170754Sdelphij
185170754Sdelphijvoid	userauth(Authctxt *, char *);
186170754Sdelphij
187170754Sdelphijstatic int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
188170754Sdelphijstatic void clear_auth_state(Authctxt *);
189170754Sdelphij
190170754Sdelphijstatic Authmethod *authmethod_get(char *authlist);
191170754Sdelphijstatic Authmethod *authmethod_lookup(const char *name);
192170754Sdelphijstatic char *authmethods_get(void);
193170754Sdelphij
194170754SdelphijAuthmethod authmethods[] = {
195170754Sdelphij	{"hostbased",
196170754Sdelphij		userauth_hostbased,
197170754Sdelphij		&options.hostbased_authentication,
198170754Sdelphij		NULL},
199170754Sdelphij	{"publickey",
200170754Sdelphij		userauth_pubkey,
201170754Sdelphij		&options.pubkey_authentication,
202170754Sdelphij		NULL},
203170754Sdelphij	{"keyboard-interactive",
204170754Sdelphij		userauth_kbdint,
205170754Sdelphij		&options.kbd_interactive_authentication,
206170754Sdelphij		&options.batch_mode},
207170754Sdelphij	{"password",
208170754Sdelphij		userauth_passwd,
209170754Sdelphij		&options.password_authentication,
210170754Sdelphij		&options.batch_mode},
211170754Sdelphij	{"none",
212170754Sdelphij		userauth_none,
213170754Sdelphij		NULL,
214170754Sdelphij		NULL},
215170754Sdelphij	{NULL, NULL, NULL, NULL}
216170754Sdelphij};
217170754Sdelphij
218170754Sdelphijvoid
219170754Sdelphijssh_userauth2(const char *local_user, const char *server_user, char *host,
220170754Sdelphij    Sensitive *sensitive)
221170754Sdelphij{
222170754Sdelphij	Authctxt authctxt;
223170754Sdelphij	int type;
224170754Sdelphij
225170754Sdelphij	if (options.challenge_response_authentication)
226170754Sdelphij		options.kbd_interactive_authentication = 1;
227170754Sdelphij
228170754Sdelphij	debug("send SSH2_MSG_SERVICE_REQUEST");
229170754Sdelphij	packet_start(SSH2_MSG_SERVICE_REQUEST);
230170754Sdelphij	packet_put_cstring("ssh-userauth");
231170754Sdelphij	packet_send();
232170754Sdelphij	packet_write_wait();
233170754Sdelphij	type = packet_read();
234170754Sdelphij	if (type != SSH2_MSG_SERVICE_ACCEPT) {
235170754Sdelphij		fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
236170754Sdelphij	}
237170754Sdelphij	if (packet_remaining() > 0) {
238170754Sdelphij		char *reply = packet_get_string(NULL);
239170754Sdelphij		debug("service_accept: %s", reply);
240170754Sdelphij		xfree(reply);
241170754Sdelphij	} else {
242170754Sdelphij		debug("buggy server: service_accept w/o service");
243170754Sdelphij	}
244170754Sdelphij	packet_check_eom();
245170754Sdelphij	debug("got SSH2_MSG_SERVICE_ACCEPT");
246170754Sdelphij
247170754Sdelphij	if (options.preferred_authentications == NULL)
248170754Sdelphij		options.preferred_authentications = authmethods_get();
249170754Sdelphij
250170754Sdelphij	/* setup authentication context */
251170754Sdelphij	memset(&authctxt, 0, sizeof(authctxt));
252170754Sdelphij	authctxt.agent = ssh_get_authentication_connection();
253170754Sdelphij	authctxt.server_user = server_user;
254170754Sdelphij	authctxt.local_user = local_user;
255170754Sdelphij	authctxt.host = host;
256170754Sdelphij	authctxt.service = "ssh-connection";		/* service name */
257170754Sdelphij	authctxt.success = 0;
258170754Sdelphij	authctxt.method = authmethod_lookup("none");
259170754Sdelphij	authctxt.authlist = NULL;
260170754Sdelphij	authctxt.sensitive = sensitive;
261170754Sdelphij	authctxt.info_req_seen = 0;
262170754Sdelphij	if (authctxt.method == NULL)
263170754Sdelphij		fatal("ssh_userauth2: internal error: cannot send userauth none request");
264170754Sdelphij
265170754Sdelphij	/* initial userauth request */
266170754Sdelphij	userauth_none(&authctxt);
267170754Sdelphij
268170754Sdelphij	dispatch_init(&input_userauth_error);
269170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
270170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
271170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
272170754Sdelphij	dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);	/* loop until success */
273170754Sdelphij
274170754Sdelphij	if (authctxt.agent != NULL)
275170754Sdelphij		ssh_close_authentication_connection(authctxt.agent);
276170754Sdelphij
277170754Sdelphij	debug("ssh-userauth2 successful: method %s", authctxt.method->name);
278170754Sdelphij}
279170754Sdelphijvoid
280170754Sdelphijuserauth(Authctxt *authctxt, char *authlist)
281170754Sdelphij{
282170754Sdelphij	if (authlist == NULL) {
283170754Sdelphij		authlist = authctxt->authlist;
284170754Sdelphij	} else {
285170754Sdelphij		if (authctxt->authlist)
286170754Sdelphij			xfree(authctxt->authlist);
287170754Sdelphij		authctxt->authlist = authlist;
288170754Sdelphij	}
289170754Sdelphij	for (;;) {
290170754Sdelphij		Authmethod *method = authmethod_get(authlist);
291170754Sdelphij		if (method == NULL)
292170754Sdelphij			fatal("Permission denied (%s).", authlist);
293170754Sdelphij		authctxt->method = method;
294170754Sdelphij		if (method->userauth(authctxt) != 0) {
295170754Sdelphij			debug2("we sent a %s packet, wait for reply", method->name);
296170754Sdelphij			break;
297170754Sdelphij		} else {
298170754Sdelphij			debug2("we did not send a packet, disable method");
299170754Sdelphij			method->enabled = NULL;
300170754Sdelphij		}
301170754Sdelphij	}
302170754Sdelphij}
303170754Sdelphij
304170754Sdelphijvoid
305170754Sdelphijinput_userauth_error(int type, u_int32_t seq, void *ctxt)
306170754Sdelphij{
307170754Sdelphij	fatal("input_userauth_error: bad message during authentication: "
308170754Sdelphij	   "type %d", type);
309170754Sdelphij}
310170754Sdelphij
311170754Sdelphijvoid
312170754Sdelphijinput_userauth_banner(int type, u_int32_t seq, void *ctxt)
313170754Sdelphij{
314170754Sdelphij	char *msg, *lang;
315170754Sdelphij	debug3("input_userauth_banner");
316170754Sdelphij	msg = packet_get_string(NULL);
317170754Sdelphij	lang = packet_get_string(NULL);
318170754Sdelphij	fprintf(stderr, "%s", msg);
319170754Sdelphij	xfree(msg);
320170754Sdelphij	xfree(lang);
321170754Sdelphij}
322170754Sdelphij
323170754Sdelphijvoid
324170754Sdelphijinput_userauth_success(int type, u_int32_t seq, void *ctxt)
325170754Sdelphij{
326170754Sdelphij	Authctxt *authctxt = ctxt;
327170754Sdelphij	if (authctxt == NULL)
328170754Sdelphij		fatal("input_userauth_success: no authentication context");
329170754Sdelphij	if (authctxt->authlist)
330170754Sdelphij		xfree(authctxt->authlist);
331170754Sdelphij	clear_auth_state(authctxt);
332170754Sdelphij	authctxt->success = 1;			/* break out */
333170754Sdelphij}
334170754Sdelphij
335170754Sdelphijvoid
336170754Sdelphijinput_userauth_failure(int type, u_int32_t seq, void *ctxt)
337170754Sdelphij{
338170754Sdelphij	Authctxt *authctxt = ctxt;
339170754Sdelphij	char *authlist = NULL;
340170754Sdelphij	int partial;
341170754Sdelphij
342170754Sdelphij	if (authctxt == NULL)
343170754Sdelphij		fatal("input_userauth_failure: no authentication context");
344170754Sdelphij
345170754Sdelphij	authlist = packet_get_string(NULL);
346170754Sdelphij	partial = packet_get_char();
347170754Sdelphij	packet_check_eom();
348170754Sdelphij
349170754Sdelphij	if (partial != 0)
350170754Sdelphij		log("Authenticated with partial success.");
351170754Sdelphij	debug("authentications that can continue: %s", authlist);
352170754Sdelphij
353170754Sdelphij	clear_auth_state(authctxt);
354170754Sdelphij	userauth(authctxt, authlist);
355170754Sdelphij}
356170754Sdelphijvoid
357170754Sdelphijinput_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
358170754Sdelphij{
359170754Sdelphij	Authctxt *authctxt = ctxt;
360170754Sdelphij	Key *key = NULL;
361170754Sdelphij	Buffer b;
362170754Sdelphij	int pktype, sent = 0;
363170754Sdelphij	u_int alen, blen;
364170754Sdelphij	char *pkalg, *fp;
365170754Sdelphij	u_char *pkblob;
366170754Sdelphij
367170754Sdelphij	if (authctxt == NULL)
368170754Sdelphij		fatal("input_userauth_pk_ok: no authentication context");
369170754Sdelphij	if (datafellows & SSH_BUG_PKOK) {
370170754Sdelphij		/* this is similar to SSH_BUG_PKAUTH */
371170754Sdelphij		debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
372170754Sdelphij		pkblob = packet_get_string(&blen);
373170754Sdelphij		buffer_init(&b);
374170754Sdelphij		buffer_append(&b, pkblob, blen);
375170754Sdelphij		pkalg = buffer_get_string(&b, &alen);
376170754Sdelphij		buffer_free(&b);
377170754Sdelphij	} else {
378170754Sdelphij		pkalg = packet_get_string(&alen);
379170754Sdelphij		pkblob = packet_get_string(&blen);
380170754Sdelphij	}
381170754Sdelphij	packet_check_eom();
382170754Sdelphij
383170754Sdelphij	debug("input_userauth_pk_ok: pkalg %s blen %u lastkey %p hint %d",
384170754Sdelphij	    pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
385170754Sdelphij
386170754Sdelphij	do {
387170754Sdelphij		if (authctxt->last_key == NULL ||
388170754Sdelphij		    authctxt->last_key_sign == NULL) {
389170754Sdelphij			debug("no last key or no sign cb");
390170754Sdelphij			break;
391170754Sdelphij		}
392170754Sdelphij		if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
393170754Sdelphij			debug("unknown pkalg %s", pkalg);
394170754Sdelphij			break;
395170754Sdelphij		}
396170754Sdelphij		if ((key = key_from_blob(pkblob, blen)) == NULL) {
397170754Sdelphij			debug("no key from blob. pkalg %s", pkalg);
398170754Sdelphij			break;
399170754Sdelphij		}
400170754Sdelphij		if (key->type != pktype) {
401170754Sdelphij			error("input_userauth_pk_ok: type mismatch "
402170754Sdelphij			    "for decoded key (received %d, expected %d)",
403170754Sdelphij			    key->type, pktype);
404170754Sdelphij			break;
405170754Sdelphij		}
406170754Sdelphij		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
407170754Sdelphij		debug2("input_userauth_pk_ok: fp %s", fp);
408170754Sdelphij		xfree(fp);
409170754Sdelphij		if (!key_equal(key, authctxt->last_key)) {
410170754Sdelphij			debug("key != last_key");
411170754Sdelphij			break;
412170754Sdelphij		}
413170754Sdelphij		sent = sign_and_send_pubkey(authctxt, key,
414170754Sdelphij		   authctxt->last_key_sign);
415170754Sdelphij	} while (0);
416170754Sdelphij
417170754Sdelphij	if (key != NULL)
418170754Sdelphij		key_free(key);
419170754Sdelphij	xfree(pkalg);
420170754Sdelphij	xfree(pkblob);
421170754Sdelphij
422170754Sdelphij	/* unregister */
423170754Sdelphij	clear_auth_state(authctxt);
424170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
425170754Sdelphij
426170754Sdelphij	/* try another method if we did not send a packet*/
427170754Sdelphij	if (sent == 0)
428170754Sdelphij		userauth(authctxt, NULL);
429170754Sdelphij
430170754Sdelphij}
431170754Sdelphij
432170754Sdelphijint
433170754Sdelphijuserauth_none(Authctxt *authctxt)
434170754Sdelphij{
435170754Sdelphij	/* initial userauth request */
436170754Sdelphij	packet_start(SSH2_MSG_USERAUTH_REQUEST);
437170754Sdelphij	packet_put_cstring(authctxt->server_user);
438170754Sdelphij	packet_put_cstring(authctxt->service);
439170754Sdelphij	packet_put_cstring(authctxt->method->name);
440170754Sdelphij	packet_send();
441170754Sdelphij	return 1;
442170754Sdelphij}
443170754Sdelphij
444170754Sdelphijint
445170754Sdelphijuserauth_passwd(Authctxt *authctxt)
446170754Sdelphij{
447170754Sdelphij	static int attempt = 0;
448170754Sdelphij	char prompt[150];
449170754Sdelphij	char *password;
450170754Sdelphij
451170754Sdelphij	if (attempt++ >= options.number_of_password_prompts)
452170754Sdelphij		return 0;
453170754Sdelphij
454170754Sdelphij	if (attempt != 1)
455170754Sdelphij		error("Permission denied, please try again.");
456170754Sdelphij
457170754Sdelphij	snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
458170754Sdelphij	    authctxt->server_user, authctxt->host);
459170754Sdelphij	password = read_passphrase(prompt, 0);
460170754Sdelphij	packet_start(SSH2_MSG_USERAUTH_REQUEST);
461170754Sdelphij	packet_put_cstring(authctxt->server_user);
462170754Sdelphij	packet_put_cstring(authctxt->service);
463170754Sdelphij	packet_put_cstring(authctxt->method->name);
464170754Sdelphij	packet_put_char(0);
465170754Sdelphij	packet_put_cstring(password);
466170754Sdelphij	memset(password, 0, strlen(password));
467170754Sdelphij	xfree(password);
468170754Sdelphij	packet_add_padding(64);
469170754Sdelphij	packet_send();
470170754Sdelphij
471170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
472170754Sdelphij	    &input_userauth_passwd_changereq);
473170754Sdelphij
474170754Sdelphij	return 1;
475170754Sdelphij}
476170754Sdelphij/*
477170754Sdelphij * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
478170754Sdelphij */
479170754Sdelphijvoid
480170754Sdelphijinput_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
481170754Sdelphij{
482170754Sdelphij	Authctxt *authctxt = ctxt;
483170754Sdelphij	char *info, *lang, *password = NULL, *retype = NULL;
484170754Sdelphij	char prompt[150];
485170754Sdelphij
486170754Sdelphij	debug2("input_userauth_passwd_changereq");
487170754Sdelphij
488170754Sdelphij	if (authctxt == NULL)
489170754Sdelphij		fatal("input_userauth_passwd_changereq: "
490170754Sdelphij		    "no authentication context");
491170754Sdelphij
492170754Sdelphij	info = packet_get_string(NULL);
493170754Sdelphij	lang = packet_get_string(NULL);
494170754Sdelphij	if (strlen(info) > 0)
495170754Sdelphij		log("%s", info);
496170754Sdelphij	xfree(info);
497170754Sdelphij	xfree(lang);
498170754Sdelphij	packet_start(SSH2_MSG_USERAUTH_REQUEST);
499170754Sdelphij	packet_put_cstring(authctxt->server_user);
500170754Sdelphij	packet_put_cstring(authctxt->service);
501170754Sdelphij	packet_put_cstring(authctxt->method->name);
502170754Sdelphij	packet_put_char(1);			/* additional info */
503170754Sdelphij	snprintf(prompt, sizeof(prompt),
504170754Sdelphij	    "Enter %.30s@%.128s's old password: ",
505170754Sdelphij	    authctxt->server_user, authctxt->host);
506170754Sdelphij	password = read_passphrase(prompt, 0);
507170754Sdelphij	packet_put_cstring(password);
508170754Sdelphij	memset(password, 0, strlen(password));
509170754Sdelphij	xfree(password);
510170754Sdelphij	password = NULL;
511170754Sdelphij	while (password == NULL) {
512170754Sdelphij		snprintf(prompt, sizeof(prompt),
513170754Sdelphij		    "Enter %.30s@%.128s's new password: ",
514170754Sdelphij		    authctxt->server_user, authctxt->host);
515170754Sdelphij		password = read_passphrase(prompt, RP_ALLOW_EOF);
516170754Sdelphij		if (password == NULL) {
517170754Sdelphij			/* bail out */
518170754Sdelphij			return;
519170754Sdelphij		}
520170754Sdelphij		snprintf(prompt, sizeof(prompt),
521170754Sdelphij		    "Retype %.30s@%.128s's new password: ",
522170754Sdelphij		    authctxt->server_user, authctxt->host);
523170754Sdelphij		retype = read_passphrase(prompt, 0);
524170754Sdelphij		if (strcmp(password, retype) != 0) {
525170754Sdelphij			memset(password, 0, strlen(password));
526170754Sdelphij			xfree(password);
527170754Sdelphij			log("Mismatch; try again, EOF to quit.");
528170754Sdelphij			password = NULL;
529170754Sdelphij		}
530170754Sdelphij		memset(retype, 0, strlen(retype));
531170754Sdelphij		xfree(retype);
532170754Sdelphij	}
533170754Sdelphij	packet_put_cstring(password);
534170754Sdelphij	memset(password, 0, strlen(password));
535170754Sdelphij	xfree(password);
536170754Sdelphij	packet_add_padding(64);
537170754Sdelphij	packet_send();
538170754Sdelphij
539170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
540170754Sdelphij	    &input_userauth_passwd_changereq);
541170754Sdelphij}
542170754Sdelphij
543170754Sdelphijstatic void
544170754Sdelphijclear_auth_state(Authctxt *authctxt)
545170754Sdelphij{
546170754Sdelphij	/* XXX clear authentication state */
547170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
548170754Sdelphij
549170754Sdelphij	if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
550170754Sdelphij		debug3("clear_auth_state: key_free %p", authctxt->last_key);
551170754Sdelphij		key_free(authctxt->last_key);
552170754Sdelphij	}
553170754Sdelphij	authctxt->last_key = NULL;
554170754Sdelphij	authctxt->last_key_hint = -2;
555170754Sdelphij	authctxt->last_key_sign = NULL;
556170754Sdelphij}
557170754Sdelphij
558170754Sdelphijstatic int
559170754Sdelphijsign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
560170754Sdelphij{
561170754Sdelphij	Buffer b;
562170754Sdelphij	u_char *blob, *signature;
563170754Sdelphij	u_int bloblen, slen;
564170754Sdelphij	int skip = 0;
565170754Sdelphij	int ret = -1;
566170754Sdelphij	int have_sig = 1;
567170754Sdelphij
568170754Sdelphij	debug3("sign_and_send_pubkey");
569170754Sdelphij
570170754Sdelphij	if (key_to_blob(k, &blob, &bloblen) == 0) {
571170754Sdelphij		/* we cannot handle this key */
572170754Sdelphij		debug3("sign_and_send_pubkey: cannot handle key");
573170754Sdelphij		return 0;
574170754Sdelphij	}
575170754Sdelphij	/* data to be signed */
576170754Sdelphij	buffer_init(&b);
577170754Sdelphij	if (datafellows & SSH_OLD_SESSIONID) {
578170754Sdelphij		buffer_append(&b, session_id2, session_id2_len);
579170754Sdelphij		skip = session_id2_len;
580170754Sdelphij	} else {
581170754Sdelphij		buffer_put_string(&b, session_id2, session_id2_len);
582170754Sdelphij		skip = buffer_len(&b);
583170754Sdelphij	}
584170754Sdelphij	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
585170754Sdelphij	buffer_put_cstring(&b, authctxt->server_user);
586170754Sdelphij	buffer_put_cstring(&b,
587170754Sdelphij	    datafellows & SSH_BUG_PKSERVICE ?
588170754Sdelphij	    "ssh-userauth" :
589170754Sdelphij	    authctxt->service);
590170754Sdelphij	if (datafellows & SSH_BUG_PKAUTH) {
591170754Sdelphij		buffer_put_char(&b, have_sig);
592170754Sdelphij	} else {
593170754Sdelphij		buffer_put_cstring(&b, authctxt->method->name);
594170754Sdelphij		buffer_put_char(&b, have_sig);
595170754Sdelphij		buffer_put_cstring(&b, key_ssh_name(k));
596170754Sdelphij	}
597170754Sdelphij	buffer_put_string(&b, blob, bloblen);
598170754Sdelphij
599170754Sdelphij	/* generate signature */
600170754Sdelphij	ret = (*sign_callback)(authctxt, k, &signature, &slen,
601170754Sdelphij	    buffer_ptr(&b), buffer_len(&b));
602170754Sdelphij	if (ret == -1) {
603170754Sdelphij		xfree(blob);
604170754Sdelphij		buffer_free(&b);
605170754Sdelphij		return 0;
606170754Sdelphij	}
607170754Sdelphij#ifdef DEBUG_PK
608170754Sdelphij	buffer_dump(&b);
609170754Sdelphij#endif
610170754Sdelphij	if (datafellows & SSH_BUG_PKSERVICE) {
611170754Sdelphij		buffer_clear(&b);
612170754Sdelphij		buffer_append(&b, session_id2, session_id2_len);
613170754Sdelphij		skip = session_id2_len;
614170754Sdelphij		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
615170754Sdelphij		buffer_put_cstring(&b, authctxt->server_user);
616170754Sdelphij		buffer_put_cstring(&b, authctxt->service);
617170754Sdelphij		buffer_put_cstring(&b, authctxt->method->name);
618170754Sdelphij		buffer_put_char(&b, have_sig);
619170754Sdelphij		if (!(datafellows & SSH_BUG_PKAUTH))
620170754Sdelphij			buffer_put_cstring(&b, key_ssh_name(k));
621170754Sdelphij		buffer_put_string(&b, blob, bloblen);
622170754Sdelphij	}
623170754Sdelphij	xfree(blob);
624170754Sdelphij
625170754Sdelphij	/* append signature */
626170754Sdelphij	buffer_put_string(&b, signature, slen);
627170754Sdelphij	xfree(signature);
628170754Sdelphij
629170754Sdelphij	/* skip session id and packet type */
630170754Sdelphij	if (buffer_len(&b) < skip + 1)
631170754Sdelphij		fatal("userauth_pubkey: internal error");
632170754Sdelphij	buffer_consume(&b, skip + 1);
633170754Sdelphij
634170754Sdelphij	/* put remaining data from buffer into packet */
635170754Sdelphij	packet_start(SSH2_MSG_USERAUTH_REQUEST);
636170754Sdelphij	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
637170754Sdelphij	buffer_free(&b);
638170754Sdelphij	packet_send();
639170754Sdelphij
640170754Sdelphij	return 1;
641170754Sdelphij}
642170754Sdelphij
643170754Sdelphijstatic int
644170754Sdelphijsend_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
645170754Sdelphij    int hint)
646170754Sdelphij{
647170754Sdelphij	u_char *blob;
648170754Sdelphij	u_int bloblen, have_sig = 0;
649170754Sdelphij
650170754Sdelphij	debug3("send_pubkey_test");
651170754Sdelphij
652170754Sdelphij	if (key_to_blob(k, &blob, &bloblen) == 0) {
653170754Sdelphij		/* we cannot handle this key */
654170754Sdelphij		debug3("send_pubkey_test: cannot handle key");
655170754Sdelphij		return 0;
656170754Sdelphij	}
657170754Sdelphij	/* register callback for USERAUTH_PK_OK message */
658170754Sdelphij	authctxt->last_key_sign = sign_callback;
659170754Sdelphij	authctxt->last_key_hint = hint;
660170754Sdelphij	authctxt->last_key = k;
661170754Sdelphij	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
662170754Sdelphij
663170754Sdelphij	packet_start(SSH2_MSG_USERAUTH_REQUEST);
664170754Sdelphij	packet_put_cstring(authctxt->server_user);
665170754Sdelphij	packet_put_cstring(authctxt->service);
666170754Sdelphij	packet_put_cstring(authctxt->method->name);
667170754Sdelphij	packet_put_char(have_sig);
668170754Sdelphij	if (!(datafellows & SSH_BUG_PKAUTH))
669170754Sdelphij		packet_put_cstring(key_ssh_name(k));
670170754Sdelphij	packet_put_string(blob, bloblen);
671170754Sdelphij	xfree(blob);
672170754Sdelphij	packet_send();
673170754Sdelphij	return 1;
674170754Sdelphij}
675170754Sdelphij
676170754Sdelphijstatic Key *
677170754Sdelphijload_identity_file(char *filename)
678{
679	Key *private;
680	char prompt[300], *passphrase;
681	int quit, i;
682	struct stat st;
683
684	if (stat(filename, &st) < 0) {
685		debug3("no such identity: %s", filename);
686		return NULL;
687	}
688	private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
689	if (private == NULL) {
690		if (options.batch_mode)
691			return NULL;
692		snprintf(prompt, sizeof prompt,
693		    "Enter passphrase for key '%.100s': ", filename);
694		for (i = 0; i < options.number_of_password_prompts; i++) {
695			passphrase = read_passphrase(prompt, 0);
696			if (strcmp(passphrase, "") != 0) {
697				private = key_load_private_type(KEY_UNSPEC, filename,
698				    passphrase, NULL);
699				quit = 0;
700			} else {
701				debug2("no passphrase given, try next key");
702				quit = 1;
703			}
704			memset(passphrase, 0, strlen(passphrase));
705			xfree(passphrase);
706			if (private != NULL || quit)
707				break;
708			debug2("bad passphrase given, try again...");
709		}
710	}
711	return private;
712}
713
714static int
715identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
716    u_char *data, u_int datalen)
717{
718	Key *private;
719	int idx, ret;
720
721	idx = authctxt->last_key_hint;
722	if (idx < 0)
723		return -1;
724
725	/* private key is stored in external hardware */
726	if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
727		return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
728
729	private = load_identity_file(options.identity_files[idx]);
730	if (private == NULL)
731		return -1;
732	ret = key_sign(private, sigp, lenp, data, datalen);
733	key_free(private);
734	return ret;
735}
736
737static int
738agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
739    u_char *data, u_int datalen)
740{
741	return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
742}
743
744static int
745key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
746    u_char *data, u_int datalen)
747{
748	return key_sign(key, sigp, lenp, data, datalen);
749}
750
751static int
752userauth_pubkey_agent(Authctxt *authctxt)
753{
754	static int called = 0;
755	int ret = 0;
756	char *comment;
757	Key *k;
758
759	if (called == 0) {
760		if (ssh_get_num_identities(authctxt->agent, 2) == 0)
761			debug2("userauth_pubkey_agent: no keys at all");
762		called = 1;
763	}
764	k = ssh_get_next_identity(authctxt->agent, &comment, 2);
765	if (k == NULL) {
766		debug2("userauth_pubkey_agent: no more keys");
767	} else {
768		debug("userauth_pubkey_agent: testing agent key %s", comment);
769		xfree(comment);
770		ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
771		if (ret == 0)
772			key_free(k);
773	}
774	if (ret == 0)
775		debug2("userauth_pubkey_agent: no message sent");
776	return ret;
777}
778
779int
780userauth_pubkey(Authctxt *authctxt)
781{
782	static int idx = 0;
783	int sent = 0;
784	Key *key;
785	char *filename;
786
787	if (authctxt->agent != NULL) {
788		do {
789			sent = userauth_pubkey_agent(authctxt);
790		} while (!sent && authctxt->agent->howmany > 0);
791	}
792	while (!sent && idx < options.num_identity_files) {
793		key = options.identity_keys[idx];
794		filename = options.identity_files[idx];
795		if (key == NULL) {
796			debug("try privkey: %s", filename);
797			key = load_identity_file(filename);
798			if (key != NULL) {
799				sent = sign_and_send_pubkey(authctxt, key,
800				    key_sign_cb);
801				key_free(key);
802			}
803		} else if (key->type != KEY_RSA1) {
804			debug("try pubkey: %s", filename);
805			sent = send_pubkey_test(authctxt, key,
806			    identity_sign_cb, idx);
807		}
808		idx++;
809	}
810	return sent;
811}
812
813/*
814 * Send userauth request message specifying keyboard-interactive method.
815 */
816int
817userauth_kbdint(Authctxt *authctxt)
818{
819	static int attempt = 0;
820
821	if (attempt++ >= options.number_of_password_prompts)
822		return 0;
823	/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
824	if (attempt > 1 && !authctxt->info_req_seen) {
825		debug3("userauth_kbdint: disable: no info_req_seen");
826		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
827		return 0;
828	}
829
830	debug2("userauth_kbdint");
831	packet_start(SSH2_MSG_USERAUTH_REQUEST);
832	packet_put_cstring(authctxt->server_user);
833	packet_put_cstring(authctxt->service);
834	packet_put_cstring(authctxt->method->name);
835	packet_put_cstring("");					/* lang */
836	packet_put_cstring(options.kbd_interactive_devices ?
837	    options.kbd_interactive_devices : "");
838	packet_send();
839
840	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
841	return 1;
842}
843
844/*
845 * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
846 */
847void
848input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
849{
850	Authctxt *authctxt = ctxt;
851	char *name, *inst, *lang, *prompt, *response;
852	u_int num_prompts, i;
853	int echo = 0;
854
855	debug2("input_userauth_info_req");
856
857	if (authctxt == NULL)
858		fatal("input_userauth_info_req: no authentication context");
859
860	authctxt->info_req_seen = 1;
861
862	name = packet_get_string(NULL);
863	inst = packet_get_string(NULL);
864	lang = packet_get_string(NULL);
865	if (strlen(name) > 0)
866		log("%s", name);
867	if (strlen(inst) > 0)
868		log("%s", inst);
869	xfree(name);
870	xfree(inst);
871	xfree(lang);
872
873	num_prompts = packet_get_int();
874	/*
875	 * Begin to build info response packet based on prompts requested.
876	 * We commit to providing the correct number of responses, so if
877	 * further on we run into a problem that prevents this, we have to
878	 * be sure and clean this up and send a correct error response.
879	 */
880	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
881	packet_put_int(num_prompts);
882
883	debug2("input_userauth_info_req: num_prompts %d", num_prompts);
884	for (i = 0; i < num_prompts; i++) {
885		prompt = packet_get_string(NULL);
886		echo = packet_get_char();
887
888		response = read_passphrase(prompt, echo ? RP_ECHO : 0);
889
890		packet_put_cstring(response);
891		memset(response, 0, strlen(response));
892		xfree(response);
893		xfree(prompt);
894	}
895	packet_check_eom(); /* done with parsing incoming message. */
896
897	packet_add_padding(64);
898	packet_send();
899}
900
901static int
902ssh_keysign(Key *key, u_char **sigp, u_int *lenp,
903    u_char *data, u_int datalen)
904{
905	Buffer b;
906	struct stat st;
907	pid_t pid;
908	int to[2], from[2], status, version = 2;
909
910	debug("ssh_keysign called");
911
912	if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
913		error("ssh_keysign: no installed: %s", strerror(errno));
914		return -1;
915	}
916	if (fflush(stdout) != 0)
917		error("ssh_keysign: fflush: %s", strerror(errno));
918	if (pipe(to) < 0) {
919		error("ssh_keysign: pipe: %s", strerror(errno));
920		return -1;
921	}
922	if (pipe(from) < 0) {
923		error("ssh_keysign: pipe: %s", strerror(errno));
924		return -1;
925	}
926	if ((pid = fork()) < 0) {
927		error("ssh_keysign: fork: %s", strerror(errno));
928		return -1;
929	}
930	if (pid == 0) {
931		seteuid(getuid());
932		setuid(getuid());
933		close(from[0]);
934		if (dup2(from[1], STDOUT_FILENO) < 0)
935			fatal("ssh_keysign: dup2: %s", strerror(errno));
936		close(to[1]);
937		if (dup2(to[0], STDIN_FILENO) < 0)
938			fatal("ssh_keysign: dup2: %s", strerror(errno));
939		close(from[1]);
940		close(to[0]);
941		execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
942		fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
943		    strerror(errno));
944	}
945	close(from[1]);
946	close(to[0]);
947
948	buffer_init(&b);
949	buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
950	buffer_put_string(&b, data, datalen);
951	msg_send(to[1], version, &b);
952
953	if (msg_recv(from[0], &b) < 0) {
954		error("ssh_keysign: no reply");
955		buffer_clear(&b);
956		return -1;
957	}
958	close(from[0]);
959	close(to[1]);
960
961	while (waitpid(pid, &status, 0) < 0)
962		if (errno != EINTR)
963			break;
964
965	if (buffer_get_char(&b) != version) {
966		error("ssh_keysign: bad version");
967		buffer_clear(&b);
968		return -1;
969	}
970	*sigp = buffer_get_string(&b, lenp);
971	buffer_clear(&b);
972
973	return 0;
974}
975
976int
977userauth_hostbased(Authctxt *authctxt)
978{
979	Key *private = NULL;
980	Sensitive *sensitive = authctxt->sensitive;
981	Buffer b;
982	u_char *signature, *blob;
983	char *chost, *pkalg, *p;
984	const char *service;
985	u_int blen, slen;
986	int ok, i, len, found = 0;
987
988	/* check for a useful key */
989	for (i = 0; i < sensitive->nkeys; i++) {
990		private = sensitive->keys[i];
991		if (private && private->type != KEY_RSA1) {
992			found = 1;
993			/* we take and free the key */
994			sensitive->keys[i] = NULL;
995			break;
996		}
997	}
998	if (!found) {
999		debug("userauth_hostbased: no more client hostkeys");
1000		return 0;
1001	}
1002	if (key_to_blob(private, &blob, &blen) == 0) {
1003		key_free(private);
1004		return 0;
1005	}
1006	/* figure out a name for the client host */
1007	p = get_local_name(packet_get_connection_in());
1008	if (p == NULL) {
1009		error("userauth_hostbased: cannot get local ipaddr/name");
1010		key_free(private);
1011		return 0;
1012	}
1013	len = strlen(p) + 2;
1014	chost = xmalloc(len);
1015	strlcpy(chost, p, len);
1016	strlcat(chost, ".", len);
1017	debug2("userauth_hostbased: chost %s", chost);
1018
1019	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
1020	    authctxt->service;
1021	pkalg = xstrdup(key_ssh_name(private));
1022	buffer_init(&b);
1023	/* construct data */
1024	buffer_put_string(&b, session_id2, session_id2_len);
1025	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1026	buffer_put_cstring(&b, authctxt->server_user);
1027	buffer_put_cstring(&b, service);
1028	buffer_put_cstring(&b, authctxt->method->name);
1029	buffer_put_cstring(&b, pkalg);
1030	buffer_put_string(&b, blob, blen);
1031	buffer_put_cstring(&b, chost);
1032	buffer_put_cstring(&b, authctxt->local_user);
1033#ifdef DEBUG_PK
1034	buffer_dump(&b);
1035#endif
1036	if (sensitive->external_keysign)
1037		ok = ssh_keysign(private, &signature, &slen,
1038		    buffer_ptr(&b), buffer_len(&b));
1039	else
1040		ok = key_sign(private, &signature, &slen,
1041		    buffer_ptr(&b), buffer_len(&b));
1042	key_free(private);
1043	buffer_free(&b);
1044	if (ok != 0) {
1045		error("key_sign failed");
1046		xfree(chost);
1047		xfree(pkalg);
1048		return 0;
1049	}
1050	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1051	packet_put_cstring(authctxt->server_user);
1052	packet_put_cstring(authctxt->service);
1053	packet_put_cstring(authctxt->method->name);
1054	packet_put_cstring(pkalg);
1055	packet_put_string(blob, blen);
1056	packet_put_cstring(chost);
1057	packet_put_cstring(authctxt->local_user);
1058	packet_put_string(signature, slen);
1059	memset(signature, 's', slen);
1060	xfree(signature);
1061	xfree(chost);
1062	xfree(pkalg);
1063
1064	packet_send();
1065	return 1;
1066}
1067
1068/* find auth method */
1069
1070/*
1071 * given auth method name, if configurable options permit this method fill
1072 * in auth_ident field and return true, otherwise return false.
1073 */
1074static int
1075authmethod_is_enabled(Authmethod *method)
1076{
1077	if (method == NULL)
1078		return 0;
1079	/* return false if options indicate this method is disabled */
1080	if  (method->enabled == NULL || *method->enabled == 0)
1081		return 0;
1082	/* return false if batch mode is enabled but method needs interactive mode */
1083	if  (method->batch_flag != NULL && *method->batch_flag != 0)
1084		return 0;
1085	return 1;
1086}
1087
1088static Authmethod *
1089authmethod_lookup(const char *name)
1090{
1091	Authmethod *method = NULL;
1092	if (name != NULL)
1093		for (method = authmethods; method->name != NULL; method++)
1094			if (strcmp(name, method->name) == 0)
1095				return method;
1096	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1097	return NULL;
1098}
1099
1100/* XXX internal state */
1101static Authmethod *current = NULL;
1102static char *supported = NULL;
1103static char *preferred = NULL;
1104
1105/*
1106 * Given the authentication method list sent by the server, return the
1107 * next method we should try.  If the server initially sends a nil list,
1108 * use a built-in default list.
1109 */
1110static Authmethod *
1111authmethod_get(char *authlist)
1112{
1113
1114	char *name = NULL;
1115	u_int next;
1116
1117	/* Use a suitable default if we're passed a nil list.  */
1118	if (authlist == NULL || strlen(authlist) == 0)
1119		authlist = options.preferred_authentications;
1120
1121	if (supported == NULL || strcmp(authlist, supported) != 0) {
1122		debug3("start over, passed a different list %s", authlist);
1123		if (supported != NULL)
1124			xfree(supported);
1125		supported = xstrdup(authlist);
1126		preferred = options.preferred_authentications;
1127		debug3("preferred %s", preferred);
1128		current = NULL;
1129	} else if (current != NULL && authmethod_is_enabled(current))
1130		return current;
1131
1132	for (;;) {
1133		if ((name = match_list(preferred, supported, &next)) == NULL) {
1134			debug("no more auth methods to try");
1135			current = NULL;
1136			return NULL;
1137		}
1138		preferred += next;
1139		debug3("authmethod_lookup %s", name);
1140		debug3("remaining preferred: %s", preferred);
1141		if ((current = authmethod_lookup(name)) != NULL &&
1142		    authmethod_is_enabled(current)) {
1143			debug3("authmethod_is_enabled %s", name);
1144			debug("next auth method to try is %s", name);
1145			return current;
1146		}
1147	}
1148}
1149
1150static char *
1151authmethods_get(void)
1152{
1153	Authmethod *method = NULL;
1154	Buffer b;
1155	char *list;
1156
1157	buffer_init(&b);
1158	for (method = authmethods; method->name != NULL; method++) {
1159		if (authmethod_is_enabled(method)) {
1160			if (buffer_len(&b) > 0)
1161				buffer_append(&b, ",", 1);
1162			buffer_append(&b, method->name, strlen(method->name));
1163		}
1164	}
1165	buffer_append(&b, "\0", 1);
1166	list = xstrdup(buffer_ptr(&b));
1167	buffer_free(&b);
1168	return list;
1169}
1170