xref: /freebsd/crypto/openssh/auth2.c (revision 099584266b3a508b982965708de56eaba461bee4)
1a04a10f8SKris Kennaway /*
2a04a10f8SKris Kennaway  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3a04a10f8SKris Kennaway  *
4a04a10f8SKris Kennaway  * Redistribution and use in source and binary forms, with or without
5a04a10f8SKris Kennaway  * modification, are permitted provided that the following conditions
6a04a10f8SKris Kennaway  * are met:
7a04a10f8SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
8a04a10f8SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
9a04a10f8SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
10a04a10f8SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
11a04a10f8SKris Kennaway  *    documentation and/or other materials provided with the distribution.
12a04a10f8SKris Kennaway  *
13a04a10f8SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14a04a10f8SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15a04a10f8SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16a04a10f8SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17a04a10f8SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18a04a10f8SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19a04a10f8SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20a04a10f8SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21a04a10f8SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22a04a10f8SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23a04a10f8SKris Kennaway  */
24c2d3a559SKris Kennaway 
25a04a10f8SKris Kennaway #include "includes.h"
2609958426SBrian Feldman RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $");
27c2d3a559SKris Kennaway RCSID("$FreeBSD$");
28a04a10f8SKris Kennaway 
29a04a10f8SKris Kennaway #include <openssl/dsa.h>
30a04a10f8SKris Kennaway #include <openssl/rsa.h>
31a04a10f8SKris Kennaway #include <openssl/evp.h>
32a04a10f8SKris Kennaway 
33a04a10f8SKris Kennaway #include "xmalloc.h"
34a04a10f8SKris Kennaway #include "rsa.h"
35a04a10f8SKris Kennaway #include "ssh.h"
36a04a10f8SKris Kennaway #include "pty.h"
37a04a10f8SKris Kennaway #include "packet.h"
38a04a10f8SKris Kennaway #include "buffer.h"
39a04a10f8SKris Kennaway #include "servconf.h"
40a04a10f8SKris Kennaway #include "compat.h"
41a04a10f8SKris Kennaway #include "channels.h"
42a04a10f8SKris Kennaway #include "bufaux.h"
43a04a10f8SKris Kennaway #include "ssh2.h"
44a04a10f8SKris Kennaway #include "auth.h"
45a04a10f8SKris Kennaway #include "session.h"
46a04a10f8SKris Kennaway #include "dispatch.h"
47a04a10f8SKris Kennaway #include "auth.h"
48a04a10f8SKris Kennaway #include "key.h"
49a04a10f8SKris Kennaway #include "kex.h"
50a04a10f8SKris Kennaway 
51a04a10f8SKris Kennaway #include "dsa.h"
52a04a10f8SKris Kennaway #include "uidswap.h"
53c2d3a559SKris Kennaway #include "auth-options.h"
54a04a10f8SKris Kennaway 
5503e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP
5603e72be8SBrian Feldman #include <login_cap.h>
5703e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP */
5803e72be8SBrian Feldman 
59a04a10f8SKris Kennaway /* import */
60a04a10f8SKris Kennaway extern ServerOptions options;
61a04a10f8SKris Kennaway extern unsigned char *session_id2;
62a04a10f8SKris Kennaway extern int session_id2_len;
63a04a10f8SKris Kennaway 
6409958426SBrian Feldman static Authctxt	*x_authctxt = NULL;
6509958426SBrian Feldman static int one = 1;
6609958426SBrian Feldman 
6709958426SBrian Feldman typedef struct Authmethod Authmethod;
6809958426SBrian Feldman struct Authmethod {
6909958426SBrian Feldman 	char	*name;
7009958426SBrian Feldman 	int	(*userauth)(Authctxt *authctxt);
7109958426SBrian Feldman 	int	*enabled;
7209958426SBrian Feldman };
7309958426SBrian Feldman 
74a04a10f8SKris Kennaway /* protocol */
75a04a10f8SKris Kennaway 
7609958426SBrian Feldman void	input_service_request(int type, int plen, void *ctxt);
7709958426SBrian Feldman void	input_userauth_request(int type, int plen, void *ctxt);
7809958426SBrian Feldman void	protocol_error(int type, int plen, void *ctxt);
79a04a10f8SKris Kennaway 
80a04a10f8SKris Kennaway 
81a04a10f8SKris Kennaway /* helper */
8209958426SBrian Feldman Authmethod	*authmethod_lookup(const char *name);
8309958426SBrian Feldman struct passwd	*pwcopy(struct passwd *pw);
84a04a10f8SKris Kennaway int	user_dsa_key_allowed(struct passwd *pw, Key *key);
8509958426SBrian Feldman char	*authmethods_get(void);
86a04a10f8SKris Kennaway 
8709958426SBrian Feldman /* auth */
8809958426SBrian Feldman int	userauth_none(Authctxt *authctxt);
8909958426SBrian Feldman int	userauth_passwd(Authctxt *authctxt);
9009958426SBrian Feldman int	userauth_pubkey(Authctxt *authctxt);
9109958426SBrian Feldman int	userauth_kbdint(Authctxt *authctxt);
9209958426SBrian Feldman 
9309958426SBrian Feldman Authmethod authmethods[] = {
9409958426SBrian Feldman 	{"none",
9509958426SBrian Feldman 		userauth_none,
9609958426SBrian Feldman 		&one},
9709958426SBrian Feldman 	{"publickey",
9809958426SBrian Feldman 		userauth_pubkey,
9909958426SBrian Feldman 		&options.dsa_authentication},
10009958426SBrian Feldman 	{"keyboard-interactive",
10109958426SBrian Feldman 		userauth_kbdint,
10209958426SBrian Feldman 		&options.kbd_interactive_authentication},
10309958426SBrian Feldman 	{"password",
10409958426SBrian Feldman 		userauth_passwd,
10509958426SBrian Feldman 		&options.password_authentication},
10609958426SBrian Feldman 	{NULL, NULL, NULL}
107a04a10f8SKris Kennaway };
108a04a10f8SKris Kennaway 
109a04a10f8SKris Kennaway /*
11009958426SBrian Feldman  * loop until authctxt->success == TRUE
111a04a10f8SKris Kennaway  */
112a04a10f8SKris Kennaway 
113a04a10f8SKris Kennaway void
114a04a10f8SKris Kennaway do_authentication2()
115a04a10f8SKris Kennaway {
11609958426SBrian Feldman 	Authctxt *authctxt = xmalloc(sizeof(*authctxt));
11709958426SBrian Feldman 	memset(authctxt, 'a', sizeof(*authctxt));
11809958426SBrian Feldman 	authctxt->valid = 0;
11909958426SBrian Feldman 	authctxt->attempt = 0;
12009958426SBrian Feldman 	authctxt->success = 0;
12109958426SBrian Feldman 	x_authctxt = authctxt;		/*XXX*/
12209958426SBrian Feldman 
123a04a10f8SKris Kennaway #ifdef KRB4
12409958426SBrian Feldman 	/* turn off kerberos, not supported by SSH2 */
125e8aafc91SKris Kennaway 	options.krb4_authentication = 0;
126a04a10f8SKris Kennaway #endif
127a04a10f8SKris Kennaway 	dispatch_init(&protocol_error);
128a04a10f8SKris Kennaway 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
12909958426SBrian Feldman 	dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
130a04a10f8SKris Kennaway 	do_authenticated2();
131a04a10f8SKris Kennaway }
132a04a10f8SKris Kennaway 
133a04a10f8SKris Kennaway void
13409958426SBrian Feldman protocol_error(int type, int plen, void *ctxt)
135a04a10f8SKris Kennaway {
136a04a10f8SKris Kennaway 	log("auth: protocol error: type %d plen %d", type, plen);
137a04a10f8SKris Kennaway 	packet_start(SSH2_MSG_UNIMPLEMENTED);
138a04a10f8SKris Kennaway 	packet_put_int(0);
139a04a10f8SKris Kennaway 	packet_send();
140a04a10f8SKris Kennaway 	packet_write_wait();
141a04a10f8SKris Kennaway }
142a04a10f8SKris Kennaway 
143a04a10f8SKris Kennaway void
14409958426SBrian Feldman input_service_request(int type, int plen, void *ctxt)
145a04a10f8SKris Kennaway {
14609958426SBrian Feldman 	Authctxt *authctxt = ctxt;
147a04a10f8SKris Kennaway 	unsigned int len;
148a04a10f8SKris Kennaway 	int accept = 0;
149a04a10f8SKris Kennaway 	char *service = packet_get_string(&len);
150a04a10f8SKris Kennaway 	packet_done();
151a04a10f8SKris Kennaway 
15209958426SBrian Feldman 	if (authctxt == NULL)
15309958426SBrian Feldman 		fatal("input_service_request: no authctxt");
15409958426SBrian Feldman 
155a04a10f8SKris Kennaway 	if (strcmp(service, "ssh-userauth") == 0) {
15609958426SBrian Feldman 		if (!authctxt->success) {
157a04a10f8SKris Kennaway 			accept = 1;
158a04a10f8SKris Kennaway 			/* now we can handle user-auth requests */
159a04a10f8SKris Kennaway 			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
160a04a10f8SKris Kennaway 		}
161a04a10f8SKris Kennaway 	}
162a04a10f8SKris Kennaway 	/* XXX all other service requests are denied */
163a04a10f8SKris Kennaway 
164a04a10f8SKris Kennaway 	if (accept) {
165a04a10f8SKris Kennaway 		packet_start(SSH2_MSG_SERVICE_ACCEPT);
166a04a10f8SKris Kennaway 		packet_put_cstring(service);
167a04a10f8SKris Kennaway 		packet_send();
168a04a10f8SKris Kennaway 		packet_write_wait();
169a04a10f8SKris Kennaway 	} else {
170a04a10f8SKris Kennaway 		debug("bad service request %s", service);
171a04a10f8SKris Kennaway 		packet_disconnect("bad service request %s", service);
172a04a10f8SKris Kennaway 	}
173a04a10f8SKris Kennaway 	xfree(service);
174a04a10f8SKris Kennaway }
175a04a10f8SKris Kennaway 
176a04a10f8SKris Kennaway void
17709958426SBrian Feldman input_userauth_request(int type, int plen, void *ctxt)
178a04a10f8SKris Kennaway {
17909958426SBrian Feldman 	Authctxt *authctxt = ctxt;
18009958426SBrian Feldman 	Authmethod *m = NULL;
181a04a10f8SKris Kennaway 	int authenticated = 0;
182c2d3a559SKris Kennaway 	char *user, *service, *method, *authmsg = NULL;
18303e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP
18403e72be8SBrian Feldman 	login_cap_t *lc;
18503e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP */
18603e72be8SBrian Feldman #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
18703e72be8SBrian Feldman 	const char *from_host, *from_ip;
18803e72be8SBrian Feldman 
18903e72be8SBrian Feldman 	from_host = get_canonical_hostname();
19003e72be8SBrian Feldman 	from_ip = get_remote_ipaddr();
19103e72be8SBrian Feldman #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
192a04a10f8SKris Kennaway 
19309958426SBrian Feldman 	if (authctxt == NULL)
19409958426SBrian Feldman 		fatal("input_userauth_request: no authctxt");
19509958426SBrian Feldman 	if (authctxt->attempt++ >= AUTH_FAIL_MAX)
196a04a10f8SKris Kennaway 		packet_disconnect("too many failed userauth_requests");
197a04a10f8SKris Kennaway 
19809958426SBrian Feldman 	user = packet_get_string(NULL);
19909958426SBrian Feldman 	service = packet_get_string(NULL);
20009958426SBrian Feldman 	method = packet_get_string(NULL);
201a04a10f8SKris Kennaway 	debug("userauth-request for user %s service %s method %s", user, service, method);
20209958426SBrian Feldman 	debug("attempt #%d", authctxt->attempt);
203a04a10f8SKris Kennaway 
20409958426SBrian Feldman 	if (authctxt->attempt == 1) {
20509958426SBrian Feldman 		/* setup auth context */
20609958426SBrian Feldman 		struct passwd *pw = NULL;
20709958426SBrian Feldman 		setproctitle("%s", user);
20809958426SBrian Feldman 		pw = getpwnam(user);
20909958426SBrian Feldman 		if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
21009958426SBrian Feldman 			authctxt->pw = pwcopy(pw);
21109958426SBrian Feldman 			authctxt->valid = 1;
21209958426SBrian Feldman 			debug2("input_userauth_request: setting up authctxt for %s", user);
21309958426SBrian Feldman #ifdef USE_PAM
21409958426SBrian Feldman 			start_pam(pw);
21509958426SBrian Feldman #endif
21609958426SBrian Feldman 		} else {
21709958426SBrian Feldman 			log("input_userauth_request: illegal user %s", user);
218a04a10f8SKris Kennaway 		}
21909958426SBrian Feldman 		authctxt->user = xstrdup(user);
22009958426SBrian Feldman 		authctxt->service = xstrdup(service);
22109958426SBrian Feldman 	} else if (authctxt->valid) {
22209958426SBrian Feldman 		if (strcmp(user, authctxt->user) != 0 ||
22309958426SBrian Feldman 		    strcmp(service, authctxt->service) != 0) {
22409958426SBrian Feldman 			log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
22509958426SBrian Feldman 			    user, service, authctxt->user, authctxt->service);
22609958426SBrian Feldman 			authctxt->valid = 0;
227a04a10f8SKris Kennaway 		}
228a04a10f8SKris Kennaway 	}
229a04a10f8SKris Kennaway 
23003e72be8SBrian Feldman #ifdef HAVE_LOGIN_CAP
23109958426SBrian Feldman 	if (authctxt->pw != NULL) {
23209958426SBrian Feldman 		lc = login_getpwclass(authctxt->pw);
23303e72be8SBrian Feldman 		if (lc == NULL)
23409958426SBrian Feldman 			lc = login_getclassbyname(NULL, authctxt->pw);
23503e72be8SBrian Feldman 		if (!auth_hostok(lc, from_host, from_ip)) {
23603e72be8SBrian Feldman 			log("Denied connection for %.200s from %.200s [%.200s].",
23709958426SBrian Feldman 			    authctxt->pw->pw_name, from_host, from_ip);
23803e72be8SBrian Feldman 			packet_disconnect("Sorry, you are not allowed to connect.");
23903e72be8SBrian Feldman 		}
24003e72be8SBrian Feldman 		if (!auth_timeok(lc, time(NULL))) {
24103e72be8SBrian Feldman 			log("LOGIN %.200s REFUSED (TIME) FROM %.200s",
24209958426SBrian Feldman 			    authctxt->pw->pw_name, from_host);
24303e72be8SBrian Feldman 			packet_disconnect("Logins not available right now.");
24403e72be8SBrian Feldman 		}
24503e72be8SBrian Feldman 		login_close(lc);
24609958426SBrian Feldman 		lc = NULL;
24709958426SBrian Feldman 	}
24803e72be8SBrian Feldman #endif  /* HAVE_LOGIN_CAP */
24903e72be8SBrian Feldman #ifdef LOGIN_ACCESS
25009958426SBrian Feldman 	if (authctxt->pw != NULL &&
25109958426SBrian Feldman 	    !login_access(authctxt->pw->pw_name, from_host)) {
25203e72be8SBrian Feldman 		log("Denied connection for %.200s from %.200s [%.200s].",
25309958426SBrian Feldman 		    authctxt->pw->pw_name, from_host, from_ip);
25403e72be8SBrian Feldman 		packet_disconnect("Sorry, you are not allowed to connect.");
25503e72be8SBrian Feldman 	}
25603e72be8SBrian Feldman #endif /* LOGIN_ACCESS */
25703e72be8SBrian Feldman 
25809958426SBrian Feldman 	m = authmethod_lookup(method);
25909958426SBrian Feldman 	if (m != NULL) {
26009958426SBrian Feldman 		debug2("input_userauth_request: try method %s", method);
26109958426SBrian Feldman 		authenticated =	m->userauth(authctxt);
26209958426SBrian Feldman 	} else {
26309958426SBrian Feldman 		debug2("input_userauth_request: unsupported method %s", method);
26409958426SBrian Feldman 	}
26509958426SBrian Feldman 	if (!authctxt->valid && authenticated == 1) {
26609958426SBrian Feldman 		log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
26709958426SBrian Feldman 		authenticated = 0;
26809958426SBrian Feldman 	}
26909958426SBrian Feldman 
27009958426SBrian Feldman 	/* Special handling for root */
27109958426SBrian Feldman 	if (authenticated == 1 &&
27209958426SBrian Feldman 	    authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
27309958426SBrian Feldman 		authenticated = 0;
27409958426SBrian Feldman 		log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
27509958426SBrian Feldman 	}
27609958426SBrian Feldman 
27709958426SBrian Feldman #ifdef USE_PAM
27809958426SBrian Feldman 	if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL))
27909958426SBrian Feldman 		authenticated = 0;
28009958426SBrian Feldman #endif /* USE_PAM */
28109958426SBrian Feldman 
28209958426SBrian Feldman 	/* Log before sending the reply */
28309958426SBrian Feldman 	userauth_log(authctxt, authenticated, method);
28409958426SBrian Feldman 	userauth_reply(authctxt, authenticated);
28509958426SBrian Feldman 
28609958426SBrian Feldman 	xfree(service);
28709958426SBrian Feldman 	xfree(user);
28809958426SBrian Feldman 	xfree(method);
28909958426SBrian Feldman }
29009958426SBrian Feldman 
29109958426SBrian Feldman 
29209958426SBrian Feldman void
29309958426SBrian Feldman userauth_log(Authctxt *authctxt, int authenticated, char *method)
29409958426SBrian Feldman {
29509958426SBrian Feldman 	void (*authlog) (const char *fmt,...) = verbose;
29609958426SBrian Feldman 	char *user = NULL, *authmsg = NULL;
29709958426SBrian Feldman 
298a04a10f8SKris Kennaway 	/* Raise logging level */
299a04a10f8SKris Kennaway 	if (authenticated == 1 ||
30009958426SBrian Feldman 	    !authctxt->valid ||
30109958426SBrian Feldman 	    authctxt->attempt >= AUTH_FAIL_LOG ||
302a04a10f8SKris Kennaway 	    strcmp(method, "password") == 0)
303a04a10f8SKris Kennaway 		authlog = log;
304a04a10f8SKris Kennaway 
305a04a10f8SKris Kennaway 	if (authenticated == 1) {
306a04a10f8SKris Kennaway 		authmsg = "Accepted";
307a04a10f8SKris Kennaway 	} else if (authenticated == 0) {
308a04a10f8SKris Kennaway 		authmsg = "Failed";
309a04a10f8SKris Kennaway 	} else {
310a04a10f8SKris Kennaway 		authmsg = "Postponed";
311a04a10f8SKris Kennaway 	}
31209958426SBrian Feldman 
31309958426SBrian Feldman 	if (authctxt->valid) {
31409958426SBrian Feldman 		user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
31509958426SBrian Feldman 	} else {
31609958426SBrian Feldman 		user = "NOUSER";
31709958426SBrian Feldman 	}
31809958426SBrian Feldman 
319a04a10f8SKris Kennaway 	authlog("%s %s for %.200s from %.200s port %d ssh2",
320a04a10f8SKris Kennaway 	    authmsg,
321a04a10f8SKris Kennaway 	    method,
32209958426SBrian Feldman 	    user,
323a04a10f8SKris Kennaway 	    get_remote_ipaddr(),
324a04a10f8SKris Kennaway 	    get_remote_port());
32509958426SBrian Feldman }
326a04a10f8SKris Kennaway 
32709958426SBrian Feldman void
32809958426SBrian Feldman userauth_reply(Authctxt *authctxt, int authenticated)
32909958426SBrian Feldman {
330a04a10f8SKris Kennaway 	/* XXX todo: check if multiple auth methods are needed */
331a04a10f8SKris Kennaway 	if (authenticated == 1) {
332a04a10f8SKris Kennaway 		/* turn off userauth */
333a04a10f8SKris Kennaway 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
334a04a10f8SKris Kennaway 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
335a04a10f8SKris Kennaway 		packet_send();
336a04a10f8SKris Kennaway 		packet_write_wait();
337a04a10f8SKris Kennaway 		/* now we can break out */
33809958426SBrian Feldman 		authctxt->success = 1;
339a04a10f8SKris Kennaway 	} else if (authenticated == 0) {
34009958426SBrian Feldman 		char *methods = authmethods_get();
341a04a10f8SKris Kennaway 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
34209958426SBrian Feldman 		packet_put_cstring(methods);
343a04a10f8SKris Kennaway 		packet_put_char(0);	/* XXX partial success, unused */
344a04a10f8SKris Kennaway 		packet_send();
345a04a10f8SKris Kennaway 		packet_write_wait();
34609958426SBrian Feldman 		xfree(methods);
34709958426SBrian Feldman 	} else {
34809958426SBrian Feldman 		/* do nothing, we did already send a reply */
349a04a10f8SKris Kennaway 	}
350a04a10f8SKris Kennaway }
351a04a10f8SKris Kennaway 
352a04a10f8SKris Kennaway int
35309958426SBrian Feldman userauth_none(Authctxt *authctxt)
354a04a10f8SKris Kennaway {
35509958426SBrian Feldman 	/* disable method "none", only allowed one time */
35609958426SBrian Feldman 	Authmethod *m = authmethod_lookup("none");
35709958426SBrian Feldman 	if (m != NULL)
35809958426SBrian Feldman 		m->enabled = NULL;
359a04a10f8SKris Kennaway 	packet_done();
36009958426SBrian Feldman #ifdef USE_PAM
36109958426SBrian Feldman 	return authctxt->valid ? auth_pam_password(authctxt->pw, "") : 0;
36209958426SBrian Feldman #else /* !USE_PAM */
36309958426SBrian Feldman 	return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
36409958426SBrian Feldman #endif /* USE_PAM */
365a04a10f8SKris Kennaway }
36609958426SBrian Feldman 
367a04a10f8SKris Kennaway int
36809958426SBrian Feldman userauth_passwd(Authctxt *authctxt)
369a04a10f8SKris Kennaway {
370a04a10f8SKris Kennaway 	char *password;
371a04a10f8SKris Kennaway 	int authenticated = 0;
372a04a10f8SKris Kennaway 	int change;
373a04a10f8SKris Kennaway 	unsigned int len;
374a04a10f8SKris Kennaway 	change = packet_get_char();
375a04a10f8SKris Kennaway 	if (change)
376a04a10f8SKris Kennaway 		log("password change not supported");
377a04a10f8SKris Kennaway 	password = packet_get_string(&len);
378a04a10f8SKris Kennaway 	packet_done();
37909958426SBrian Feldman 	if (authctxt->valid &&
38009958426SBrian Feldman #ifdef USE_PAM
38109958426SBrian Feldman 	    auth_pam_password(authctxt->pw, password) == 1
38209958426SBrian Feldman #else
38309958426SBrian Feldman 	    auth_password(authctxt->pw, password) == 1
38409958426SBrian Feldman #endif
38509958426SBrian Feldman 	    )
386a04a10f8SKris Kennaway 		authenticated = 1;
387a04a10f8SKris Kennaway 	memset(password, 0, len);
388a04a10f8SKris Kennaway 	xfree(password);
389a04a10f8SKris Kennaway 	return authenticated;
390a04a10f8SKris Kennaway }
39109958426SBrian Feldman 
392a04a10f8SKris Kennaway int
39309958426SBrian Feldman userauth_kbdint(Authctxt *authctxt)
39409958426SBrian Feldman {
39509958426SBrian Feldman 	int authenticated = 0;
39609958426SBrian Feldman 	char *lang = NULL;
39709958426SBrian Feldman 	char *devs = NULL;
39809958426SBrian Feldman 
39909958426SBrian Feldman 	lang = packet_get_string(NULL);
40009958426SBrian Feldman 	devs = packet_get_string(NULL);
40109958426SBrian Feldman 	packet_done();
40209958426SBrian Feldman 
40309958426SBrian Feldman 	debug("keyboard-interactive language %s devs %s", lang, devs);
40409958426SBrian Feldman #ifdef SKEY
40509958426SBrian Feldman 	/* XXX hardcoded, we should look at devs */
40609958426SBrian Feldman 	if (options.skey_authentication != 0)
40709958426SBrian Feldman 		authenticated = auth2_skey(authctxt);
40809958426SBrian Feldman #endif
40909958426SBrian Feldman 	xfree(lang);
41009958426SBrian Feldman 	xfree(devs);
41109958426SBrian Feldman 	return authenticated;
41209958426SBrian Feldman }
41309958426SBrian Feldman 
41409958426SBrian Feldman int
41509958426SBrian Feldman userauth_pubkey(Authctxt *authctxt)
416a04a10f8SKris Kennaway {
417a04a10f8SKris Kennaway 	Buffer b;
418a04a10f8SKris Kennaway 	Key *key;
419a04a10f8SKris Kennaway 	char *pkalg, *pkblob, *sig;
420a04a10f8SKris Kennaway 	unsigned int alen, blen, slen;
421a04a10f8SKris Kennaway 	int have_sig;
422a04a10f8SKris Kennaway 	int authenticated = 0;
423a04a10f8SKris Kennaway 
42409958426SBrian Feldman 	if (!authctxt->valid) {
42509958426SBrian Feldman 		debug2("userauth_pubkey: disabled because of invalid user");
426a04a10f8SKris Kennaway 		return 0;
427a04a10f8SKris Kennaway 	}
428a04a10f8SKris Kennaway 	have_sig = packet_get_char();
429a04a10f8SKris Kennaway 	pkalg = packet_get_string(&alen);
430a04a10f8SKris Kennaway 	if (strcmp(pkalg, KEX_DSS) != 0) {
431a04a10f8SKris Kennaway 		log("bad pkalg %s", pkalg);	/*XXX*/
43209958426SBrian Feldman 		xfree(pkalg);
433a04a10f8SKris Kennaway 		return 0;
434a04a10f8SKris Kennaway 	}
435a04a10f8SKris Kennaway 	pkblob = packet_get_string(&blen);
436a04a10f8SKris Kennaway 	key = dsa_key_from_blob(pkblob, blen);
437a04a10f8SKris Kennaway 	if (key != NULL) {
438a04a10f8SKris Kennaway 		if (have_sig) {
439a04a10f8SKris Kennaway 			sig = packet_get_string(&slen);
440a04a10f8SKris Kennaway 			packet_done();
441a04a10f8SKris Kennaway 			buffer_init(&b);
44209958426SBrian Feldman 			if (datafellows & SSH_OLD_SESSIONID) {
443a04a10f8SKris Kennaway 				buffer_append(&b, session_id2, session_id2_len);
44409958426SBrian Feldman 			} else {
44509958426SBrian Feldman 				buffer_put_string(&b, session_id2, session_id2_len);
446c2d3a559SKris Kennaway 			}
447c2d3a559SKris Kennaway 			/* reconstruct packet */
448a04a10f8SKris Kennaway 			buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
44909958426SBrian Feldman 			buffer_put_cstring(&b, authctxt->user);
450c2d3a559SKris Kennaway 			buffer_put_cstring(&b,
451c2d3a559SKris Kennaway 			    datafellows & SSH_BUG_PUBKEYAUTH ?
452c2d3a559SKris Kennaway 			    "ssh-userauth" :
45309958426SBrian Feldman 			    authctxt->service);
454c2d3a559SKris Kennaway 			buffer_put_cstring(&b, "publickey");
455c2d3a559SKris Kennaway 			buffer_put_char(&b, have_sig);
456c2d3a559SKris Kennaway 			buffer_put_cstring(&b, KEX_DSS);
457c2d3a559SKris Kennaway 			buffer_put_string(&b, pkblob, blen);
458a04a10f8SKris Kennaway #ifdef DEBUG_DSS
459a04a10f8SKris Kennaway 			buffer_dump(&b);
460a04a10f8SKris Kennaway #endif
461a04a10f8SKris Kennaway 			/* test for correct signature */
46209958426SBrian Feldman 			if (user_dsa_key_allowed(authctxt->pw, key) &&
463a04a10f8SKris Kennaway 			    dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
464a04a10f8SKris Kennaway 				authenticated = 1;
465a04a10f8SKris Kennaway 			buffer_clear(&b);
466a04a10f8SKris Kennaway 			xfree(sig);
467a04a10f8SKris Kennaway 		} else {
46809958426SBrian Feldman 			debug("test whether pkalg/pkblob are acceptable");
469a04a10f8SKris Kennaway 			packet_done();
47009958426SBrian Feldman 
471a04a10f8SKris Kennaway 			/* XXX fake reply and always send PK_OK ? */
472a04a10f8SKris Kennaway 			/*
473a04a10f8SKris Kennaway 			 * XXX this allows testing whether a user is allowed
474a04a10f8SKris Kennaway 			 * to login: if you happen to have a valid pubkey this
475a04a10f8SKris Kennaway 			 * message is sent. the message is NEVER sent at all
476a04a10f8SKris Kennaway 			 * if a user is not allowed to login. is this an
477a04a10f8SKris Kennaway 			 * issue? -markus
478a04a10f8SKris Kennaway 			 */
47909958426SBrian Feldman 			if (user_dsa_key_allowed(authctxt->pw, key)) {
480a04a10f8SKris Kennaway 				packet_start(SSH2_MSG_USERAUTH_PK_OK);
481a04a10f8SKris Kennaway 				packet_put_string(pkalg, alen);
482a04a10f8SKris Kennaway 				packet_put_string(pkblob, blen);
483a04a10f8SKris Kennaway 				packet_send();
484a04a10f8SKris Kennaway 				packet_write_wait();
485a04a10f8SKris Kennaway 				authenticated = -1;
486a04a10f8SKris Kennaway 			}
487a04a10f8SKris Kennaway 		}
48809958426SBrian Feldman 		if (authenticated != 1)
48909958426SBrian Feldman 			auth_clear_options();
490a04a10f8SKris Kennaway 		key_free(key);
491a04a10f8SKris Kennaway 	}
492a04a10f8SKris Kennaway 	xfree(pkalg);
493a04a10f8SKris Kennaway 	xfree(pkblob);
494a04a10f8SKris Kennaway 	return authenticated;
495a04a10f8SKris Kennaway }
496a04a10f8SKris Kennaway 
49709958426SBrian Feldman /* get current user */
498a04a10f8SKris Kennaway 
499a04a10f8SKris Kennaway struct passwd*
500a04a10f8SKris Kennaway auth_get_user(void)
501a04a10f8SKris Kennaway {
50209958426SBrian Feldman 	return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
503a04a10f8SKris Kennaway }
504a04a10f8SKris Kennaway 
50509958426SBrian Feldman #define	DELIM	","
50609958426SBrian Feldman 
50709958426SBrian Feldman char *
50809958426SBrian Feldman authmethods_get(void)
509a04a10f8SKris Kennaway {
51009958426SBrian Feldman 	Authmethod *method = NULL;
51109958426SBrian Feldman 	unsigned int size = 0;
51209958426SBrian Feldman 	char *list;
513a04a10f8SKris Kennaway 
51409958426SBrian Feldman 	for (method = authmethods; method->name != NULL; method++) {
51509958426SBrian Feldman 		if (strcmp(method->name, "none") == 0)
51609958426SBrian Feldman 			continue;
51709958426SBrian Feldman 		if (method->enabled != NULL && *(method->enabled) != 0) {
51809958426SBrian Feldman 			if (size != 0)
51909958426SBrian Feldman 				size += strlen(DELIM);
52009958426SBrian Feldman 			size += strlen(method->name);
52109958426SBrian Feldman 		}
52209958426SBrian Feldman 	}
52309958426SBrian Feldman 	size++;			/* trailing '\0' */
52409958426SBrian Feldman 	list = xmalloc(size);
52509958426SBrian Feldman 	list[0] = '\0';
52609958426SBrian Feldman 
52709958426SBrian Feldman 	for (method = authmethods; method->name != NULL; method++) {
52809958426SBrian Feldman 		if (strcmp(method->name, "none") == 0)
52909958426SBrian Feldman 			continue;
53009958426SBrian Feldman 		if (method->enabled != NULL && *(method->enabled) != 0) {
53109958426SBrian Feldman 			if (list[0] != '\0')
53209958426SBrian Feldman 				strlcat(list, DELIM, size);
53309958426SBrian Feldman 			strlcat(list, method->name, size);
53409958426SBrian Feldman 		}
53509958426SBrian Feldman 	}
53609958426SBrian Feldman 	return list;
53709958426SBrian Feldman }
53809958426SBrian Feldman 
53909958426SBrian Feldman Authmethod *
54009958426SBrian Feldman authmethod_lookup(const char *name)
54109958426SBrian Feldman {
54209958426SBrian Feldman 	Authmethod *method = NULL;
54309958426SBrian Feldman 	if (name != NULL)
54409958426SBrian Feldman 		for (method = authmethods; method->name != NULL; method++)
54509958426SBrian Feldman 			if (method->enabled != NULL &&
54609958426SBrian Feldman 			    *(method->enabled) != 0 &&
54709958426SBrian Feldman 			    strcmp(name, method->name) == 0)
54809958426SBrian Feldman 				return method;
54909958426SBrian Feldman 	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
550a04a10f8SKris Kennaway 	return NULL;
551a04a10f8SKris Kennaway }
552a04a10f8SKris Kennaway 
553a04a10f8SKris Kennaway /* return 1 if user allows given key */
554a04a10f8SKris Kennaway int
555a04a10f8SKris Kennaway user_dsa_key_allowed(struct passwd *pw, Key *key)
556a04a10f8SKris Kennaway {
557a04a10f8SKris Kennaway 	char line[8192], file[1024];
558a04a10f8SKris Kennaway 	int found_key = 0;
559a04a10f8SKris Kennaway 	unsigned int bits = -1;
560a04a10f8SKris Kennaway 	FILE *f;
561a04a10f8SKris Kennaway 	unsigned long linenum = 0;
562a04a10f8SKris Kennaway 	struct stat st;
563a04a10f8SKris Kennaway 	Key *found;
564a04a10f8SKris Kennaway 
56509958426SBrian Feldman 	if (pw == NULL)
56609958426SBrian Feldman 		return 0;
56709958426SBrian Feldman 
568a04a10f8SKris Kennaway 	/* Temporarily use the user's uid. */
569a04a10f8SKris Kennaway 	temporarily_use_uid(pw->pw_uid);
570a04a10f8SKris Kennaway 
571a04a10f8SKris Kennaway 	/* The authorized keys. */
572a04a10f8SKris Kennaway 	snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
573a04a10f8SKris Kennaway 	    SSH_USER_PERMITTED_KEYS2);
574a04a10f8SKris Kennaway 
575a04a10f8SKris Kennaway 	/* Fail quietly if file does not exist */
576a04a10f8SKris Kennaway 	if (stat(file, &st) < 0) {
577a04a10f8SKris Kennaway 		/* Restore the privileged uid. */
578a04a10f8SKris Kennaway 		restore_uid();
579a04a10f8SKris Kennaway 		return 0;
580a04a10f8SKris Kennaway 	}
581a04a10f8SKris Kennaway 	/* Open the file containing the authorized keys. */
582a04a10f8SKris Kennaway 	f = fopen(file, "r");
583a04a10f8SKris Kennaway 	if (!f) {
584a04a10f8SKris Kennaway 		/* Restore the privileged uid. */
585a04a10f8SKris Kennaway 		restore_uid();
586a04a10f8SKris Kennaway 		return 0;
587a04a10f8SKris Kennaway 	}
588a04a10f8SKris Kennaway 	if (options.strict_modes) {
589a04a10f8SKris Kennaway 		int fail = 0;
590a04a10f8SKris Kennaway 		char buf[1024];
591a04a10f8SKris Kennaway 		/* Check open file in order to avoid open/stat races */
592a04a10f8SKris Kennaway 		if (fstat(fileno(f), &st) < 0 ||
593a04a10f8SKris Kennaway 		    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
594a04a10f8SKris Kennaway 		    (st.st_mode & 022) != 0) {
59509958426SBrian Feldman 			snprintf(buf, sizeof buf,
59609958426SBrian Feldman 			    "%s authentication refused for %.100s: "
59709958426SBrian Feldman 			    "bad ownership or modes for '%s'.",
59809958426SBrian Feldman 			    key_type(key), pw->pw_name, file);
599a04a10f8SKris Kennaway 			fail = 1;
600a04a10f8SKris Kennaway 		} else {
601a04a10f8SKris Kennaway 			/* Check path to SSH_USER_PERMITTED_KEYS */
602a04a10f8SKris Kennaway 			int i;
603a04a10f8SKris Kennaway 			static const char *check[] = {
604a04a10f8SKris Kennaway 				"", SSH_USER_DIR, NULL
605a04a10f8SKris Kennaway 			};
606a04a10f8SKris Kennaway 			for (i = 0; check[i]; i++) {
607a04a10f8SKris Kennaway 				snprintf(line, sizeof line, "%.500s/%.100s",
608a04a10f8SKris Kennaway 				    pw->pw_dir, check[i]);
609a04a10f8SKris Kennaway 				if (stat(line, &st) < 0 ||
610a04a10f8SKris Kennaway 				    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
611a04a10f8SKris Kennaway 				    (st.st_mode & 022) != 0) {
612a04a10f8SKris Kennaway 					snprintf(buf, sizeof buf,
61309958426SBrian Feldman 					    "%s authentication refused for %.100s: "
614a04a10f8SKris Kennaway 					    "bad ownership or modes for '%s'.",
61509958426SBrian Feldman 					    key_type(key), pw->pw_name, line);
616a04a10f8SKris Kennaway 					fail = 1;
617a04a10f8SKris Kennaway 					break;
618a04a10f8SKris Kennaway 				}
619a04a10f8SKris Kennaway 			}
620a04a10f8SKris Kennaway 		}
621a04a10f8SKris Kennaway 		if (fail) {
622a04a10f8SKris Kennaway 			fclose(f);
623c2d3a559SKris Kennaway 			log("%s",buf);
624a04a10f8SKris Kennaway 			restore_uid();
625a04a10f8SKris Kennaway 			return 0;
626a04a10f8SKris Kennaway 		}
627a04a10f8SKris Kennaway 	}
628a04a10f8SKris Kennaway 	found_key = 0;
62909958426SBrian Feldman 	found = key_new(key->type);
630a04a10f8SKris Kennaway 
631a04a10f8SKris Kennaway 	while (fgets(line, sizeof(line), f)) {
632c2d3a559SKris Kennaway 		char *cp, *options = NULL;
633a04a10f8SKris Kennaway 		linenum++;
634a04a10f8SKris Kennaway 		/* Skip leading whitespace, empty and comment lines. */
635a04a10f8SKris Kennaway 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
636a04a10f8SKris Kennaway 			;
637a04a10f8SKris Kennaway 		if (!*cp || *cp == '\n' || *cp == '#')
638a04a10f8SKris Kennaway 			continue;
639c2d3a559SKris Kennaway 
640a04a10f8SKris Kennaway 		bits = key_read(found, &cp);
641c2d3a559SKris Kennaway 		if (bits == 0) {
642c2d3a559SKris Kennaway 			/* no key?  check if there are options for this key */
643c2d3a559SKris Kennaway 			int quoted = 0;
644c2d3a559SKris Kennaway 			options = cp;
645c2d3a559SKris Kennaway 			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
646c2d3a559SKris Kennaway 				if (*cp == '\\' && cp[1] == '"')
647c2d3a559SKris Kennaway 					cp++;	/* Skip both */
648c2d3a559SKris Kennaway 				else if (*cp == '"')
649c2d3a559SKris Kennaway 					quoted = !quoted;
650c2d3a559SKris Kennaway 			}
651c2d3a559SKris Kennaway 			/* Skip remaining whitespace. */
652c2d3a559SKris Kennaway 			for (; *cp == ' ' || *cp == '\t'; cp++)
653c2d3a559SKris Kennaway 				;
654c2d3a559SKris Kennaway 			bits = key_read(found, &cp);
655c2d3a559SKris Kennaway 			if (bits == 0) {
656c2d3a559SKris Kennaway 				/* still no key?  advance to next line*/
657a04a10f8SKris Kennaway 				continue;
658c2d3a559SKris Kennaway 			}
659c2d3a559SKris Kennaway 		}
660c2d3a559SKris Kennaway 		if (key_equal(found, key) &&
661c2d3a559SKris Kennaway 		    auth_parse_options(pw, options, linenum) == 1) {
662a04a10f8SKris Kennaway 			found_key = 1;
663a04a10f8SKris Kennaway 			debug("matching key found: file %s, line %ld",
664a04a10f8SKris Kennaway 			    file, linenum);
665a04a10f8SKris Kennaway 			break;
666a04a10f8SKris Kennaway 		}
667a04a10f8SKris Kennaway 	}
668a04a10f8SKris Kennaway 	restore_uid();
669a04a10f8SKris Kennaway 	fclose(f);
670a04a10f8SKris Kennaway 	key_free(found);
671a04a10f8SKris Kennaway 	return found_key;
672a04a10f8SKris Kennaway }
67309958426SBrian Feldman 
67409958426SBrian Feldman struct passwd *
67509958426SBrian Feldman pwcopy(struct passwd *pw)
67609958426SBrian Feldman {
67709958426SBrian Feldman 	struct passwd *copy = xmalloc(sizeof(*copy));
67809958426SBrian Feldman 	memset(copy, 0, sizeof(*copy));
67909958426SBrian Feldman 	copy->pw_name = xstrdup(pw->pw_name);
68009958426SBrian Feldman 	copy->pw_passwd = xstrdup(pw->pw_passwd);
68109958426SBrian Feldman 	copy->pw_uid = pw->pw_uid;
68209958426SBrian Feldman 	copy->pw_gid = pw->pw_gid;
68309958426SBrian Feldman 	copy->pw_class = xstrdup(pw->pw_class);
68409958426SBrian Feldman 	copy->pw_dir = xstrdup(pw->pw_dir);
68509958426SBrian Feldman 	copy->pw_shell = xstrdup(pw->pw_shell);
68609958426SBrian Feldman 	copy->pw_expire = pw->pw_expire;
68709958426SBrian Feldman 	copy->pw_change = pw->pw_change;
68809958426SBrian Feldman 	return copy;
68909958426SBrian Feldman }
690