1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
5*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
6*0Sstevel@tonic-gate  * are met:
7*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
8*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
9*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
10*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
11*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*0Sstevel@tonic-gate  */
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "includes.h"
30*0Sstevel@tonic-gate RCSID("$OpenBSD: sshconnect2.c,v 1.107 2002/07/01 19:48:46 markus Exp $");
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include "ssh.h"
35*0Sstevel@tonic-gate #include "ssh2.h"
36*0Sstevel@tonic-gate #include "xmalloc.h"
37*0Sstevel@tonic-gate #include "buffer.h"
38*0Sstevel@tonic-gate #include "packet.h"
39*0Sstevel@tonic-gate #include "compat.h"
40*0Sstevel@tonic-gate #include "bufaux.h"
41*0Sstevel@tonic-gate #include "cipher.h"
42*0Sstevel@tonic-gate #include "kex.h"
43*0Sstevel@tonic-gate #include "myproposal.h"
44*0Sstevel@tonic-gate #include "sshconnect.h"
45*0Sstevel@tonic-gate #include "authfile.h"
46*0Sstevel@tonic-gate #include "dh.h"
47*0Sstevel@tonic-gate #include "authfd.h"
48*0Sstevel@tonic-gate #include "log.h"
49*0Sstevel@tonic-gate #include "readconf.h"
50*0Sstevel@tonic-gate #include "readpass.h"
51*0Sstevel@tonic-gate #include "match.h"
52*0Sstevel@tonic-gate #include "dispatch.h"
53*0Sstevel@tonic-gate #include "canohost.h"
54*0Sstevel@tonic-gate #include "msg.h"
55*0Sstevel@tonic-gate #include "pathnames.h"
56*0Sstevel@tonic-gate #include "g11n.h"
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #ifdef GSSAPI
59*0Sstevel@tonic-gate #include "ssh-gss.h"
60*0Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt;
61*0Sstevel@tonic-gate #endif /* GSSAPI */
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate /* import */
64*0Sstevel@tonic-gate extern char *client_version_string;
65*0Sstevel@tonic-gate extern char *server_version_string;
66*0Sstevel@tonic-gate extern Options options;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * SSH2 key exchange
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate u_char *session_id2 = NULL;
73*0Sstevel@tonic-gate int session_id2_len = 0;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate char *xxx_host;
76*0Sstevel@tonic-gate struct sockaddr *xxx_hostaddr;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate Kex *xxx_kex = NULL;
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate static int
81*0Sstevel@tonic-gate verify_host_key_callback(Key *hostkey)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate 	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
84*0Sstevel@tonic-gate 		fatal("Host key verification failed.");
85*0Sstevel@tonic-gate 	return 0;
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate static int
89*0Sstevel@tonic-gate accept_host_key_callback(Key *hostkey)
90*0Sstevel@tonic-gate {
91*0Sstevel@tonic-gate 	if (accept_host_key(xxx_host, xxx_hostaddr, hostkey) == -1)
92*0Sstevel@tonic-gate 		log("GSS-API authenticated host key addition to "
93*0Sstevel@tonic-gate 			"known_hosts file failed");
94*0Sstevel@tonic-gate 	return 0;
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate void
98*0Sstevel@tonic-gate ssh_kex2(char *host, struct sockaddr *hostaddr)
99*0Sstevel@tonic-gate {
100*0Sstevel@tonic-gate 	Kex *kex;
101*0Sstevel@tonic-gate 	Kex_hook_func kex_hook = NULL;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	xxx_host = host;
104*0Sstevel@tonic-gate 	xxx_hostaddr = hostaddr;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate #ifdef GSSAPI
107*0Sstevel@tonic-gate 	/* Add the GSSAPI mechanisms currently supported on this client to
108*0Sstevel@tonic-gate 	 * the key exchange algorithm proposal */
109*0Sstevel@tonic-gate 	if (options.gss_keyex)
110*0Sstevel@tonic-gate 		kex_hook = ssh_gssapi_client_kex_hook;
111*0Sstevel@tonic-gate #endif /* GSSAPI */
112*0Sstevel@tonic-gate 	if (options.ciphers == (char *)-1) {
113*0Sstevel@tonic-gate 		log("No valid ciphers for protocol version 2 given, using defaults.");
114*0Sstevel@tonic-gate 		options.ciphers = NULL;
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 	if (options.ciphers != NULL) {
117*0Sstevel@tonic-gate 		myproposal[PROPOSAL_ENC_ALGS_CTOS] =
118*0Sstevel@tonic-gate 		myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 	myproposal[PROPOSAL_ENC_ALGS_CTOS] =
121*0Sstevel@tonic-gate 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]);
122*0Sstevel@tonic-gate 	myproposal[PROPOSAL_ENC_ALGS_STOC] =
123*0Sstevel@tonic-gate 	    compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]);
124*0Sstevel@tonic-gate 	if (options.compression) {
125*0Sstevel@tonic-gate 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
126*0Sstevel@tonic-gate 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none";
127*0Sstevel@tonic-gate 	} else {
128*0Sstevel@tonic-gate 		myproposal[PROPOSAL_COMP_ALGS_CTOS] =
129*0Sstevel@tonic-gate 		myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib";
130*0Sstevel@tonic-gate 	}
131*0Sstevel@tonic-gate 	if (options.macs != NULL) {
132*0Sstevel@tonic-gate 		myproposal[PROPOSAL_MAC_ALGS_CTOS] =
133*0Sstevel@tonic-gate 		myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 	if (options.hostkeyalgorithms != NULL)
136*0Sstevel@tonic-gate 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
137*0Sstevel@tonic-gate 		    options.hostkeyalgorithms;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) {
140*0Sstevel@tonic-gate 		char *locale = setlocale(LC_ALL, "");
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate 		/* Solaris 9 SSHD expects a locale, not a langtag list */
143*0Sstevel@tonic-gate 		myproposal[PROPOSAL_LANG_CTOS] = "";
144*0Sstevel@tonic-gate 		if (locale != NULL && *locale != '\0' &&
145*0Sstevel@tonic-gate 		    strcmp(locale, "C") != 0)
146*0Sstevel@tonic-gate 			myproposal[PROPOSAL_LANG_CTOS] = locale;
147*0Sstevel@tonic-gate 	} else {
148*0Sstevel@tonic-gate 		myproposal[PROPOSAL_LANG_CTOS] = g11n_getlangs();
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	/* Same languages proposal for both directions */
152*0Sstevel@tonic-gate 	if (myproposal[PROPOSAL_LANG_CTOS] == NULL) {
153*0Sstevel@tonic-gate 		myproposal[PROPOSAL_LANG_CTOS] = "";
154*0Sstevel@tonic-gate 		myproposal[PROPOSAL_LANG_STOC] = "";
155*0Sstevel@tonic-gate 	} else {
156*0Sstevel@tonic-gate 		myproposal[PROPOSAL_LANG_STOC] =
157*0Sstevel@tonic-gate 			myproposal[PROPOSAL_LANG_CTOS];
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate         /* start key exchange */
161*0Sstevel@tonic-gate         kex = kex_setup(host, myproposal, kex_hook);
162*0Sstevel@tonic-gate         kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
163*0Sstevel@tonic-gate         kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
164*0Sstevel@tonic-gate #ifdef GSSAPI
165*0Sstevel@tonic-gate 	kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
166*0Sstevel@tonic-gate 	kex->options.gss_deleg_creds = options.gss_deleg_creds;
167*0Sstevel@tonic-gate #endif /* GSSAPI */
168*0Sstevel@tonic-gate         kex->client_version_string=client_version_string;
169*0Sstevel@tonic-gate         kex->server_version_string=server_version_string;
170*0Sstevel@tonic-gate         kex->verify_host_key=&verify_host_key_callback;
171*0Sstevel@tonic-gate         kex->accept_host_key=&accept_host_key_callback;
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	xxx_kex = kex;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	session_id2 = kex->session_id;
178*0Sstevel@tonic-gate 	session_id2_len = kex->session_id_len;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate #ifdef DEBUG_KEXDH
181*0Sstevel@tonic-gate 	/* send 1st encrypted/maced/compressed message */
182*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_IGNORE);
183*0Sstevel@tonic-gate 	packet_put_cstring("markus");
184*0Sstevel@tonic-gate 	packet_send();
185*0Sstevel@tonic-gate 	packet_write_wait();
186*0Sstevel@tonic-gate #endif
187*0Sstevel@tonic-gate 	debug("done: ssh_kex2.");
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate /*
191*0Sstevel@tonic-gate  * Authenticate user
192*0Sstevel@tonic-gate  */
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate typedef struct Authctxt Authctxt;
195*0Sstevel@tonic-gate typedef struct Authmethod Authmethod;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate typedef int sign_cb_fn(
198*0Sstevel@tonic-gate     Authctxt *authctxt, Key *key,
199*0Sstevel@tonic-gate     u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate struct Authctxt {
202*0Sstevel@tonic-gate 	const char *server_user;
203*0Sstevel@tonic-gate 	const char *local_user;
204*0Sstevel@tonic-gate 	const char *host;
205*0Sstevel@tonic-gate 	const char *service;
206*0Sstevel@tonic-gate 	Authmethod *method;
207*0Sstevel@tonic-gate 	int success;
208*0Sstevel@tonic-gate 	char *authlist;
209*0Sstevel@tonic-gate 	/* pubkey */
210*0Sstevel@tonic-gate 	Key *last_key;
211*0Sstevel@tonic-gate 	sign_cb_fn *last_key_sign;
212*0Sstevel@tonic-gate 	int last_key_hint;
213*0Sstevel@tonic-gate 	AuthenticationConnection *agent;
214*0Sstevel@tonic-gate 	/* hostbased */
215*0Sstevel@tonic-gate 	Sensitive *sensitive;
216*0Sstevel@tonic-gate 	/* kbd-interactive */
217*0Sstevel@tonic-gate 	int info_req_seen;
218*0Sstevel@tonic-gate 	/* generic */
219*0Sstevel@tonic-gate 	void *methoddata;
220*0Sstevel@tonic-gate };
221*0Sstevel@tonic-gate struct Authmethod {
222*0Sstevel@tonic-gate 	char	*name;		/* string to compare against server's list */
223*0Sstevel@tonic-gate 	int	(*userauth)(Authctxt *authctxt);
224*0Sstevel@tonic-gate 	void	(*cleanup)(Authctxt *authctxt);
225*0Sstevel@tonic-gate 	int	*enabled;	/* flag in option struct that enables method */
226*0Sstevel@tonic-gate 	int	*batch_flag;	/* flag in option struct that disables method */
227*0Sstevel@tonic-gate };
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate void	input_userauth_success(int, u_int32_t, void *);
230*0Sstevel@tonic-gate void	input_userauth_failure(int, u_int32_t, void *);
231*0Sstevel@tonic-gate void	input_userauth_banner(int, u_int32_t, void *);
232*0Sstevel@tonic-gate void	input_userauth_error(int, u_int32_t, void *);
233*0Sstevel@tonic-gate void	input_userauth_info_req(int, u_int32_t, void *);
234*0Sstevel@tonic-gate void	input_userauth_pk_ok(int, u_int32_t, void *);
235*0Sstevel@tonic-gate void	input_userauth_passwd_changereq(int, u_int32_t, void *);
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate int	userauth_none(Authctxt *);
238*0Sstevel@tonic-gate int	userauth_pubkey(Authctxt *);
239*0Sstevel@tonic-gate int	userauth_passwd(Authctxt *);
240*0Sstevel@tonic-gate int	userauth_kbdint(Authctxt *);
241*0Sstevel@tonic-gate int	userauth_hostbased(Authctxt *);
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate #ifdef GSSAPI
244*0Sstevel@tonic-gate static	int	userauth_gssapi_keyex(Authctxt *authctxt);
245*0Sstevel@tonic-gate static	int	userauth_gssapi(Authctxt *authctxt);
246*0Sstevel@tonic-gate static	void	userauth_gssapi_cleanup(Authctxt *authctxt);
247*0Sstevel@tonic-gate static	void	input_gssapi_response(int type, u_int32_t, void *);
248*0Sstevel@tonic-gate static	void	input_gssapi_token(int type, u_int32_t, void *);
249*0Sstevel@tonic-gate static	void	input_gssapi_hash(int type, u_int32_t, void *);
250*0Sstevel@tonic-gate static	void	input_gssapi_error(int, u_int32_t, void *);
251*0Sstevel@tonic-gate static	void	input_gssapi_errtok(int, u_int32_t, void *);
252*0Sstevel@tonic-gate #endif /* GSSAPI */
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate void	userauth(Authctxt *, char *);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
257*0Sstevel@tonic-gate static void clear_auth_state(Authctxt *);
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate static Authmethod *authmethod_get(char *authlist);
260*0Sstevel@tonic-gate static Authmethod *authmethod_lookup(const char *name);
261*0Sstevel@tonic-gate static char *authmethods_get(void);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate Authmethod authmethods[] = {
264*0Sstevel@tonic-gate #ifdef GSSAPI
265*0Sstevel@tonic-gate 	{"gssapi-keyex",
266*0Sstevel@tonic-gate 		userauth_gssapi_keyex,
267*0Sstevel@tonic-gate 		userauth_gssapi_cleanup,
268*0Sstevel@tonic-gate 		&options.gss_keyex,
269*0Sstevel@tonic-gate 		NULL},
270*0Sstevel@tonic-gate 	{"gssapi-with-mic",
271*0Sstevel@tonic-gate 		userauth_gssapi,
272*0Sstevel@tonic-gate 		userauth_gssapi_cleanup,
273*0Sstevel@tonic-gate 		&options.gss_authentication,
274*0Sstevel@tonic-gate 		NULL},
275*0Sstevel@tonic-gate #endif /* GSSAPI */
276*0Sstevel@tonic-gate 	{"hostbased",
277*0Sstevel@tonic-gate 		userauth_hostbased,
278*0Sstevel@tonic-gate 		NULL,
279*0Sstevel@tonic-gate 		&options.hostbased_authentication,
280*0Sstevel@tonic-gate 		NULL},
281*0Sstevel@tonic-gate 	{"publickey",
282*0Sstevel@tonic-gate 		userauth_pubkey,
283*0Sstevel@tonic-gate 		NULL,
284*0Sstevel@tonic-gate 		&options.pubkey_authentication,
285*0Sstevel@tonic-gate 		NULL},
286*0Sstevel@tonic-gate 	{"keyboard-interactive",
287*0Sstevel@tonic-gate 		userauth_kbdint,
288*0Sstevel@tonic-gate 		NULL,
289*0Sstevel@tonic-gate 		&options.kbd_interactive_authentication,
290*0Sstevel@tonic-gate 		&options.batch_mode},
291*0Sstevel@tonic-gate 	{"password",
292*0Sstevel@tonic-gate 		userauth_passwd,
293*0Sstevel@tonic-gate 		NULL,
294*0Sstevel@tonic-gate 		&options.password_authentication,
295*0Sstevel@tonic-gate 		&options.batch_mode},
296*0Sstevel@tonic-gate 	{"none",
297*0Sstevel@tonic-gate 		userauth_none,
298*0Sstevel@tonic-gate 		NULL,
299*0Sstevel@tonic-gate 		NULL,
300*0Sstevel@tonic-gate 		NULL},
301*0Sstevel@tonic-gate 	{NULL, NULL, NULL, NULL, NULL}
302*0Sstevel@tonic-gate };
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate void
305*0Sstevel@tonic-gate ssh_userauth2(const char *local_user, const char *server_user, char *host,
306*0Sstevel@tonic-gate     Sensitive *sensitive)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	Authctxt authctxt;
309*0Sstevel@tonic-gate 	int type;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	if (options.challenge_response_authentication)
312*0Sstevel@tonic-gate 		options.kbd_interactive_authentication = 1;
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_SERVICE_REQUEST);
315*0Sstevel@tonic-gate 	packet_put_cstring("ssh-userauth");
316*0Sstevel@tonic-gate 	packet_send();
317*0Sstevel@tonic-gate 	debug("send SSH2_MSG_SERVICE_REQUEST");
318*0Sstevel@tonic-gate 	packet_write_wait();
319*0Sstevel@tonic-gate 	type = packet_read();
320*0Sstevel@tonic-gate 	if (type != SSH2_MSG_SERVICE_ACCEPT)
321*0Sstevel@tonic-gate 		fatal("Server denied authentication request: %d", type);
322*0Sstevel@tonic-gate 	if (packet_remaining() > 0) {
323*0Sstevel@tonic-gate 		char *reply = packet_get_string(NULL);
324*0Sstevel@tonic-gate 		debug2("service_accept: %s", reply);
325*0Sstevel@tonic-gate 		xfree(reply);
326*0Sstevel@tonic-gate 	} else {
327*0Sstevel@tonic-gate 		debug2("buggy server: service_accept w/o service");
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 	packet_check_eom();
330*0Sstevel@tonic-gate 	debug("got SSH2_MSG_SERVICE_ACCEPT");
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	if (options.preferred_authentications == NULL)
333*0Sstevel@tonic-gate 		options.preferred_authentications = authmethods_get();
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/* setup authentication context */
336*0Sstevel@tonic-gate 	memset(&authctxt, 0, sizeof(authctxt));
337*0Sstevel@tonic-gate 	authctxt.agent = ssh_get_authentication_connection();
338*0Sstevel@tonic-gate 	authctxt.server_user = server_user;
339*0Sstevel@tonic-gate 	authctxt.local_user = local_user;
340*0Sstevel@tonic-gate 	authctxt.host = host;
341*0Sstevel@tonic-gate 	authctxt.service = "ssh-connection";		/* service name */
342*0Sstevel@tonic-gate 	authctxt.success = 0;
343*0Sstevel@tonic-gate 	authctxt.method = authmethod_lookup("none");
344*0Sstevel@tonic-gate 	authctxt.authlist = NULL;
345*0Sstevel@tonic-gate 	authctxt.methoddata = NULL;
346*0Sstevel@tonic-gate 	authctxt.sensitive = sensitive;
347*0Sstevel@tonic-gate 	authctxt.info_req_seen = 0;
348*0Sstevel@tonic-gate 	if (authctxt.method == NULL)
349*0Sstevel@tonic-gate 		fatal("ssh_userauth2: internal error: cannot send userauth none request");
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	/* initial userauth request */
352*0Sstevel@tonic-gate 	userauth_none(&authctxt);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 	dispatch_init(&input_userauth_error);
355*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
356*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure);
357*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
358*0Sstevel@tonic-gate 	dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);	/* loop until success */
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	if (authctxt.agent != NULL)
361*0Sstevel@tonic-gate 		ssh_close_authentication_connection(authctxt.agent);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	debug("Authentication succeeded (%s)", authctxt.method->name);
364*0Sstevel@tonic-gate }
365*0Sstevel@tonic-gate void
366*0Sstevel@tonic-gate userauth(Authctxt *authctxt, char *authlist)
367*0Sstevel@tonic-gate {
368*0Sstevel@tonic-gate 	if (authctxt->method != NULL &&
369*0Sstevel@tonic-gate 	    authctxt->method->cleanup != NULL)
370*0Sstevel@tonic-gate 		authctxt->method->cleanup(authctxt);
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	if (authlist == NULL) {
373*0Sstevel@tonic-gate 		authlist = authctxt->authlist;
374*0Sstevel@tonic-gate 	} else {
375*0Sstevel@tonic-gate 		if (authctxt->authlist)
376*0Sstevel@tonic-gate 			xfree(authctxt->authlist);
377*0Sstevel@tonic-gate 		authctxt->authlist = authlist;
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 	for (;;) {
380*0Sstevel@tonic-gate 		Authmethod *method = authmethod_get(authlist);
381*0Sstevel@tonic-gate 		if (method == NULL)
382*0Sstevel@tonic-gate 			fatal("Permission denied (%s).", authlist);
383*0Sstevel@tonic-gate 		authctxt->method = method;
384*0Sstevel@tonic-gate 		if (method->userauth(authctxt) != 0) {
385*0Sstevel@tonic-gate 			debug2("we sent a %s packet, wait for reply", method->name);
386*0Sstevel@tonic-gate 			break;
387*0Sstevel@tonic-gate 		} else {
388*0Sstevel@tonic-gate 			debug2("we did not send a packet, disable method");
389*0Sstevel@tonic-gate 			method->enabled = NULL;
390*0Sstevel@tonic-gate 		}
391*0Sstevel@tonic-gate 	}
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate void
395*0Sstevel@tonic-gate input_userauth_error(int type, u_int32_t seq, void *ctxt)
396*0Sstevel@tonic-gate {
397*0Sstevel@tonic-gate 	fatal("input_userauth_error: bad message during authentication: "
398*0Sstevel@tonic-gate 	   "type %d", type);
399*0Sstevel@tonic-gate }
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate void
402*0Sstevel@tonic-gate input_userauth_banner(int type, u_int32_t seq, void *ctxt)
403*0Sstevel@tonic-gate {
404*0Sstevel@tonic-gate 	char *msg, *lang;
405*0Sstevel@tonic-gate 	debug3("input_userauth_banner");
406*0Sstevel@tonic-gate 	msg = packet_get_string(NULL);
407*0Sstevel@tonic-gate 	lang = packet_get_string(NULL);
408*0Sstevel@tonic-gate 	fprintf(stderr, "%s", msg);
409*0Sstevel@tonic-gate 	xfree(msg);
410*0Sstevel@tonic-gate 	xfree(lang);
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate void
414*0Sstevel@tonic-gate input_userauth_success(int type, u_int32_t seq, void *ctxt)
415*0Sstevel@tonic-gate {
416*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
417*0Sstevel@tonic-gate 	if (authctxt == NULL)
418*0Sstevel@tonic-gate 		fatal("input_userauth_success: no authentication context");
419*0Sstevel@tonic-gate 	if (authctxt->authlist)
420*0Sstevel@tonic-gate 		xfree(authctxt->authlist);
421*0Sstevel@tonic-gate 	if (authctxt->method != NULL &&
422*0Sstevel@tonic-gate 	    authctxt->method->cleanup != NULL)
423*0Sstevel@tonic-gate 		authctxt->method->cleanup(authctxt);
424*0Sstevel@tonic-gate 	clear_auth_state(authctxt);
425*0Sstevel@tonic-gate 	authctxt->success = 1;			/* break out */
426*0Sstevel@tonic-gate }
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate void
429*0Sstevel@tonic-gate input_userauth_failure(int type, u_int32_t seq, void *ctxt)
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
432*0Sstevel@tonic-gate 	char *authlist = NULL;
433*0Sstevel@tonic-gate 	int partial;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if (authctxt == NULL)
436*0Sstevel@tonic-gate 		fatal("input_userauth_failure: no authentication context");
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	authlist = packet_get_string(NULL);
439*0Sstevel@tonic-gate 	partial = packet_get_char();
440*0Sstevel@tonic-gate 	packet_check_eom();
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	if (partial != 0)
443*0Sstevel@tonic-gate 		log("Authenticated with partial success.");
444*0Sstevel@tonic-gate 	debug("Authentications that can continue: %s", authlist);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	clear_auth_state(authctxt);
447*0Sstevel@tonic-gate 	userauth(authctxt, authlist);
448*0Sstevel@tonic-gate }
449*0Sstevel@tonic-gate void
450*0Sstevel@tonic-gate input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
451*0Sstevel@tonic-gate {
452*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
453*0Sstevel@tonic-gate 	Key *key = NULL;
454*0Sstevel@tonic-gate 	Buffer b;
455*0Sstevel@tonic-gate 	int pktype, sent = 0;
456*0Sstevel@tonic-gate 	u_int alen, blen;
457*0Sstevel@tonic-gate 	char *pkalg, *fp;
458*0Sstevel@tonic-gate 	u_char *pkblob;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	if (authctxt == NULL)
461*0Sstevel@tonic-gate 		fatal("input_userauth_pk_ok: no authentication context");
462*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_PKOK) {
463*0Sstevel@tonic-gate 		/* this is similar to SSH_BUG_PKAUTH */
464*0Sstevel@tonic-gate 		debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
465*0Sstevel@tonic-gate 		pkblob = packet_get_string(&blen);
466*0Sstevel@tonic-gate 		buffer_init(&b);
467*0Sstevel@tonic-gate 		buffer_append(&b, pkblob, blen);
468*0Sstevel@tonic-gate 		pkalg = buffer_get_string(&b, &alen);
469*0Sstevel@tonic-gate 		buffer_free(&b);
470*0Sstevel@tonic-gate 	} else {
471*0Sstevel@tonic-gate 		pkalg = packet_get_string(&alen);
472*0Sstevel@tonic-gate 		pkblob = packet_get_string(&blen);
473*0Sstevel@tonic-gate 	}
474*0Sstevel@tonic-gate 	packet_check_eom();
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d",
477*0Sstevel@tonic-gate 	    pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	do {
480*0Sstevel@tonic-gate 		if (authctxt->last_key == NULL ||
481*0Sstevel@tonic-gate 		    authctxt->last_key_sign == NULL) {
482*0Sstevel@tonic-gate 			debug("no last key or no sign cb");
483*0Sstevel@tonic-gate 			break;
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 		if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
486*0Sstevel@tonic-gate 			debug("unknown pkalg %s", pkalg);
487*0Sstevel@tonic-gate 			break;
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 		if ((key = key_from_blob(pkblob, blen)) == NULL) {
490*0Sstevel@tonic-gate 			debug("no key from blob. pkalg %s", pkalg);
491*0Sstevel@tonic-gate 			break;
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 		if (key->type != pktype) {
494*0Sstevel@tonic-gate 			error("input_userauth_pk_ok: type mismatch "
495*0Sstevel@tonic-gate 			    "for decoded key (received %d, expected %d)",
496*0Sstevel@tonic-gate 			    key->type, pktype);
497*0Sstevel@tonic-gate 			break;
498*0Sstevel@tonic-gate 		}
499*0Sstevel@tonic-gate 		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
500*0Sstevel@tonic-gate 		debug2("input_userauth_pk_ok: fp %s", fp);
501*0Sstevel@tonic-gate 		xfree(fp);
502*0Sstevel@tonic-gate 		if (!key_equal(key, authctxt->last_key)) {
503*0Sstevel@tonic-gate 			debug("key != last_key");
504*0Sstevel@tonic-gate 			break;
505*0Sstevel@tonic-gate 		}
506*0Sstevel@tonic-gate 		sent = sign_and_send_pubkey(authctxt, key,
507*0Sstevel@tonic-gate 		   authctxt->last_key_sign);
508*0Sstevel@tonic-gate 	} while (0);
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	if (key != NULL)
511*0Sstevel@tonic-gate 		key_free(key);
512*0Sstevel@tonic-gate 	xfree(pkalg);
513*0Sstevel@tonic-gate 	xfree(pkblob);
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	/* unregister */
516*0Sstevel@tonic-gate 	clear_auth_state(authctxt);
517*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	/* try another method if we did not send a packet */
520*0Sstevel@tonic-gate 	if (sent == 0)
521*0Sstevel@tonic-gate 		userauth(authctxt, NULL);
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate }
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate #ifdef GSSAPI
526*0Sstevel@tonic-gate int
527*0Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt)
528*0Sstevel@tonic-gate {
529*0Sstevel@tonic-gate 	Gssctxt *gssctxt = NULL;
530*0Sstevel@tonic-gate 	static int initialized = 0;
531*0Sstevel@tonic-gate 	static int mech_idx = 0;
532*0Sstevel@tonic-gate 	static gss_OID_set supported = GSS_C_NULL_OID_SET;
533*0Sstevel@tonic-gate 	gss_OID mech = GSS_C_NULL_OID;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	/* Things work better if we send one mechanism at a time, rather
536*0Sstevel@tonic-gate 	 * than them all at once. This means that if we fail at some point
537*0Sstevel@tonic-gate 	 * in the middle of a negotiation, we can come back and try something
538*0Sstevel@tonic-gate 	 * different. */
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 	if (datafellows & SSH_OLD_GSSAPI) return 0;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	/* Before we offer a mechanism, check that we can support it. Don't
543*0Sstevel@tonic-gate 	 * bother trying to get credentials - as the standard fallback will
544*0Sstevel@tonic-gate 	 * deal with that kind of failure.
545*0Sstevel@tonic-gate 	 */
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	if (!initialized) {
548*0Sstevel@tonic-gate 		initialized = 1;
549*0Sstevel@tonic-gate 		ssh_gssapi_client_mechs(authctxt->host, &supported);
550*0Sstevel@tonic-gate 		if (supported == GSS_C_NULL_OID_SET || supported->count == 0)
551*0Sstevel@tonic-gate 			return (0);
552*0Sstevel@tonic-gate 	} else if (supported != GSS_C_NULL_OID_SET) {
553*0Sstevel@tonic-gate 		/* Try next mech, if any */
554*0Sstevel@tonic-gate 		mech_idx++;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 		if (mech_idx >= supported->count)
557*0Sstevel@tonic-gate 			return (0);
558*0Sstevel@tonic-gate 	} else {
559*0Sstevel@tonic-gate 		return (0);
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	mech = &supported->elements[mech_idx];
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	ssh_gssapi_build_ctx(&gssctxt, 1, mech);
565*0Sstevel@tonic-gate 	authctxt->methoddata=(void *)gssctxt;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
568*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
569*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
570*0Sstevel@tonic-gate         packet_put_cstring(authctxt->method->name);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	packet_put_int(1);
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	/* The newest gsskeyex draft stipulates that OIDs should
575*0Sstevel@tonic-gate 	 * be DER encoded, so we need to add the object type and
576*0Sstevel@tonic-gate 	 * length information back on */
577*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_GSSAPI_BER) {
578*0Sstevel@tonic-gate 		packet_put_string(mech->elements, mech->length);
579*0Sstevel@tonic-gate 	} else {
580*0Sstevel@tonic-gate 		packet_put_int((mech->length)+2);
581*0Sstevel@tonic-gate 		packet_put_char(0x06);
582*0Sstevel@tonic-gate 		packet_put_char(mech->length);
583*0Sstevel@tonic-gate 		packet_put_raw(mech->elements, mech->length);
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate         packet_send();
587*0Sstevel@tonic-gate         packet_write_wait();
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate         return 1;
592*0Sstevel@tonic-gate }
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate void
595*0Sstevel@tonic-gate input_gssapi_response(int type, u_int32_t plen, void *ctxt)
596*0Sstevel@tonic-gate {
597*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
598*0Sstevel@tonic-gate 	Gssctxt *gssctxt;
599*0Sstevel@tonic-gate 	OM_uint32 status,ms;
600*0Sstevel@tonic-gate 	u_int oidlen;
601*0Sstevel@tonic-gate 	char *oidv;
602*0Sstevel@tonic-gate 	gss_buffer_desc send_tok;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	if (authctxt == NULL)
605*0Sstevel@tonic-gate 		fatal("input_gssapi_response: no authentication context");
606*0Sstevel@tonic-gate 	gssctxt = authctxt->methoddata;
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	/* Setup our OID */
609*0Sstevel@tonic-gate 	oidv=packet_get_string(&oidlen);
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_GSSAPI_BER) {
612*0Sstevel@tonic-gate 		if (!ssh_gssapi_check_mech_oid(gssctxt,oidv,oidlen)) {
613*0Sstevel@tonic-gate 			gss_OID oid;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 			oid = ssh_gssapi_make_oid(oidlen, oidv);
616*0Sstevel@tonic-gate 			debug("Server returned different OID (%s) than expected (%s)",
617*0Sstevel@tonic-gate 				ssh_gssapi_oid_to_str(oid),
618*0Sstevel@tonic-gate 				ssh_gssapi_oid_to_str(gssctxt->desired_mech));
619*0Sstevel@tonic-gate 			ssh_gssapi_release_oid(&oid);
620*0Sstevel@tonic-gate 			clear_auth_state(authctxt);
621*0Sstevel@tonic-gate 			userauth(authctxt,NULL);
622*0Sstevel@tonic-gate 			return;
623*0Sstevel@tonic-gate 		}
624*0Sstevel@tonic-gate 	} else {
625*0Sstevel@tonic-gate 		if(oidv[0]!=0x06 || oidv[1]!=oidlen-2) {
626*0Sstevel@tonic-gate 			debug("Badly encoded mechanism OID received");
627*0Sstevel@tonic-gate 			clear_auth_state(authctxt);
628*0Sstevel@tonic-gate 			userauth(authctxt,NULL);
629*0Sstevel@tonic-gate 			return;
630*0Sstevel@tonic-gate 		}
631*0Sstevel@tonic-gate 		if (!ssh_gssapi_check_mech_oid(gssctxt,oidv+2,oidlen-2)) {
632*0Sstevel@tonic-gate 			gss_OID oid;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 			oid = ssh_gssapi_make_oid(oidlen-2, oidv+2);
635*0Sstevel@tonic-gate 			debug("Server returned different OID (%s) than expected (%s)",
636*0Sstevel@tonic-gate 				ssh_gssapi_oid_to_str(oid),
637*0Sstevel@tonic-gate 				ssh_gssapi_oid_to_str(gssctxt->desired_mech));
638*0Sstevel@tonic-gate 			clear_auth_state(authctxt);
639*0Sstevel@tonic-gate 			userauth(authctxt,NULL);
640*0Sstevel@tonic-gate 			return;
641*0Sstevel@tonic-gate 		}
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 	packet_check_eom();
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
647*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,&input_gssapi_error);
648*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,&input_gssapi_errtok);
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	status = ssh_gssapi_init_ctx(gssctxt, authctxt->host,
651*0Sstevel@tonic-gate 					options.gss_deleg_creds,
652*0Sstevel@tonic-gate 					GSS_C_NO_BUFFER, &send_tok);
653*0Sstevel@tonic-gate 	if (GSS_ERROR(status)) {
654*0Sstevel@tonic-gate 		if (send_tok.length>0) {
655*0Sstevel@tonic-gate 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
656*0Sstevel@tonic-gate 			packet_put_string(send_tok.value,send_tok.length);
657*0Sstevel@tonic-gate 			packet_send();
658*0Sstevel@tonic-gate 			packet_write_wait();
659*0Sstevel@tonic-gate 		}
660*0Sstevel@tonic-gate 		/* Start again with next method on list */
661*0Sstevel@tonic-gate 		debug("Trying to start again");
662*0Sstevel@tonic-gate 		clear_auth_state(authctxt);
663*0Sstevel@tonic-gate 		userauth(authctxt,NULL);
664*0Sstevel@tonic-gate 		return;
665*0Sstevel@tonic-gate 	}
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	/* We must have data to send */
668*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
669*0Sstevel@tonic-gate 	packet_put_string(send_tok.value,send_tok.length);
670*0Sstevel@tonic-gate 	packet_send();
671*0Sstevel@tonic-gate 	packet_write_wait();
672*0Sstevel@tonic-gate 	gss_release_buffer(&ms, &send_tok);
673*0Sstevel@tonic-gate }
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate void
676*0Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt)
677*0Sstevel@tonic-gate {
678*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
679*0Sstevel@tonic-gate 	Gssctxt *gssctxt;
680*0Sstevel@tonic-gate 	gss_buffer_desc send_tok, recv_tok, g_mic_data;
681*0Sstevel@tonic-gate 	Buffer mic_data;
682*0Sstevel@tonic-gate 	OM_uint32 status;
683*0Sstevel@tonic-gate 	u_int slen;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL)
686*0Sstevel@tonic-gate 		fatal("input_gssapi_response: no authentication context");
687*0Sstevel@tonic-gate 	gssctxt = authctxt->methoddata;
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 	recv_tok.value=packet_get_string(&slen);
690*0Sstevel@tonic-gate 	recv_tok.length=slen;	/* safe typecast */
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	status=ssh_gssapi_init_ctx(gssctxt, authctxt->host,
693*0Sstevel@tonic-gate 					options.gss_deleg_creds,
694*0Sstevel@tonic-gate 					&recv_tok, &send_tok);
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	packet_check_eom();
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (GSS_ERROR(status)) {
699*0Sstevel@tonic-gate 		if (send_tok.length>0) {
700*0Sstevel@tonic-gate 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
701*0Sstevel@tonic-gate 			packet_put_string(send_tok.value,send_tok.length);
702*0Sstevel@tonic-gate 			packet_send();
703*0Sstevel@tonic-gate 			packet_write_wait();
704*0Sstevel@tonic-gate 		}
705*0Sstevel@tonic-gate 		/* Start again with the next method in the list */
706*0Sstevel@tonic-gate 		clear_auth_state(authctxt);
707*0Sstevel@tonic-gate 		userauth(authctxt,NULL);
708*0Sstevel@tonic-gate 		return;
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	if (send_tok.length>0) {
712*0Sstevel@tonic-gate 		packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
713*0Sstevel@tonic-gate 		packet_put_string(send_tok.value,send_tok.length);
714*0Sstevel@tonic-gate 		packet_send();
715*0Sstevel@tonic-gate 		packet_write_wait();
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	if (status != GSS_S_COMPLETE)
719*0Sstevel@tonic-gate 		return;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	/* Make data buffer to MIC */
722*0Sstevel@tonic-gate 	buffer_init(&mic_data);
723*0Sstevel@tonic-gate 	buffer_put_string(&mic_data, session_id2, session_id2_len);
724*0Sstevel@tonic-gate 	buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
725*0Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->server_user);
726*0Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->service);
727*0Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->method->name);
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	/* Make MIC */
730*0Sstevel@tonic-gate 	g_mic_data.value  = buffer_ptr(&mic_data);
731*0Sstevel@tonic-gate 	g_mic_data.length = buffer_len(&mic_data);
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	status = ssh_gssapi_get_mic(gssctxt, &g_mic_data, &send_tok);
734*0Sstevel@tonic-gate 	buffer_clear(&mic_data);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	if (GSS_ERROR(status) || send_tok.length == 0) {
737*0Sstevel@tonic-gate 		/*
738*0Sstevel@tonic-gate 		 * Oops, now what?  There's no error token...
739*0Sstevel@tonic-gate 		 * Next userauth
740*0Sstevel@tonic-gate 		 */
741*0Sstevel@tonic-gate 		debug("GSS_GetMIC() failed! - "
742*0Sstevel@tonic-gate 		      "Abandoning GSSAPI userauth");
743*0Sstevel@tonic-gate 		clear_auth_state(authctxt);
744*0Sstevel@tonic-gate 		userauth(authctxt,NULL);
745*0Sstevel@tonic-gate 		return;
746*0Sstevel@tonic-gate 	}
747*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);
748*0Sstevel@tonic-gate 	packet_put_string(send_tok.value,send_tok.length);
749*0Sstevel@tonic-gate 	packet_send();
750*0Sstevel@tonic-gate 	packet_write_wait();
751*0Sstevel@tonic-gate }
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate void
754*0Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
755*0Sstevel@tonic-gate {
756*0Sstevel@tonic-gate 	OM_uint32 min_status;
757*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
758*0Sstevel@tonic-gate 	Gssctxt *gssctxt;
759*0Sstevel@tonic-gate 	gss_buffer_desc send_tok, recv_tok;
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (authctxt == NULL)
762*0Sstevel@tonic-gate 		fatal("input_gssapi_response: no authentication context");
763*0Sstevel@tonic-gate 	gssctxt = authctxt->methoddata;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	recv_tok.value=packet_get_string(&recv_tok.length);
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/* Stick it into GSSAPI and see what it says */
768*0Sstevel@tonic-gate 	(void) ssh_gssapi_init_ctx(gssctxt, authctxt->host,
769*0Sstevel@tonic-gate 					options.gss_deleg_creds,
770*0Sstevel@tonic-gate 					&recv_tok, &send_tok);
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	xfree(recv_tok.value);
773*0Sstevel@tonic-gate 	(void) gss_release_buffer(&min_status, &send_tok);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	debug("Server sent a GSS-API error token during GSS userauth -- %s",
776*0Sstevel@tonic-gate 		ssh_gssapi_last_error(gssctxt, NULL, NULL));
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	packet_check_eom();
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	/* We can't send a packet to the server */
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	/* The draft says that we should wait for the server to fail
783*0Sstevel@tonic-gate 	 * before starting the next authentication. So, we clear the
784*0Sstevel@tonic-gate 	 * state, but don't do anything else
785*0Sstevel@tonic-gate 	 */
786*0Sstevel@tonic-gate 	clear_auth_state(authctxt);
787*0Sstevel@tonic-gate 	return;
788*0Sstevel@tonic-gate }
789*0Sstevel@tonic-gate 
790*0Sstevel@tonic-gate void
791*0Sstevel@tonic-gate input_gssapi_error(int type, u_int32_t plen, void *ctxt)
792*0Sstevel@tonic-gate {
793*0Sstevel@tonic-gate 	OM_uint32 maj,min;
794*0Sstevel@tonic-gate 	char *msg;
795*0Sstevel@tonic-gate 	char *lang;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	maj = packet_get_int();
798*0Sstevel@tonic-gate 	min = packet_get_int();
799*0Sstevel@tonic-gate 	msg = packet_get_string(NULL);
800*0Sstevel@tonic-gate 	lang = packet_get_string(NULL);
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	packet_check_eom();
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	fprintf(stderr, "Server GSSAPI Error:\n%s (%d, %d)\n", msg, maj, min);
805*0Sstevel@tonic-gate 	xfree(msg);
806*0Sstevel@tonic-gate 	xfree(lang);
807*0Sstevel@tonic-gate }
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate int
810*0Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt)
811*0Sstevel@tonic-gate {
812*0Sstevel@tonic-gate 	Gssctxt *gssctxt;
813*0Sstevel@tonic-gate 	gss_buffer_desc send_tok;
814*0Sstevel@tonic-gate 	OM_uint32 status;
815*0Sstevel@tonic-gate         static int attempt = 0;
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL)
818*0Sstevel@tonic-gate 		fatal("input_gssapi_response: no authentication context");
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT)
821*0Sstevel@tonic-gate 		return 0;
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	if (strcmp(authctxt->method->name, "gssapi-keyex") == 0)
824*0Sstevel@tonic-gate 		authctxt->methoddata = gssctxt = xxx_gssctxt;
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate         if (attempt++ >= 1)
827*0Sstevel@tonic-gate         	return 0;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	if (strcmp(authctxt->method->name, "gssapi-keyex") == 0) {
830*0Sstevel@tonic-gate 		gss_buffer_desc g_mic_data;
831*0Sstevel@tonic-gate 		Buffer mic_data;
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 		debug2("Authenticating with GSS-API context from key exchange (w/ MIC)");
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 		/* Make data buffer to MIC */
836*0Sstevel@tonic-gate 		buffer_init(&mic_data);
837*0Sstevel@tonic-gate 		buffer_put_string(&mic_data, session_id2, session_id2_len);
838*0Sstevel@tonic-gate 		buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
839*0Sstevel@tonic-gate 		buffer_put_cstring(&mic_data, authctxt->server_user);
840*0Sstevel@tonic-gate 		buffer_put_cstring(&mic_data, authctxt->service);
841*0Sstevel@tonic-gate 		buffer_put_cstring(&mic_data, authctxt->method->name);
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 		/* Make MIC */
844*0Sstevel@tonic-gate 		g_mic_data.value  = buffer_ptr(&mic_data);
845*0Sstevel@tonic-gate 		g_mic_data.length = buffer_len(&mic_data);
846*0Sstevel@tonic-gate 		status = ssh_gssapi_get_mic(gssctxt, &g_mic_data, &send_tok);
847*0Sstevel@tonic-gate 		buffer_clear(&mic_data);
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 		if (GSS_ERROR(status) || send_tok.length == 0) {
850*0Sstevel@tonic-gate 			/*
851*0Sstevel@tonic-gate 			 * Oops, now what?  There's no error token...
852*0Sstevel@tonic-gate 			 * Next userauth
853*0Sstevel@tonic-gate 			 */
854*0Sstevel@tonic-gate 			debug("GSS_GetMIC() failed! - "
855*0Sstevel@tonic-gate 			      "Abandoning GSSAPI userauth");
856*0Sstevel@tonic-gate 			clear_auth_state(authctxt);
857*0Sstevel@tonic-gate 			userauth(authctxt,NULL);
858*0Sstevel@tonic-gate 			return 0;
859*0Sstevel@tonic-gate 		}
860*0Sstevel@tonic-gate 		packet_start(SSH2_MSG_USERAUTH_REQUEST);
861*0Sstevel@tonic-gate 		packet_put_cstring(authctxt->server_user);
862*0Sstevel@tonic-gate 		packet_put_cstring(authctxt->service);
863*0Sstevel@tonic-gate 		packet_put_cstring(authctxt->method->name);
864*0Sstevel@tonic-gate 		packet_put_string(send_tok.value,send_tok.length); /* MIC */
865*0Sstevel@tonic-gate 		packet_send();
866*0Sstevel@tonic-gate 		packet_write_wait();
867*0Sstevel@tonic-gate 		(void) gss_release_buffer(&status, &send_tok);
868*0Sstevel@tonic-gate 	} else if (strcmp(authctxt->method->name, "external-keyx") == 0) {
869*0Sstevel@tonic-gate 		debug2("Authentication with deprecated \"external-keyx\""
870*0Sstevel@tonic-gate 			" method not supported");
871*0Sstevel@tonic-gate 		return 0;
872*0Sstevel@tonic-gate 	}
873*0Sstevel@tonic-gate         return 1;
874*0Sstevel@tonic-gate }
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate static
877*0Sstevel@tonic-gate void
878*0Sstevel@tonic-gate userauth_gssapi_cleanup(Authctxt *authctxt)
879*0Sstevel@tonic-gate {
880*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL);
881*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
882*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL);
883*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL);
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 	if (authctxt == NULL ||
886*0Sstevel@tonic-gate 	    authctxt->method == NULL ||
887*0Sstevel@tonic-gate 	    authctxt->methoddata == NULL)
888*0Sstevel@tonic-gate 		return;
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 	if (strncmp(authctxt->method->name, "gssapi", strlen("gssapi")) == 0) {
891*0Sstevel@tonic-gate 		ssh_gssapi_delete_ctx((Gssctxt **)&authctxt->methoddata);
892*0Sstevel@tonic-gate 	}
893*0Sstevel@tonic-gate }
894*0Sstevel@tonic-gate #endif /* GSSAPI */
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate int
897*0Sstevel@tonic-gate userauth_none(Authctxt *authctxt)
898*0Sstevel@tonic-gate {
899*0Sstevel@tonic-gate 	/* initial userauth request */
900*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
901*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
902*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
903*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
904*0Sstevel@tonic-gate 	packet_send();
905*0Sstevel@tonic-gate 	return 1;
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate }
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate int
910*0Sstevel@tonic-gate userauth_passwd(Authctxt *authctxt)
911*0Sstevel@tonic-gate {
912*0Sstevel@tonic-gate 	static int attempt = 0;
913*0Sstevel@tonic-gate 	char prompt[150];
914*0Sstevel@tonic-gate 	char *password;
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	if (attempt++ >= options.number_of_password_prompts)
917*0Sstevel@tonic-gate 		return 0;
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	if (attempt != 1)
920*0Sstevel@tonic-gate 		error("Permission denied, please try again.");
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	snprintf(prompt, sizeof(prompt), gettext("%.30s@%.128s's password: "),
923*0Sstevel@tonic-gate 	    authctxt->server_user, authctxt->host);
924*0Sstevel@tonic-gate 	password = read_passphrase(prompt, 0);
925*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
926*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
927*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
928*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
929*0Sstevel@tonic-gate 	packet_put_char(0);
930*0Sstevel@tonic-gate 	packet_put_cstring(password);
931*0Sstevel@tonic-gate 	memset(password, 0, strlen(password));
932*0Sstevel@tonic-gate 	xfree(password);
933*0Sstevel@tonic-gate 	packet_add_padding(64);
934*0Sstevel@tonic-gate 	packet_send();
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
937*0Sstevel@tonic-gate 	    &input_userauth_passwd_changereq);
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 	return 1;
940*0Sstevel@tonic-gate }
941*0Sstevel@tonic-gate /*
942*0Sstevel@tonic-gate  * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
943*0Sstevel@tonic-gate  */
944*0Sstevel@tonic-gate void
945*0Sstevel@tonic-gate input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
946*0Sstevel@tonic-gate {
947*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
948*0Sstevel@tonic-gate 	char *info, *lang, *password = NULL, *retype = NULL;
949*0Sstevel@tonic-gate 	char prompt[150];
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 	debug2("input_userauth_passwd_changereq");
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	if (authctxt == NULL)
954*0Sstevel@tonic-gate 		fatal("input_userauth_passwd_changereq: "
955*0Sstevel@tonic-gate 		    "no authentication context");
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	info = packet_get_string(NULL);
958*0Sstevel@tonic-gate 	lang = packet_get_string(NULL);
959*0Sstevel@tonic-gate 	if (strlen(info) > 0)
960*0Sstevel@tonic-gate 		log("%s", info);
961*0Sstevel@tonic-gate 	xfree(info);
962*0Sstevel@tonic-gate 	xfree(lang);
963*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
964*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
965*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
966*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
967*0Sstevel@tonic-gate 	packet_put_char(1);			/* additional info */
968*0Sstevel@tonic-gate 	snprintf(prompt, sizeof(prompt),
969*0Sstevel@tonic-gate 	    gettext("Enter %.30s@%.128s's old password: "),
970*0Sstevel@tonic-gate 	    authctxt->server_user, authctxt->host);
971*0Sstevel@tonic-gate 	password = read_passphrase(prompt, 0);
972*0Sstevel@tonic-gate 	packet_put_cstring(password);
973*0Sstevel@tonic-gate 	memset(password, 0, strlen(password));
974*0Sstevel@tonic-gate 	xfree(password);
975*0Sstevel@tonic-gate 	password = NULL;
976*0Sstevel@tonic-gate 	while (password == NULL) {
977*0Sstevel@tonic-gate 		snprintf(prompt, sizeof(prompt),
978*0Sstevel@tonic-gate 		    gettext("Enter %.30s@%.128s's new password: "),
979*0Sstevel@tonic-gate 		    authctxt->server_user, authctxt->host);
980*0Sstevel@tonic-gate 		password = read_passphrase(prompt, RP_ALLOW_EOF);
981*0Sstevel@tonic-gate 		if (password == NULL) {
982*0Sstevel@tonic-gate 			/* bail out */
983*0Sstevel@tonic-gate 			return;
984*0Sstevel@tonic-gate 		}
985*0Sstevel@tonic-gate 		snprintf(prompt, sizeof(prompt),
986*0Sstevel@tonic-gate 		    gettext("Retype %.30s@%.128s's new password: "),
987*0Sstevel@tonic-gate 		    authctxt->server_user, authctxt->host);
988*0Sstevel@tonic-gate 		retype = read_passphrase(prompt, 0);
989*0Sstevel@tonic-gate 		if (strcmp(password, retype) != 0) {
990*0Sstevel@tonic-gate 			memset(password, 0, strlen(password));
991*0Sstevel@tonic-gate 			xfree(password);
992*0Sstevel@tonic-gate 			log("Mismatch; try again, EOF to quit.");
993*0Sstevel@tonic-gate 			password = NULL;
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 		memset(retype, 0, strlen(retype));
996*0Sstevel@tonic-gate 		xfree(retype);
997*0Sstevel@tonic-gate 	}
998*0Sstevel@tonic-gate 	packet_put_cstring(password);
999*0Sstevel@tonic-gate 	memset(password, 0, strlen(password));
1000*0Sstevel@tonic-gate 	xfree(password);
1001*0Sstevel@tonic-gate 	packet_add_padding(64);
1002*0Sstevel@tonic-gate 	packet_send();
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
1005*0Sstevel@tonic-gate 	    &input_userauth_passwd_changereq);
1006*0Sstevel@tonic-gate }
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate static void
1009*0Sstevel@tonic-gate clear_auth_state(Authctxt *authctxt)
1010*0Sstevel@tonic-gate {
1011*0Sstevel@tonic-gate 	/* XXX clear authentication state */
1012*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
1013*0Sstevel@tonic-gate #ifdef GSSAPI
1014*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL);
1015*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
1016*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL);
1017*0Sstevel@tonic-gate #endif /* GSSAPI */
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
1020*0Sstevel@tonic-gate 		debug3("clear_auth_state: key_free %p", authctxt->last_key);
1021*0Sstevel@tonic-gate 		key_free(authctxt->last_key);
1022*0Sstevel@tonic-gate 	}
1023*0Sstevel@tonic-gate 	authctxt->last_key = NULL;
1024*0Sstevel@tonic-gate 	authctxt->last_key_hint = -2;
1025*0Sstevel@tonic-gate 	authctxt->last_key_sign = NULL;
1026*0Sstevel@tonic-gate }
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate static int
1029*0Sstevel@tonic-gate sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
1030*0Sstevel@tonic-gate {
1031*0Sstevel@tonic-gate 	Buffer b;
1032*0Sstevel@tonic-gate 	u_char *blob, *signature;
1033*0Sstevel@tonic-gate 	u_int bloblen, slen;
1034*0Sstevel@tonic-gate 	int skip = 0;
1035*0Sstevel@tonic-gate 	int ret = -1;
1036*0Sstevel@tonic-gate 	int have_sig = 1;
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 	debug3("sign_and_send_pubkey");
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 	if (key_to_blob(k, &blob, &bloblen) == 0) {
1041*0Sstevel@tonic-gate 		/* we cannot handle this key */
1042*0Sstevel@tonic-gate 		debug3("sign_and_send_pubkey: cannot handle key");
1043*0Sstevel@tonic-gate 		return 0;
1044*0Sstevel@tonic-gate 	}
1045*0Sstevel@tonic-gate 	/* data to be signed */
1046*0Sstevel@tonic-gate 	buffer_init(&b);
1047*0Sstevel@tonic-gate 	if (datafellows & SSH_OLD_SESSIONID) {
1048*0Sstevel@tonic-gate 		buffer_append(&b, session_id2, session_id2_len);
1049*0Sstevel@tonic-gate 		skip = session_id2_len;
1050*0Sstevel@tonic-gate 	} else {
1051*0Sstevel@tonic-gate 		buffer_put_string(&b, session_id2, session_id2_len);
1052*0Sstevel@tonic-gate 		skip = buffer_len(&b);
1053*0Sstevel@tonic-gate 	}
1054*0Sstevel@tonic-gate 	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1055*0Sstevel@tonic-gate 	buffer_put_cstring(&b, authctxt->server_user);
1056*0Sstevel@tonic-gate 	buffer_put_cstring(&b,
1057*0Sstevel@tonic-gate 	    datafellows & SSH_BUG_PKSERVICE ?
1058*0Sstevel@tonic-gate 	    "ssh-userauth" :
1059*0Sstevel@tonic-gate 	    authctxt->service);
1060*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_PKAUTH) {
1061*0Sstevel@tonic-gate 		buffer_put_char(&b, have_sig);
1062*0Sstevel@tonic-gate 	} else {
1063*0Sstevel@tonic-gate 		buffer_put_cstring(&b, authctxt->method->name);
1064*0Sstevel@tonic-gate 		buffer_put_char(&b, have_sig);
1065*0Sstevel@tonic-gate 		buffer_put_cstring(&b, key_ssh_name(k));
1066*0Sstevel@tonic-gate 	}
1067*0Sstevel@tonic-gate 	buffer_put_string(&b, blob, bloblen);
1068*0Sstevel@tonic-gate 
1069*0Sstevel@tonic-gate 	/* generate signature */
1070*0Sstevel@tonic-gate 	ret = (*sign_callback)(authctxt, k, &signature, &slen,
1071*0Sstevel@tonic-gate 	    buffer_ptr(&b), buffer_len(&b));
1072*0Sstevel@tonic-gate 	if (ret == -1) {
1073*0Sstevel@tonic-gate 		xfree(blob);
1074*0Sstevel@tonic-gate 		buffer_free(&b);
1075*0Sstevel@tonic-gate 		return 0;
1076*0Sstevel@tonic-gate 	}
1077*0Sstevel@tonic-gate #ifdef DEBUG_PK
1078*0Sstevel@tonic-gate 	buffer_dump(&b);
1079*0Sstevel@tonic-gate #endif
1080*0Sstevel@tonic-gate 	if (datafellows & SSH_BUG_PKSERVICE) {
1081*0Sstevel@tonic-gate 		buffer_clear(&b);
1082*0Sstevel@tonic-gate 		buffer_append(&b, session_id2, session_id2_len);
1083*0Sstevel@tonic-gate 		skip = session_id2_len;
1084*0Sstevel@tonic-gate 		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1085*0Sstevel@tonic-gate 		buffer_put_cstring(&b, authctxt->server_user);
1086*0Sstevel@tonic-gate 		buffer_put_cstring(&b, authctxt->service);
1087*0Sstevel@tonic-gate 		buffer_put_cstring(&b, authctxt->method->name);
1088*0Sstevel@tonic-gate 		buffer_put_char(&b, have_sig);
1089*0Sstevel@tonic-gate 		if (!(datafellows & SSH_BUG_PKAUTH))
1090*0Sstevel@tonic-gate 			buffer_put_cstring(&b, key_ssh_name(k));
1091*0Sstevel@tonic-gate 		buffer_put_string(&b, blob, bloblen);
1092*0Sstevel@tonic-gate 	}
1093*0Sstevel@tonic-gate 	xfree(blob);
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 	/* append signature */
1096*0Sstevel@tonic-gate 	buffer_put_string(&b, signature, slen);
1097*0Sstevel@tonic-gate 	xfree(signature);
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	/* skip session id and packet type */
1100*0Sstevel@tonic-gate 	if (buffer_len(&b) < skip + 1)
1101*0Sstevel@tonic-gate 		fatal("userauth_pubkey: internal error");
1102*0Sstevel@tonic-gate 	buffer_consume(&b, skip + 1);
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	/* put remaining data from buffer into packet */
1105*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1106*0Sstevel@tonic-gate 	packet_put_raw(buffer_ptr(&b), buffer_len(&b));
1107*0Sstevel@tonic-gate 	buffer_free(&b);
1108*0Sstevel@tonic-gate 	packet_send();
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 	return 1;
1111*0Sstevel@tonic-gate }
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate static int
1114*0Sstevel@tonic-gate send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
1115*0Sstevel@tonic-gate     int hint)
1116*0Sstevel@tonic-gate {
1117*0Sstevel@tonic-gate 	u_char *blob;
1118*0Sstevel@tonic-gate 	u_int bloblen, have_sig = 0;
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 	debug3("send_pubkey_test");
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	if (key_to_blob(k, &blob, &bloblen) == 0) {
1123*0Sstevel@tonic-gate 		/* we cannot handle this key */
1124*0Sstevel@tonic-gate 		debug3("send_pubkey_test: cannot handle key");
1125*0Sstevel@tonic-gate 		return 0;
1126*0Sstevel@tonic-gate 	}
1127*0Sstevel@tonic-gate 	/* register callback for USERAUTH_PK_OK message */
1128*0Sstevel@tonic-gate 	authctxt->last_key_sign = sign_callback;
1129*0Sstevel@tonic-gate 	authctxt->last_key_hint = hint;
1130*0Sstevel@tonic-gate 	authctxt->last_key = k;
1131*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
1132*0Sstevel@tonic-gate 
1133*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1134*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
1135*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
1136*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
1137*0Sstevel@tonic-gate 	packet_put_char(have_sig);
1138*0Sstevel@tonic-gate 	if (!(datafellows & SSH_BUG_PKAUTH))
1139*0Sstevel@tonic-gate 		packet_put_cstring(key_ssh_name(k));
1140*0Sstevel@tonic-gate 	packet_put_string(blob, bloblen);
1141*0Sstevel@tonic-gate 	xfree(blob);
1142*0Sstevel@tonic-gate 	packet_send();
1143*0Sstevel@tonic-gate 	return 1;
1144*0Sstevel@tonic-gate }
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate static Key *
1147*0Sstevel@tonic-gate load_identity_file(char *filename)
1148*0Sstevel@tonic-gate {
1149*0Sstevel@tonic-gate 	Key *private;
1150*0Sstevel@tonic-gate 	char prompt[300], *passphrase;
1151*0Sstevel@tonic-gate 	int quit, i;
1152*0Sstevel@tonic-gate 	struct stat st;
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	if (stat(filename, &st) < 0) {
1155*0Sstevel@tonic-gate 		debug3("no such identity: %s", filename);
1156*0Sstevel@tonic-gate 		return NULL;
1157*0Sstevel@tonic-gate 	}
1158*0Sstevel@tonic-gate 	private = key_load_private_type(KEY_UNSPEC, filename, "", NULL);
1159*0Sstevel@tonic-gate 	if (private == NULL) {
1160*0Sstevel@tonic-gate 		if (options.batch_mode)
1161*0Sstevel@tonic-gate 			return NULL;
1162*0Sstevel@tonic-gate 		snprintf(prompt, sizeof prompt,
1163*0Sstevel@tonic-gate 		    gettext("Enter passphrase for key '%.100s': "), filename);
1164*0Sstevel@tonic-gate 		for (i = 0; i < options.number_of_password_prompts; i++) {
1165*0Sstevel@tonic-gate 			passphrase = read_passphrase(prompt, 0);
1166*0Sstevel@tonic-gate 			if (strcmp(passphrase, "") != 0) {
1167*0Sstevel@tonic-gate 				private = key_load_private_type(KEY_UNSPEC, filename,
1168*0Sstevel@tonic-gate 				    passphrase, NULL);
1169*0Sstevel@tonic-gate 				quit = 0;
1170*0Sstevel@tonic-gate 			} else {
1171*0Sstevel@tonic-gate 				debug2("no passphrase given, try next key");
1172*0Sstevel@tonic-gate 				quit = 1;
1173*0Sstevel@tonic-gate 			}
1174*0Sstevel@tonic-gate 			memset(passphrase, 0, strlen(passphrase));
1175*0Sstevel@tonic-gate 			xfree(passphrase);
1176*0Sstevel@tonic-gate 			if (private != NULL || quit)
1177*0Sstevel@tonic-gate 				break;
1178*0Sstevel@tonic-gate 			debug2("bad passphrase given, try again...");
1179*0Sstevel@tonic-gate 		}
1180*0Sstevel@tonic-gate 	}
1181*0Sstevel@tonic-gate 	return private;
1182*0Sstevel@tonic-gate }
1183*0Sstevel@tonic-gate 
1184*0Sstevel@tonic-gate static int
1185*0Sstevel@tonic-gate identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
1186*0Sstevel@tonic-gate     u_char *data, u_int datalen)
1187*0Sstevel@tonic-gate {
1188*0Sstevel@tonic-gate 	Key *private;
1189*0Sstevel@tonic-gate 	int idx, ret;
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	idx = authctxt->last_key_hint;
1192*0Sstevel@tonic-gate 	if (idx < 0)
1193*0Sstevel@tonic-gate 		return -1;
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 	/* private key is stored in external hardware */
1196*0Sstevel@tonic-gate 	if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
1197*0Sstevel@tonic-gate 		return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate 	private = load_identity_file(options.identity_files[idx]);
1200*0Sstevel@tonic-gate 	if (private == NULL)
1201*0Sstevel@tonic-gate 		return -1;
1202*0Sstevel@tonic-gate 	ret = key_sign(private, sigp, lenp, data, datalen);
1203*0Sstevel@tonic-gate 	key_free(private);
1204*0Sstevel@tonic-gate 	return ret;
1205*0Sstevel@tonic-gate }
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate static int
1208*0Sstevel@tonic-gate agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
1209*0Sstevel@tonic-gate     u_char *data, u_int datalen)
1210*0Sstevel@tonic-gate {
1211*0Sstevel@tonic-gate 	return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
1212*0Sstevel@tonic-gate }
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate static int
1215*0Sstevel@tonic-gate key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
1216*0Sstevel@tonic-gate     u_char *data, u_int datalen)
1217*0Sstevel@tonic-gate {
1218*0Sstevel@tonic-gate 	return key_sign(key, sigp, lenp, data, datalen);
1219*0Sstevel@tonic-gate }
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate static int
1222*0Sstevel@tonic-gate userauth_pubkey_agent(Authctxt *authctxt)
1223*0Sstevel@tonic-gate {
1224*0Sstevel@tonic-gate 	static int called = 0;
1225*0Sstevel@tonic-gate 	int ret = 0;
1226*0Sstevel@tonic-gate 	char *comment;
1227*0Sstevel@tonic-gate 	Key *k;
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate 	if (called == 0) {
1230*0Sstevel@tonic-gate 		if (ssh_get_num_identities(authctxt->agent, 2) == 0)
1231*0Sstevel@tonic-gate 			debug2("userauth_pubkey_agent: no keys at all");
1232*0Sstevel@tonic-gate 		called = 1;
1233*0Sstevel@tonic-gate 	}
1234*0Sstevel@tonic-gate 	k = ssh_get_next_identity(authctxt->agent, &comment, 2);
1235*0Sstevel@tonic-gate 	if (k == NULL) {
1236*0Sstevel@tonic-gate 		debug2("userauth_pubkey_agent: no more keys");
1237*0Sstevel@tonic-gate 	} else {
1238*0Sstevel@tonic-gate 		debug("Offering agent key: %s", comment);
1239*0Sstevel@tonic-gate 		xfree(comment);
1240*0Sstevel@tonic-gate 		ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
1241*0Sstevel@tonic-gate 		if (ret == 0)
1242*0Sstevel@tonic-gate 			key_free(k);
1243*0Sstevel@tonic-gate 	}
1244*0Sstevel@tonic-gate 	if (ret == 0)
1245*0Sstevel@tonic-gate 		debug2("userauth_pubkey_agent: no message sent");
1246*0Sstevel@tonic-gate 	return ret;
1247*0Sstevel@tonic-gate }
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate int
1250*0Sstevel@tonic-gate userauth_pubkey(Authctxt *authctxt)
1251*0Sstevel@tonic-gate {
1252*0Sstevel@tonic-gate 	static int idx = 0;
1253*0Sstevel@tonic-gate 	int sent = 0;
1254*0Sstevel@tonic-gate 	Key *key;
1255*0Sstevel@tonic-gate 	char *filename;
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	if (authctxt->agent != NULL) {
1258*0Sstevel@tonic-gate 		do {
1259*0Sstevel@tonic-gate 			sent = userauth_pubkey_agent(authctxt);
1260*0Sstevel@tonic-gate 		} while (!sent && authctxt->agent->howmany > 0);
1261*0Sstevel@tonic-gate 	}
1262*0Sstevel@tonic-gate 	while (!sent && idx < options.num_identity_files) {
1263*0Sstevel@tonic-gate 		key = options.identity_keys[idx];
1264*0Sstevel@tonic-gate 		filename = options.identity_files[idx];
1265*0Sstevel@tonic-gate 		if (key == NULL) {
1266*0Sstevel@tonic-gate 			debug("Trying private key: %s", filename);
1267*0Sstevel@tonic-gate 			key = load_identity_file(filename);
1268*0Sstevel@tonic-gate 			if (key != NULL) {
1269*0Sstevel@tonic-gate 				sent = sign_and_send_pubkey(authctxt, key,
1270*0Sstevel@tonic-gate 				    key_sign_cb);
1271*0Sstevel@tonic-gate 				key_free(key);
1272*0Sstevel@tonic-gate 			}
1273*0Sstevel@tonic-gate 		} else if (key->type != KEY_RSA1) {
1274*0Sstevel@tonic-gate 			debug("Trying public key: %s", filename);
1275*0Sstevel@tonic-gate 			sent = send_pubkey_test(authctxt, key,
1276*0Sstevel@tonic-gate 			    identity_sign_cb, idx);
1277*0Sstevel@tonic-gate 		}
1278*0Sstevel@tonic-gate 		idx++;
1279*0Sstevel@tonic-gate 	}
1280*0Sstevel@tonic-gate 	return sent;
1281*0Sstevel@tonic-gate }
1282*0Sstevel@tonic-gate 
1283*0Sstevel@tonic-gate /*
1284*0Sstevel@tonic-gate  * Send userauth request message specifying keyboard-interactive method.
1285*0Sstevel@tonic-gate  */
1286*0Sstevel@tonic-gate int
1287*0Sstevel@tonic-gate userauth_kbdint(Authctxt *authctxt)
1288*0Sstevel@tonic-gate {
1289*0Sstevel@tonic-gate 	static int attempt = 0;
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate 	if (attempt++ >= options.number_of_password_prompts)
1292*0Sstevel@tonic-gate 		return 0;
1293*0Sstevel@tonic-gate 	/* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */
1294*0Sstevel@tonic-gate 	if (attempt > 1 && !authctxt->info_req_seen) {
1295*0Sstevel@tonic-gate 		debug3("userauth_kbdint: disable: no info_req_seen");
1296*0Sstevel@tonic-gate 		dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL);
1297*0Sstevel@tonic-gate 		return 0;
1298*0Sstevel@tonic-gate 	}
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 	debug2("userauth_kbdint");
1301*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1302*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
1303*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
1304*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
1305*0Sstevel@tonic-gate 	packet_put_cstring("");					/* lang */
1306*0Sstevel@tonic-gate 	packet_put_cstring(options.kbd_interactive_devices ?
1307*0Sstevel@tonic-gate 	    options.kbd_interactive_devices : "");
1308*0Sstevel@tonic-gate 	packet_send();
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
1311*0Sstevel@tonic-gate 	return 1;
1312*0Sstevel@tonic-gate }
1313*0Sstevel@tonic-gate 
1314*0Sstevel@tonic-gate /*
1315*0Sstevel@tonic-gate  * parse INFO_REQUEST, prompt user and send INFO_RESPONSE
1316*0Sstevel@tonic-gate  */
1317*0Sstevel@tonic-gate void
1318*0Sstevel@tonic-gate input_userauth_info_req(int type, u_int32_t seq, void *ctxt)
1319*0Sstevel@tonic-gate {
1320*0Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
1321*0Sstevel@tonic-gate 	char *name, *inst, *lang, *prompt, *response;
1322*0Sstevel@tonic-gate 	u_int num_prompts, i;
1323*0Sstevel@tonic-gate 	int echo = 0;
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 	debug2("input_userauth_info_req");
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	if (authctxt == NULL)
1328*0Sstevel@tonic-gate 		fatal("input_userauth_info_req: no authentication context");
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 	authctxt->info_req_seen = 1;
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate 	name = packet_get_string(NULL);
1333*0Sstevel@tonic-gate 	inst = packet_get_string(NULL);
1334*0Sstevel@tonic-gate 	lang = packet_get_string(NULL);
1335*0Sstevel@tonic-gate 	if (strlen(name) > 0)
1336*0Sstevel@tonic-gate 		log("%s", name);
1337*0Sstevel@tonic-gate 	if (strlen(inst) > 0)
1338*0Sstevel@tonic-gate 		log("%s", inst);
1339*0Sstevel@tonic-gate 	xfree(name);
1340*0Sstevel@tonic-gate 	xfree(inst);
1341*0Sstevel@tonic-gate 	xfree(lang);
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	num_prompts = packet_get_int();
1344*0Sstevel@tonic-gate 	/*
1345*0Sstevel@tonic-gate 	 * Begin to build info response packet based on prompts requested.
1346*0Sstevel@tonic-gate 	 * We commit to providing the correct number of responses, so if
1347*0Sstevel@tonic-gate 	 * further on we run into a problem that prevents this, we have to
1348*0Sstevel@tonic-gate 	 * be sure and clean this up and send a correct error response.
1349*0Sstevel@tonic-gate 	 */
1350*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
1351*0Sstevel@tonic-gate 	packet_put_int(num_prompts);
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 	debug2("input_userauth_info_req: num_prompts %d", num_prompts);
1354*0Sstevel@tonic-gate 	for (i = 0; i < num_prompts; i++) {
1355*0Sstevel@tonic-gate 		prompt = packet_get_string(NULL);
1356*0Sstevel@tonic-gate 		echo = packet_get_char();
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 		response = read_passphrase(prompt, echo ? RP_ECHO : 0);
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 		packet_put_cstring(response);
1361*0Sstevel@tonic-gate 		memset(response, 0, strlen(response));
1362*0Sstevel@tonic-gate 		xfree(response);
1363*0Sstevel@tonic-gate 		xfree(prompt);
1364*0Sstevel@tonic-gate 	}
1365*0Sstevel@tonic-gate 	packet_check_eom(); /* done with parsing incoming message. */
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	packet_add_padding(64);
1368*0Sstevel@tonic-gate 	packet_send();
1369*0Sstevel@tonic-gate }
1370*0Sstevel@tonic-gate 
1371*0Sstevel@tonic-gate static int
1372*0Sstevel@tonic-gate ssh_keysign(Key *key, u_char **sigp, u_int *lenp,
1373*0Sstevel@tonic-gate     u_char *data, u_int datalen)
1374*0Sstevel@tonic-gate {
1375*0Sstevel@tonic-gate 	Buffer b;
1376*0Sstevel@tonic-gate 	struct stat st;
1377*0Sstevel@tonic-gate 	pid_t pid;
1378*0Sstevel@tonic-gate 	int to[2], from[2], status, version = 2;
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 	debug2("ssh_keysign called");
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
1383*0Sstevel@tonic-gate 		error("ssh_keysign: no installed: %s", strerror(errno));
1384*0Sstevel@tonic-gate 		return -1;
1385*0Sstevel@tonic-gate 	}
1386*0Sstevel@tonic-gate 	if (fflush(stdout) != 0)
1387*0Sstevel@tonic-gate 		error("ssh_keysign: fflush: %s", strerror(errno));
1388*0Sstevel@tonic-gate 	if (pipe(to) < 0) {
1389*0Sstevel@tonic-gate 		error("ssh_keysign: pipe: %s", strerror(errno));
1390*0Sstevel@tonic-gate 		return -1;
1391*0Sstevel@tonic-gate 	}
1392*0Sstevel@tonic-gate 	if (pipe(from) < 0) {
1393*0Sstevel@tonic-gate 		error("ssh_keysign: pipe: %s", strerror(errno));
1394*0Sstevel@tonic-gate 		return -1;
1395*0Sstevel@tonic-gate 	}
1396*0Sstevel@tonic-gate 	if ((pid = fork()) < 0) {
1397*0Sstevel@tonic-gate 		error("ssh_keysign: fork: %s", strerror(errno));
1398*0Sstevel@tonic-gate 		return -1;
1399*0Sstevel@tonic-gate 	}
1400*0Sstevel@tonic-gate 	if (pid == 0) {
1401*0Sstevel@tonic-gate 		seteuid(getuid());
1402*0Sstevel@tonic-gate 		setuid(getuid());
1403*0Sstevel@tonic-gate 		close(from[0]);
1404*0Sstevel@tonic-gate 		if (dup2(from[1], STDOUT_FILENO) < 0)
1405*0Sstevel@tonic-gate 			fatal("ssh_keysign: dup2: %s", strerror(errno));
1406*0Sstevel@tonic-gate 		close(to[1]);
1407*0Sstevel@tonic-gate 		if (dup2(to[0], STDIN_FILENO) < 0)
1408*0Sstevel@tonic-gate 			fatal("ssh_keysign: dup2: %s", strerror(errno));
1409*0Sstevel@tonic-gate 		close(from[1]);
1410*0Sstevel@tonic-gate 		close(to[0]);
1411*0Sstevel@tonic-gate 		execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
1412*0Sstevel@tonic-gate 		fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
1413*0Sstevel@tonic-gate 		    strerror(errno));
1414*0Sstevel@tonic-gate 	}
1415*0Sstevel@tonic-gate 	close(from[1]);
1416*0Sstevel@tonic-gate 	close(to[0]);
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 	buffer_init(&b);
1419*0Sstevel@tonic-gate 	buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
1420*0Sstevel@tonic-gate 	buffer_put_string(&b, data, datalen);
1421*0Sstevel@tonic-gate 	ssh_msg_send(to[1], version, &b);
1422*0Sstevel@tonic-gate 
1423*0Sstevel@tonic-gate 	if (ssh_msg_recv(from[0], &b) < 0) {
1424*0Sstevel@tonic-gate 		error("ssh_keysign: no reply");
1425*0Sstevel@tonic-gate 		buffer_clear(&b);
1426*0Sstevel@tonic-gate 		return -1;
1427*0Sstevel@tonic-gate 	}
1428*0Sstevel@tonic-gate 	close(from[0]);
1429*0Sstevel@tonic-gate 	close(to[1]);
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	while (waitpid(pid, &status, 0) < 0)
1432*0Sstevel@tonic-gate 		if (errno != EINTR)
1433*0Sstevel@tonic-gate 			break;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	if (buffer_get_char(&b) != version) {
1436*0Sstevel@tonic-gate 		error("ssh_keysign: bad version");
1437*0Sstevel@tonic-gate 		buffer_clear(&b);
1438*0Sstevel@tonic-gate 		return -1;
1439*0Sstevel@tonic-gate 	}
1440*0Sstevel@tonic-gate 	*sigp = buffer_get_string(&b, lenp);
1441*0Sstevel@tonic-gate 	buffer_clear(&b);
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 	return 0;
1444*0Sstevel@tonic-gate }
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate int
1447*0Sstevel@tonic-gate userauth_hostbased(Authctxt *authctxt)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate 	Key *private = NULL;
1450*0Sstevel@tonic-gate 	Sensitive *sensitive = authctxt->sensitive;
1451*0Sstevel@tonic-gate 	Buffer b;
1452*0Sstevel@tonic-gate 	u_char *signature, *blob;
1453*0Sstevel@tonic-gate 	char *chost, *pkalg, *p;
1454*0Sstevel@tonic-gate 	const char *service;
1455*0Sstevel@tonic-gate 	u_int blen, slen;
1456*0Sstevel@tonic-gate 	int ok, i, len, found = 0;
1457*0Sstevel@tonic-gate 	static int last_hostkey = -1;
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	/* check for a useful key */
1460*0Sstevel@tonic-gate 	for (i = 0; i < sensitive->nkeys; i++) {
1461*0Sstevel@tonic-gate 		private = sensitive->keys[i];
1462*0Sstevel@tonic-gate 		if (private && private->type != KEY_RSA1 && i > last_hostkey) {
1463*0Sstevel@tonic-gate 			found = 1;
1464*0Sstevel@tonic-gate 			last_hostkey = i;
1465*0Sstevel@tonic-gate 			/* we take and free the key */
1466*0Sstevel@tonic-gate 			sensitive->keys[i] = NULL;
1467*0Sstevel@tonic-gate 			break;
1468*0Sstevel@tonic-gate 		}
1469*0Sstevel@tonic-gate 	}
1470*0Sstevel@tonic-gate 	if (!found) {
1471*0Sstevel@tonic-gate 		debug("No more client hostkeys for hostbased authentication");
1472*0Sstevel@tonic-gate 		return 0;
1473*0Sstevel@tonic-gate 	}
1474*0Sstevel@tonic-gate 	if (key_to_blob(private, &blob, &blen) == 0) {
1475*0Sstevel@tonic-gate 		key_free(private);
1476*0Sstevel@tonic-gate 		return 0;
1477*0Sstevel@tonic-gate 	}
1478*0Sstevel@tonic-gate 	/* figure out a name for the client host */
1479*0Sstevel@tonic-gate 	p = get_local_name(packet_get_connection_in());
1480*0Sstevel@tonic-gate 	if (p == NULL) {
1481*0Sstevel@tonic-gate 		error("userauth_hostbased: cannot get local ipaddr/name");
1482*0Sstevel@tonic-gate 		key_free(private);
1483*0Sstevel@tonic-gate 		return 0;
1484*0Sstevel@tonic-gate 	}
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
1487*0Sstevel@tonic-gate 	    authctxt->service;
1488*0Sstevel@tonic-gate 	pkalg = xstrdup(key_ssh_name(private));
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate 	len = strlen(p) + 2;
1491*0Sstevel@tonic-gate 	chost = xmalloc(len);
1492*0Sstevel@tonic-gate 	strlcpy(chost, p, len);
1493*0Sstevel@tonic-gate 	strlcat(chost, ".", len);
1494*0Sstevel@tonic-gate 	xfree(p);
1495*0Sstevel@tonic-gate 	debug2("userauth_hostbased: chost %s, pkalg %s", chost, pkalg);
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 	buffer_init(&b);
1498*0Sstevel@tonic-gate 	/* construct data */
1499*0Sstevel@tonic-gate 	buffer_put_string(&b, session_id2, session_id2_len);
1500*0Sstevel@tonic-gate 	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1501*0Sstevel@tonic-gate 	buffer_put_cstring(&b, authctxt->server_user);
1502*0Sstevel@tonic-gate 	buffer_put_cstring(&b, service);
1503*0Sstevel@tonic-gate 	buffer_put_cstring(&b, authctxt->method->name);
1504*0Sstevel@tonic-gate 	buffer_put_cstring(&b, pkalg);
1505*0Sstevel@tonic-gate 	buffer_put_string(&b, blob, blen);
1506*0Sstevel@tonic-gate 	buffer_put_cstring(&b, chost);
1507*0Sstevel@tonic-gate 	buffer_put_cstring(&b, authctxt->local_user);
1508*0Sstevel@tonic-gate #ifdef DEBUG_PK
1509*0Sstevel@tonic-gate 	buffer_dump(&b);
1510*0Sstevel@tonic-gate #endif
1511*0Sstevel@tonic-gate 	if (sensitive->external_keysign)
1512*0Sstevel@tonic-gate 		ok = ssh_keysign(private, &signature, &slen,
1513*0Sstevel@tonic-gate 		    buffer_ptr(&b), buffer_len(&b));
1514*0Sstevel@tonic-gate 	else
1515*0Sstevel@tonic-gate 		ok = key_sign(private, &signature, &slen,
1516*0Sstevel@tonic-gate 		    buffer_ptr(&b), buffer_len(&b));
1517*0Sstevel@tonic-gate 	key_free(private);
1518*0Sstevel@tonic-gate 	buffer_free(&b);
1519*0Sstevel@tonic-gate 	if (ok != 0) {
1520*0Sstevel@tonic-gate 		error("key_sign failed");
1521*0Sstevel@tonic-gate 		xfree(chost);
1522*0Sstevel@tonic-gate 		xfree(pkalg);
1523*0Sstevel@tonic-gate 		return 0;
1524*0Sstevel@tonic-gate 	}
1525*0Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
1526*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->server_user);
1527*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->service);
1528*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->method->name);
1529*0Sstevel@tonic-gate 	packet_put_cstring(pkalg);
1530*0Sstevel@tonic-gate 	packet_put_string(blob, blen);
1531*0Sstevel@tonic-gate 	packet_put_cstring(chost);
1532*0Sstevel@tonic-gate 	packet_put_cstring(authctxt->local_user);
1533*0Sstevel@tonic-gate 	packet_put_string(signature, slen);
1534*0Sstevel@tonic-gate 	memset(signature, 's', slen);
1535*0Sstevel@tonic-gate 	xfree(signature);
1536*0Sstevel@tonic-gate 	xfree(chost);
1537*0Sstevel@tonic-gate 	xfree(pkalg);
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate 	packet_send();
1540*0Sstevel@tonic-gate 	return 1;
1541*0Sstevel@tonic-gate }
1542*0Sstevel@tonic-gate 
1543*0Sstevel@tonic-gate /* find auth method */
1544*0Sstevel@tonic-gate 
1545*0Sstevel@tonic-gate /*
1546*0Sstevel@tonic-gate  * given auth method name, if configurable options permit this method fill
1547*0Sstevel@tonic-gate  * in auth_ident field and return true, otherwise return false.
1548*0Sstevel@tonic-gate  */
1549*0Sstevel@tonic-gate static int
1550*0Sstevel@tonic-gate authmethod_is_enabled(Authmethod *method)
1551*0Sstevel@tonic-gate {
1552*0Sstevel@tonic-gate 	if (method == NULL)
1553*0Sstevel@tonic-gate 		return 0;
1554*0Sstevel@tonic-gate 	/* return false if options indicate this method is disabled */
1555*0Sstevel@tonic-gate 	if  (method->enabled == NULL || *method->enabled == 0)
1556*0Sstevel@tonic-gate 		return 0;
1557*0Sstevel@tonic-gate 	/* return false if batch mode is enabled but method needs interactive mode */
1558*0Sstevel@tonic-gate 	if  (method->batch_flag != NULL && *method->batch_flag != 0)
1559*0Sstevel@tonic-gate 		return 0;
1560*0Sstevel@tonic-gate 	return 1;
1561*0Sstevel@tonic-gate }
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate static Authmethod *
1564*0Sstevel@tonic-gate authmethod_lookup(const char *name)
1565*0Sstevel@tonic-gate {
1566*0Sstevel@tonic-gate 	Authmethod *method = NULL;
1567*0Sstevel@tonic-gate 	if (name != NULL) {
1568*0Sstevel@tonic-gate 		for (method = authmethods; method->name != NULL; method++) {
1569*0Sstevel@tonic-gate 			if (strcmp(name, method->name) == 0)
1570*0Sstevel@tonic-gate 				return method;
1571*0Sstevel@tonic-gate 		}
1572*0Sstevel@tonic-gate 	}
1573*0Sstevel@tonic-gate 	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
1574*0Sstevel@tonic-gate 	return NULL;
1575*0Sstevel@tonic-gate }
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate /* XXX internal state */
1578*0Sstevel@tonic-gate static Authmethod *current = NULL;
1579*0Sstevel@tonic-gate static char *supported = NULL;
1580*0Sstevel@tonic-gate static char *preferred = NULL;
1581*0Sstevel@tonic-gate 
1582*0Sstevel@tonic-gate /*
1583*0Sstevel@tonic-gate  * Given the authentication method list sent by the server, return the
1584*0Sstevel@tonic-gate  * next method we should try.  If the server initially sends a nil list,
1585*0Sstevel@tonic-gate  * use a built-in default list.
1586*0Sstevel@tonic-gate  */
1587*0Sstevel@tonic-gate static Authmethod *
1588*0Sstevel@tonic-gate authmethod_get(char *authlist)
1589*0Sstevel@tonic-gate {
1590*0Sstevel@tonic-gate 
1591*0Sstevel@tonic-gate 	char *name = NULL;
1592*0Sstevel@tonic-gate 	u_int next;
1593*0Sstevel@tonic-gate 
1594*0Sstevel@tonic-gate 	/* Use a suitable default if we're passed a nil list.  */
1595*0Sstevel@tonic-gate 	if (authlist == NULL || strlen(authlist) == 0)
1596*0Sstevel@tonic-gate 		authlist = options.preferred_authentications;
1597*0Sstevel@tonic-gate 
1598*0Sstevel@tonic-gate 	if (supported == NULL || strcmp(authlist, supported) != 0) {
1599*0Sstevel@tonic-gate 		debug3("start over, passed a different list %s", authlist);
1600*0Sstevel@tonic-gate 		if (supported != NULL)
1601*0Sstevel@tonic-gate 			xfree(supported);
1602*0Sstevel@tonic-gate 		supported = xstrdup(authlist);
1603*0Sstevel@tonic-gate 		preferred = options.preferred_authentications;
1604*0Sstevel@tonic-gate 		debug3("preferred %s", preferred);
1605*0Sstevel@tonic-gate 		current = NULL;
1606*0Sstevel@tonic-gate 	} else if (current != NULL && authmethod_is_enabled(current))
1607*0Sstevel@tonic-gate 		return current;
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate 	for (;;) {
1610*0Sstevel@tonic-gate 		if ((name = match_list(preferred, supported, &next)) == NULL) {
1611*0Sstevel@tonic-gate 			debug("No more authentication methods to try.");
1612*0Sstevel@tonic-gate 			current = NULL;
1613*0Sstevel@tonic-gate 			return NULL;
1614*0Sstevel@tonic-gate 		}
1615*0Sstevel@tonic-gate 		preferred += next;
1616*0Sstevel@tonic-gate 		debug3("authmethod_lookup %s", name);
1617*0Sstevel@tonic-gate 		debug3("remaining preferred: %s", preferred);
1618*0Sstevel@tonic-gate 		if ((current = authmethod_lookup(name)) != NULL &&
1619*0Sstevel@tonic-gate 		    authmethod_is_enabled(current)) {
1620*0Sstevel@tonic-gate 			debug3("authmethod_is_enabled %s", name);
1621*0Sstevel@tonic-gate 			debug("Next authentication method: %s", name);
1622*0Sstevel@tonic-gate 			return current;
1623*0Sstevel@tonic-gate 		}
1624*0Sstevel@tonic-gate 	}
1625*0Sstevel@tonic-gate }
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate static char *
1628*0Sstevel@tonic-gate authmethods_get(void)
1629*0Sstevel@tonic-gate {
1630*0Sstevel@tonic-gate 	Authmethod *method = NULL;
1631*0Sstevel@tonic-gate 	Buffer b;
1632*0Sstevel@tonic-gate 	char *list;
1633*0Sstevel@tonic-gate 
1634*0Sstevel@tonic-gate 	buffer_init(&b);
1635*0Sstevel@tonic-gate 	for (method = authmethods; method->name != NULL; method++) {
1636*0Sstevel@tonic-gate 		if (authmethod_is_enabled(method)) {
1637*0Sstevel@tonic-gate 			if (buffer_len(&b) > 0)
1638*0Sstevel@tonic-gate 				buffer_append(&b, ",", 1);
1639*0Sstevel@tonic-gate 			buffer_append(&b, method->name, strlen(method->name));
1640*0Sstevel@tonic-gate 		}
1641*0Sstevel@tonic-gate 	}
1642*0Sstevel@tonic-gate 	buffer_append(&b, "\0", 1);
1643*0Sstevel@tonic-gate 	list = xstrdup(buffer_ptr(&b));
1644*0Sstevel@tonic-gate 	buffer_free(&b);
1645*0Sstevel@tonic-gate 	return list;
1646*0Sstevel@tonic-gate }
1647