auth2.c revision 92559
1/*
2 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: auth2.c,v 1.85 2002/02/24 19:14:59 markus Exp $");
27RCSID("$FreeBSD: head/crypto/openssh/auth2.c 92559 2002-03-18 10:09:43Z des $");
28
29#include <openssl/evp.h>
30
31#include "ssh2.h"
32#include "xmalloc.h"
33#include "rsa.h"
34#include "sshpty.h"
35#include "packet.h"
36#include "buffer.h"
37#include "log.h"
38#include "servconf.h"
39#include "compat.h"
40#include "channels.h"
41#include "bufaux.h"
42#include "auth.h"
43#include "session.h"
44#include "dispatch.h"
45#include "key.h"
46#include "cipher.h"
47#include "kex.h"
48#include "pathnames.h"
49#include "uidswap.h"
50#include "auth-options.h"
51#include "misc.h"
52#include "hostfile.h"
53#include "canohost.h"
54#include "match.h"
55
56#ifdef HAVE_LOGIN_CAP
57#include <login_cap.h>
58#endif /* HAVE_LOGIN_CAP */
59
60/* import */
61extern ServerOptions options;
62extern u_char *session_id2;
63extern int session_id2_len;
64
65static Authctxt	*x_authctxt = NULL;
66static int one = 1;
67
68typedef struct Authmethod Authmethod;
69struct Authmethod {
70	char	*name;
71	int	(*userauth)(Authctxt *authctxt);
72	int	*enabled;
73};
74
75/* protocol */
76
77static void input_service_request(int, u_int32_t, void *);
78static void input_userauth_request(int, u_int32_t, void *);
79
80/* helper */
81static Authmethod *authmethod_lookup(const char *);
82static char *authmethods_get(void);
83static int user_key_allowed(struct passwd *, Key *);
84static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
85
86/* auth */
87static void userauth_banner(void);
88static int userauth_none(Authctxt *);
89static int userauth_passwd(Authctxt *);
90static int userauth_pubkey(Authctxt *);
91static int userauth_hostbased(Authctxt *);
92static int userauth_kbdint(Authctxt *);
93
94Authmethod authmethods[] = {
95	{"none",
96		userauth_none,
97		&one},
98	{"publickey",
99		userauth_pubkey,
100		&options.pubkey_authentication},
101	{"password",
102		userauth_passwd,
103		&options.password_authentication},
104	{"keyboard-interactive",
105		userauth_kbdint,
106		&options.kbd_interactive_authentication},
107	{"hostbased",
108		userauth_hostbased,
109		&options.hostbased_authentication},
110	{NULL, NULL, NULL}
111};
112
113/*
114 * loop until authctxt->success == TRUE
115 */
116
117void
118do_authentication2(void)
119{
120	Authctxt *authctxt = authctxt_new();
121
122	x_authctxt = authctxt;		/*XXX*/
123
124	/* challenge-response is implemented via keyboard interactive */
125	if (options.challenge_response_authentication)
126		options.kbd_interactive_authentication = 1;
127
128	dispatch_init(&dispatch_protocol_error);
129	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
130	dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
131	do_authenticated(authctxt);
132}
133
134static void
135input_service_request(int type, u_int32_t seq, void *ctxt)
136{
137	Authctxt *authctxt = ctxt;
138	u_int len;
139	int accept = 0;
140	char *service = packet_get_string(&len);
141	packet_check_eom();
142
143	if (authctxt == NULL)
144		fatal("input_service_request: no authctxt");
145
146	if (strcmp(service, "ssh-userauth") == 0) {
147		if (!authctxt->success) {
148			accept = 1;
149			/* now we can handle user-auth requests */
150			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
151		}
152	}
153	/* XXX all other service requests are denied */
154
155	if (accept) {
156		packet_start(SSH2_MSG_SERVICE_ACCEPT);
157		packet_put_cstring(service);
158		packet_send();
159		packet_write_wait();
160	} else {
161		debug("bad service request %s", service);
162		packet_disconnect("bad service request %s", service);
163	}
164	xfree(service);
165}
166
167static void
168input_userauth_request(int type, u_int32_t seq, void *ctxt)
169{
170	Authctxt *authctxt = ctxt;
171	Authmethod *m = NULL;
172	char *user, *service, *method, *style = NULL;
173	int authenticated = 0;
174#ifdef HAVE_LOGIN_CAP
175	login_cap_t *lc;
176#endif /* HAVE_LOGIN_CAP */
177#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
178	const char *from_host, *from_ip;
179
180	from_host = get_canonical_hostname(options.verify_reverse_mapping);
181	from_ip = get_remote_ipaddr();
182#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
183
184	if (authctxt == NULL)
185		fatal("input_userauth_request: no authctxt");
186
187	user = packet_get_string(NULL);
188	service = packet_get_string(NULL);
189	method = packet_get_string(NULL);
190	debug("userauth-request for user %s service %s method %s", user, service, method);
191	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
192
193	if ((style = strchr(user, ':')) != NULL)
194		*style++ = 0;
195
196	if (authctxt->attempt++ == 0) {
197		/* setup auth context */
198		struct passwd *pw = NULL;
199		pw = getpwnam(user);
200		if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
201			authctxt->pw = pwcopy(pw);
202			authctxt->valid = 1;
203			debug2("input_userauth_request: setting up authctxt for %s", user);
204#ifdef USE_PAM
205			start_pam(pw);
206#endif
207		} else {
208			log("input_userauth_request: illegal user %s", user);
209			authctxt->pw = NULL;
210		}
211		setproctitle("%s", pw ? user : "unknown");
212		authctxt->user = xstrdup(user);
213		authctxt->service = xstrdup(service);
214		authctxt->style = style ? xstrdup(style) : NULL;
215	} else if (strcmp(user, authctxt->user) != 0 ||
216	    strcmp(service, authctxt->service) != 0) {
217		packet_disconnect("Change of username or service not allowed: "
218		    "(%s,%s) -> (%s,%s)",
219		    authctxt->user, authctxt->service, user, service);
220	}
221
222#ifdef HAVE_LOGIN_CAP
223	if (authctxt->pw != NULL) {
224		lc = login_getpwclass(authctxt->pw);
225		if (lc == NULL)
226			lc = login_getclassbyname(NULL, authctxt->pw);
227		if (!auth_hostok(lc, from_host, from_ip)) {
228			log("Denied connection for %.200s from %.200s [%.200s].",
229			    authctxt->pw->pw_name, from_host, from_ip);
230			packet_disconnect("Sorry, you are not allowed to connect.");
231		}
232		if (!auth_timeok(lc, time(NULL))) {
233			log("LOGIN %.200s REFUSED (TIME) FROM %.200s",
234			    authctxt->pw->pw_name, from_host);
235			packet_disconnect("Logins not available right now.");
236		}
237		login_close(lc);
238		lc = NULL;
239	}
240#endif  /* HAVE_LOGIN_CAP */
241#ifdef LOGIN_ACCESS
242	if (authctxt->pw != NULL &&
243	    !login_access(authctxt->pw->pw_name, from_host)) {
244		log("Denied connection for %.200s from %.200s [%.200s].",
245		    authctxt->pw->pw_name, from_host, from_ip);
246		packet_disconnect("Sorry, you are not allowed to connect.");
247	}
248#endif /* LOGIN_ACCESS */
249	/* reset state */
250	auth2_challenge_stop(authctxt);
251	authctxt->postponed = 0;
252
253	/* try to authenticate user */
254	m = authmethod_lookup(method);
255	if (m != NULL) {
256		debug2("input_userauth_request: try method %s", method);
257		authenticated =	m->userauth(authctxt);
258	}
259#ifdef USE_PAM
260	if (authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL))
261		authenticated = 0;
262#endif /* USE_PAM */
263	userauth_finish(authctxt, authenticated, method);
264
265	xfree(service);
266	xfree(user);
267	xfree(method);
268}
269
270void
271userauth_finish(Authctxt *authctxt, int authenticated, char *method)
272{
273	char *methods;
274
275	if (!authctxt->valid && authenticated)
276		fatal("INTERNAL ERROR: authenticated invalid user %s",
277		    authctxt->user);
278
279	/* Special handling for root */
280	if (authenticated && authctxt->pw->pw_uid == 0 &&
281	    !auth_root_allowed(method))
282		authenticated = 0;
283
284	/* Log before sending the reply */
285	auth_log(authctxt, authenticated, method, " ssh2");
286
287	if (authctxt->postponed)
288		return;
289
290	/* XXX todo: check if multiple auth methods are needed */
291	if (authenticated == 1) {
292		/* turn off userauth */
293		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
294		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
295		packet_send();
296		packet_write_wait();
297		/* now we can break out */
298		authctxt->success = 1;
299	} else {
300		if (authctxt->failures++ > AUTH_FAIL_MAX)
301			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
302		methods = authmethods_get();
303		packet_start(SSH2_MSG_USERAUTH_FAILURE);
304		packet_put_cstring(methods);
305		packet_put_char(0);	/* XXX partial success, unused */
306		packet_send();
307		packet_write_wait();
308		xfree(methods);
309	}
310}
311
312static void
313userauth_banner(void)
314{
315	struct stat st;
316	char *banner = NULL;
317	off_t len, n;
318	int fd;
319
320	if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
321		return;
322	if ((fd = open(options.banner, O_RDONLY)) < 0)
323		return;
324	if (fstat(fd, &st) < 0)
325		goto done;
326	len = st.st_size;
327	banner = xmalloc(len + 1);
328	if ((n = read(fd, banner, len)) < 0)
329		goto done;
330	banner[n] = '\0';
331	packet_start(SSH2_MSG_USERAUTH_BANNER);
332	packet_put_cstring(banner);
333	packet_put_cstring("");		/* language, unused */
334	packet_send();
335	debug("userauth_banner: sent");
336done:
337	if (banner)
338		xfree(banner);
339	close(fd);
340	return;
341}
342
343static int
344userauth_none(Authctxt *authctxt)
345{
346	/* disable method "none", only allowed one time */
347	Authmethod *m = authmethod_lookup("none");
348	if (m != NULL)
349		m->enabled = NULL;
350	packet_check_eom();
351	userauth_banner();
352#ifdef USE_PAM
353	return authctxt->valid ? auth_pam_password(authctxt, "") : 0;
354#else /* !USE_PAM */
355	return authctxt->valid ? auth_password(authctxt, "") : 0;
356#endif /* USE_PAM */
357}
358
359static int
360userauth_passwd(Authctxt *authctxt)
361{
362	char *password;
363	int authenticated = 0;
364	int change;
365	u_int len;
366	change = packet_get_char();
367	if (change)
368		log("password change not supported");
369	password = packet_get_string(&len);
370	packet_check_eom();
371	if (authctxt->valid &&
372#ifdef USE_PAM
373	    auth_password(authctxt, password) == 1)
374#else
375	    auth_password(authctxt, password) == 1)
376#endif
377		authenticated = 1;
378	memset(password, 0, len);
379	xfree(password);
380	return authenticated;
381}
382
383static int
384userauth_kbdint(Authctxt *authctxt)
385{
386	int authenticated = 0;
387	char *lang, *devs;
388
389	lang = packet_get_string(NULL);
390	devs = packet_get_string(NULL);
391	packet_check_eom();
392
393	debug("keyboard-interactive devs %s", devs);
394
395	if (options.challenge_response_authentication)
396		authenticated = auth2_challenge(authctxt, devs);
397
398	xfree(devs);
399	xfree(lang);
400	return authenticated;
401}
402
403static int
404userauth_pubkey(Authctxt *authctxt)
405{
406	Buffer b;
407	Key *key = NULL;
408	char *pkalg;
409	u_char *pkblob, *sig;
410	u_int alen, blen, slen;
411	int have_sig, pktype;
412	int authenticated = 0;
413
414	if (!authctxt->valid) {
415		debug2("userauth_pubkey: disabled because of invalid user");
416		return 0;
417	}
418	have_sig = packet_get_char();
419	if (datafellows & SSH_BUG_PKAUTH) {
420		debug2("userauth_pubkey: SSH_BUG_PKAUTH");
421		/* no explicit pkalg given */
422		pkblob = packet_get_string(&blen);
423		buffer_init(&b);
424		buffer_append(&b, pkblob, blen);
425		/* so we have to extract the pkalg from the pkblob */
426		pkalg = buffer_get_string(&b, &alen);
427		buffer_free(&b);
428	} else {
429		pkalg = packet_get_string(&alen);
430		pkblob = packet_get_string(&blen);
431	}
432	pktype = key_type_from_name(pkalg);
433	if (pktype == KEY_UNSPEC) {
434		/* this is perfectly legal */
435		log("userauth_pubkey: unsupported public key algorithm: %s",
436		    pkalg);
437		goto done;
438	}
439	key = key_from_blob(pkblob, blen);
440	if (key == NULL) {
441		error("userauth_pubkey: cannot decode key: %s", pkalg);
442		goto done;
443	}
444	if (key->type != pktype) {
445		error("userauth_pubkey: type mismatch for decoded key "
446		    "(received %d, expected %d)", key->type, pktype);
447		goto done;
448	}
449	if (have_sig) {
450		sig = packet_get_string(&slen);
451		packet_check_eom();
452		buffer_init(&b);
453		if (datafellows & SSH_OLD_SESSIONID) {
454			buffer_append(&b, session_id2, session_id2_len);
455		} else {
456			buffer_put_string(&b, session_id2, session_id2_len);
457		}
458		/* reconstruct packet */
459		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
460		buffer_put_cstring(&b, authctxt->user);
461		buffer_put_cstring(&b,
462		    datafellows & SSH_BUG_PKSERVICE ?
463		    "ssh-userauth" :
464		    authctxt->service);
465		if (datafellows & SSH_BUG_PKAUTH) {
466			buffer_put_char(&b, have_sig);
467		} else {
468			buffer_put_cstring(&b, "publickey");
469			buffer_put_char(&b, have_sig);
470			buffer_put_cstring(&b, pkalg);
471		}
472		buffer_put_string(&b, pkblob, blen);
473#ifdef DEBUG_PK
474		buffer_dump(&b);
475#endif
476		/* test for correct signature */
477		if (user_key_allowed(authctxt->pw, key) &&
478		    key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
479			authenticated = 1;
480		buffer_clear(&b);
481		xfree(sig);
482	} else {
483		debug("test whether pkalg/pkblob are acceptable");
484		packet_check_eom();
485
486		/* XXX fake reply and always send PK_OK ? */
487		/*
488		 * XXX this allows testing whether a user is allowed
489		 * to login: if you happen to have a valid pubkey this
490		 * message is sent. the message is NEVER sent at all
491		 * if a user is not allowed to login. is this an
492		 * issue? -markus
493		 */
494		if (user_key_allowed(authctxt->pw, key)) {
495			packet_start(SSH2_MSG_USERAUTH_PK_OK);
496			packet_put_string(pkalg, alen);
497			packet_put_string(pkblob, blen);
498			packet_send();
499			packet_write_wait();
500			authctxt->postponed = 1;
501		}
502	}
503	if (authenticated != 1)
504		auth_clear_options();
505done:
506	debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
507	if (key != NULL)
508		key_free(key);
509	xfree(pkalg);
510	xfree(pkblob);
511	return authenticated;
512}
513
514static int
515userauth_hostbased(Authctxt *authctxt)
516{
517	Buffer b;
518	Key *key = NULL;
519	char *pkalg, *cuser, *chost, *service;
520	u_char *pkblob, *sig;
521	u_int alen, blen, slen;
522	int pktype;
523	int authenticated = 0;
524
525	if (!authctxt->valid) {
526		debug2("userauth_hostbased: disabled because of invalid user");
527		return 0;
528	}
529	pkalg = packet_get_string(&alen);
530	pkblob = packet_get_string(&blen);
531	chost = packet_get_string(NULL);
532	cuser = packet_get_string(NULL);
533	sig = packet_get_string(&slen);
534
535	debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
536	    cuser, chost, pkalg, slen);
537#ifdef DEBUG_PK
538	debug("signature:");
539	buffer_init(&b);
540	buffer_append(&b, sig, slen);
541	buffer_dump(&b);
542	buffer_free(&b);
543#endif
544	pktype = key_type_from_name(pkalg);
545	if (pktype == KEY_UNSPEC) {
546		/* this is perfectly legal */
547		log("userauth_hostbased: unsupported "
548		    "public key algorithm: %s", pkalg);
549		goto done;
550	}
551	key = key_from_blob(pkblob, blen);
552	if (key == NULL) {
553		error("userauth_hostbased: cannot decode key: %s", pkalg);
554		goto done;
555	}
556	if (key->type != pktype) {
557		error("userauth_hostbased: type mismatch for decoded key "
558		    "(received %d, expected %d)", key->type, pktype);
559		goto done;
560	}
561	service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
562	    authctxt->service;
563	buffer_init(&b);
564	buffer_put_string(&b, session_id2, session_id2_len);
565	/* reconstruct packet */
566	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
567	buffer_put_cstring(&b, authctxt->user);
568	buffer_put_cstring(&b, service);
569	buffer_put_cstring(&b, "hostbased");
570	buffer_put_string(&b, pkalg, alen);
571	buffer_put_string(&b, pkblob, blen);
572	buffer_put_cstring(&b, chost);
573	buffer_put_cstring(&b, cuser);
574#ifdef DEBUG_PK
575	buffer_dump(&b);
576#endif
577	/* test for allowed key and correct signature */
578	if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
579	    key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
580		authenticated = 1;
581
582	buffer_clear(&b);
583done:
584	debug2("userauth_hostbased: authenticated %d", authenticated);
585	if (key != NULL)
586		key_free(key);
587	xfree(pkalg);
588	xfree(pkblob);
589	xfree(cuser);
590	xfree(chost);
591	xfree(sig);
592	return authenticated;
593}
594
595/* get current user */
596
597struct passwd*
598auth_get_user(void)
599{
600	return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
601}
602
603#define	DELIM	","
604
605static char *
606authmethods_get(void)
607{
608	Authmethod *method = NULL;
609	Buffer b;
610	char *list;
611
612	buffer_init(&b);
613	for (method = authmethods; method->name != NULL; method++) {
614		if (strcmp(method->name, "none") == 0)
615			continue;
616		if (method->enabled != NULL && *(method->enabled) != 0) {
617			if (buffer_len(&b) > 0)
618				buffer_append(&b, ",", 1);
619			buffer_append(&b, method->name, strlen(method->name));
620		}
621	}
622	buffer_append(&b, "\0", 1);
623	list = xstrdup(buffer_ptr(&b));
624	buffer_free(&b);
625	return list;
626}
627
628static Authmethod *
629authmethod_lookup(const char *name)
630{
631	Authmethod *method = NULL;
632	if (name != NULL)
633		for (method = authmethods; method->name != NULL; method++)
634			if (method->enabled != NULL &&
635			    *(method->enabled) != 0 &&
636			    strcmp(name, method->name) == 0)
637				return method;
638	debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
639	return NULL;
640}
641
642/* return 1 if user allows given key */
643static int
644user_key_allowed2(struct passwd *pw, Key *key, char *file)
645{
646	char line[8192];
647	int found_key = 0;
648	FILE *f;
649	u_long linenum = 0;
650	struct stat st;
651	Key *found;
652	char *fp;
653
654	if (pw == NULL)
655		return 0;
656
657	/* Temporarily use the user's uid. */
658	temporarily_use_uid(pw);
659
660	debug("trying public key file %s", file);
661
662	/* Fail quietly if file does not exist */
663	if (stat(file, &st) < 0) {
664		/* Restore the privileged uid. */
665		restore_uid();
666		return 0;
667	}
668	/* Open the file containing the authorized keys. */
669	f = fopen(file, "r");
670	if (!f) {
671		/* Restore the privileged uid. */
672		restore_uid();
673		return 0;
674	}
675	if (options.strict_modes &&
676	    secure_filename(f, file, pw, line, sizeof(line)) != 0) {
677		fclose(f);
678		log("Authentication refused: %s", line);
679		restore_uid();
680		return 0;
681	}
682
683	found_key = 0;
684	found = key_new(key->type);
685
686	while (fgets(line, sizeof(line), f)) {
687		char *cp, *options = NULL;
688		linenum++;
689		/* Skip leading whitespace, empty and comment lines. */
690		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
691			;
692		if (!*cp || *cp == '\n' || *cp == '#')
693			continue;
694
695		if (key_read(found, &cp) != 1) {
696			/* no key?  check if there are options for this key */
697			int quoted = 0;
698			debug2("user_key_allowed: check options: '%s'", cp);
699			options = cp;
700			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
701				if (*cp == '\\' && cp[1] == '"')
702					cp++;	/* Skip both */
703				else if (*cp == '"')
704					quoted = !quoted;
705			}
706			/* Skip remaining whitespace. */
707			for (; *cp == ' ' || *cp == '\t'; cp++)
708				;
709			if (key_read(found, &cp) != 1) {
710				debug2("user_key_allowed: advance: '%s'", cp);
711				/* still no key?  advance to next line*/
712				continue;
713			}
714		}
715		if (key_equal(found, key) &&
716		    auth_parse_options(pw, options, file, linenum) == 1) {
717			found_key = 1;
718			debug("matching key found: file %s, line %lu",
719			    file, linenum);
720			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
721			verbose("Found matching %s key: %s",
722			    key_type(found), fp);
723			xfree(fp);
724			break;
725		}
726	}
727	restore_uid();
728	fclose(f);
729	key_free(found);
730	if (!found_key)
731		debug2("key not found");
732	return found_key;
733}
734
735/* check whether given key is in .ssh/authorized_keys* */
736static int
737user_key_allowed(struct passwd *pw, Key *key)
738{
739	int success;
740	char *file;
741
742	file = authorized_keys_file(pw);
743	success = user_key_allowed2(pw, key, file);
744	xfree(file);
745	if (success)
746		return success;
747
748	/* try suffix "2" for backward compat, too */
749	file = authorized_keys_file2(pw);
750	success = user_key_allowed2(pw, key, file);
751	xfree(file);
752	return success;
753}
754
755/* return 1 if given hostkey is allowed */
756static int
757hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
758    Key *key)
759{
760	const char *resolvedname, *ipaddr, *lookup;
761	HostStatus host_status;
762	int len;
763
764	resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
765	ipaddr = get_remote_ipaddr();
766
767	debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
768	    chost, resolvedname, ipaddr);
769
770	if (options.hostbased_uses_name_from_packet_only) {
771		if (auth_rhosts2(pw, cuser, chost, chost) == 0)
772			return 0;
773		lookup = chost;
774	} else {
775		if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
776			debug2("stripping trailing dot from chost %s", chost);
777			chost[len - 1] = '\0';
778		}
779		if (strcasecmp(resolvedname, chost) != 0)
780			log("userauth_hostbased mismatch: "
781			    "client sends %s, but we resolve %s to %s",
782			    chost, ipaddr, resolvedname);
783		if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
784			return 0;
785		lookup = resolvedname;
786	}
787	debug2("userauth_hostbased: access allowed by auth_rhosts2");
788
789	host_status = check_key_in_hostfiles(pw, key, lookup,
790	    _PATH_SSH_SYSTEM_HOSTFILE,
791	    options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
792
793	/* backward compat if no key has been found. */
794	if (host_status == HOST_NEW)
795		host_status = check_key_in_hostfiles(pw, key, lookup,
796		    _PATH_SSH_SYSTEM_HOSTFILE2,
797		    options.ignore_user_known_hosts ? NULL :
798		    _PATH_SSH_USER_HOSTFILE2);
799
800	return (host_status == HOST_OK);
801}
802