auth2.c revision 68704
160573Skris/*
260573Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
360573Skris *
460573Skris * Redistribution and use in source and binary forms, with or without
560573Skris * modification, are permitted provided that the following conditions
660573Skris * are met:
760573Skris * 1. Redistributions of source code must retain the above copyright
860573Skris *    notice, this list of conditions and the following disclaimer.
960573Skris * 2. Redistributions in binary form must reproduce the above copyright
1060573Skris *    notice, this list of conditions and the following disclaimer in the
1160573Skris *    documentation and/or other materials provided with the distribution.
1260573Skris *
1360573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1460573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1560573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1660573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1760573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1860573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1960573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2060573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2160573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2260573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2360573Skris */
2465674Skris
2560573Skris#include "includes.h"
2665674SkrisRCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
2765674SkrisRCSID("$FreeBSD: head/crypto/openssh/auth2.c 68704 2000-11-14 04:35:03Z green $");
2860573Skris
2960573Skris#include <openssl/dsa.h>
3060573Skris#include <openssl/rsa.h>
3160573Skris#include <openssl/evp.h>
3260573Skris
3360573Skris#include "xmalloc.h"
3460573Skris#include "rsa.h"
3560573Skris#include "ssh.h"
3660573Skris#include "pty.h"
3760573Skris#include "packet.h"
3860573Skris#include "buffer.h"
3960573Skris#include "cipher.h"
4060573Skris#include "servconf.h"
4160573Skris#include "compat.h"
4260573Skris#include "channels.h"
4360573Skris#include "bufaux.h"
4460573Skris#include "ssh2.h"
4560573Skris#include "auth.h"
4660573Skris#include "session.h"
4760573Skris#include "dispatch.h"
4860573Skris#include "auth.h"
4960573Skris#include "key.h"
5060573Skris#include "kex.h"
5160573Skris
5260573Skris#include "dsa.h"
5360573Skris#include "uidswap.h"
5465674Skris#include "auth-options.h"
5560573Skris
5668704Sgreen#ifdef HAVE_LOGIN_CAP
5768704Sgreen#include <login_cap.h>
5868704Sgreen#endif /* HAVE_LOGIN_CAP */
5968704Sgreen
6060573Skris/* import */
6160573Skrisextern ServerOptions options;
6260573Skrisextern unsigned char *session_id2;
6360573Skrisextern int session_id2_len;
6460573Skris
6560573Skris/* protocol */
6660573Skris
6760573Skrisvoid	input_service_request(int type, int plen);
6860573Skrisvoid	input_userauth_request(int type, int plen);
6960573Skrisvoid	protocol_error(int type, int plen);
7060573Skris
7160573Skris/* auth */
7260573Skrisint	ssh2_auth_none(struct passwd *pw);
7360573Skrisint	ssh2_auth_password(struct passwd *pw);
7465674Skrisint  	ssh2_auth_pubkey(struct passwd *pw, char *service);
7560573Skris
7660573Skris/* helper */
7760573Skrisstruct passwd*	 auth_set_user(char *u, char *s);
7860573Skrisint	user_dsa_key_allowed(struct passwd *pw, Key *key);
7960573Skris
8060573Skristypedef struct Authctxt Authctxt;
8160573Skrisstruct Authctxt {
8260573Skris	char *user;
8360573Skris	char *service;
8460573Skris	struct passwd pw;
8560573Skris	int valid;
8660573Skris};
8760573Skrisstatic Authctxt	*authctxt = NULL;
8860573Skrisstatic int userauth_success = 0;
8960573Skris
9060573Skris/*
9160573Skris * loop until userauth_success == TRUE
9260573Skris */
9360573Skris
9460573Skrisvoid
9560573Skrisdo_authentication2()
9660573Skris{
9760573Skris	/* turn off skey/kerberos, not supported by SSH2 */
9860573Skris#ifdef SKEY
9960573Skris	options.skey_authentication = 0;
10060573Skris#endif
10160573Skris#ifdef KRB4
10260576Skris	options.krb4_authentication = 0;
10360573Skris#endif
10460573Skris
10560573Skris	dispatch_init(&protocol_error);
10660573Skris	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
10760573Skris	dispatch_run(DISPATCH_BLOCK, &userauth_success);
10860573Skris	do_authenticated2();
10960573Skris}
11060573Skris
11160573Skrisvoid
11260573Skrisprotocol_error(int type, int plen)
11360573Skris{
11460573Skris	log("auth: protocol error: type %d plen %d", type, plen);
11560573Skris	packet_start(SSH2_MSG_UNIMPLEMENTED);
11660573Skris	packet_put_int(0);
11760573Skris	packet_send();
11860573Skris	packet_write_wait();
11960573Skris}
12060573Skris
12160573Skrisvoid
12260573Skrisinput_service_request(int type, int plen)
12360573Skris{
12460573Skris	unsigned int len;
12560573Skris	int accept = 0;
12660573Skris	char *service = packet_get_string(&len);
12760573Skris	packet_done();
12860573Skris
12960573Skris	if (strcmp(service, "ssh-userauth") == 0) {
13060573Skris		if (!userauth_success) {
13160573Skris			accept = 1;
13260573Skris			/* now we can handle user-auth requests */
13360573Skris			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
13460573Skris		}
13560573Skris	}
13660573Skris	/* XXX all other service requests are denied */
13760573Skris
13860573Skris	if (accept) {
13960573Skris		packet_start(SSH2_MSG_SERVICE_ACCEPT);
14060573Skris		packet_put_cstring(service);
14160573Skris		packet_send();
14260573Skris		packet_write_wait();
14360573Skris	} else {
14460573Skris		debug("bad service request %s", service);
14560573Skris		packet_disconnect("bad service request %s", service);
14660573Skris	}
14760573Skris	xfree(service);
14860573Skris}
14960573Skris
15060573Skrisvoid
15160573Skrisinput_userauth_request(int type, int plen)
15260573Skris{
15360573Skris	static void (*authlog) (const char *fmt,...) = verbose;
15460573Skris	static int attempt = 0;
15565674Skris	unsigned int len;
15660573Skris	int authenticated = 0;
15765674Skris	char *user, *service, *method, *authmsg = NULL;
15860573Skris	struct passwd *pw;
15968704Sgreen#ifdef HAVE_LOGIN_CAP
16068704Sgreen	login_cap_t *lc;
16168704Sgreen#endif /* HAVE_LOGIN_CAP */
16268704Sgreen#if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
16368704Sgreen	const char *from_host, *from_ip;
16460573Skris
16568704Sgreen	from_host = get_canonical_hostname();
16668704Sgreen	from_ip = get_remote_ipaddr();
16768704Sgreen#endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
16868704Sgreen
16960573Skris	if (++attempt == AUTH_FAIL_MAX)
17060573Skris		packet_disconnect("too many failed userauth_requests");
17160573Skris
17260573Skris	user = packet_get_string(&len);
17360573Skris	service = packet_get_string(&len);
17460573Skris	method = packet_get_string(&len);
17560573Skris	debug("userauth-request for user %s service %s method %s", user, service, method);
17660573Skris
17760573Skris	/* XXX we only allow the ssh-connection service */
17860573Skris	pw = auth_set_user(user, service);
17960573Skris	if (pw && strcmp(service, "ssh-connection")==0) {
18060573Skris		if (strcmp(method, "none") == 0) {
18160573Skris			authenticated =	ssh2_auth_none(pw);
18260573Skris		} else if (strcmp(method, "password") == 0) {
18360573Skris			authenticated =	ssh2_auth_password(pw);
18460573Skris		} else if (strcmp(method, "publickey") == 0) {
18565674Skris			authenticated =	ssh2_auth_pubkey(pw, service);
18660573Skris		}
18760573Skris	}
18860573Skris	if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
18960573Skris		authenticated = 0;
19060573Skris		log("ROOT LOGIN REFUSED FROM %.200s",
19160573Skris		    get_canonical_hostname());
19260573Skris	}
19360573Skris
19468704Sgreen#ifdef HAVE_LOGIN_CAP
19568704Sgreen	lc = login_getpwclass(pw);
19668704Sgreen	if (lc == NULL)
19768704Sgreen		lc = login_getclassbyname(NULL, pw);
19868704Sgreen	if (!auth_hostok(lc, from_host, from_ip)) {
19968704Sgreen		log("Denied connection for %.200s from %.200s [%.200s].",
20068704Sgreen		    pw->pw_name, from_host, from_ip);
20168704Sgreen		packet_disconnect("Sorry, you are not allowed to connect.");
20268704Sgreen	}
20368704Sgreen	if (!auth_timeok(lc, time(NULL))) {
20468704Sgreen		log("LOGIN %.200s REFUSED (TIME) FROM %.200s",
20568704Sgreen		    pw->pw_name, from_host);
20668704Sgreen		packet_disconnect("Logins not available right now.");
20768704Sgreen	}
20868704Sgreen	login_close(lc);
20968704Sgreen#endif  /* HAVE_LOGIN_CAP */
21068704Sgreen#ifdef LOGIN_ACCESS
21168704Sgreen	if (!login_access(pw->pw_name, from_host)) {
21268704Sgreen		log("Denied connection for %.200s from %.200s [%.200s].",
21368704Sgreen		    pw->pw_name, from_host, from_ip);
21468704Sgreen		packet_disconnect("Sorry, you are not allowed to connect.");
21568704Sgreen	}
21668704Sgreen#endif /* LOGIN_ACCESS */
21768704Sgreen
21860573Skris	/* Raise logging level */
21960573Skris	if (authenticated == 1 ||
22060573Skris	    attempt == AUTH_FAIL_LOG ||
22160573Skris	    strcmp(method, "password") == 0)
22260573Skris		authlog = log;
22360573Skris
22460573Skris	/* Log before sending the reply */
22560573Skris	if (authenticated == 1) {
22660573Skris		authmsg = "Accepted";
22760573Skris	} else if (authenticated == 0) {
22860573Skris		authmsg = "Failed";
22960573Skris	} else {
23060573Skris		authmsg = "Postponed";
23160573Skris	}
23260573Skris	authlog("%s %s for %.200s from %.200s port %d ssh2",
23360573Skris		authmsg,
23460573Skris		method,
23560573Skris		pw && pw->pw_uid == 0 ? "ROOT" : user,
23660573Skris		get_remote_ipaddr(),
23760573Skris		get_remote_port());
23860573Skris
23960573Skris	/* XXX todo: check if multiple auth methods are needed */
24060573Skris	if (authenticated == 1) {
24160573Skris		/* turn off userauth */
24260573Skris		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
24360573Skris		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
24460573Skris		packet_send();
24560573Skris		packet_write_wait();
24660573Skris		/* now we can break out */
24760573Skris		userauth_success = 1;
24860573Skris	} else if (authenticated == 0) {
24960573Skris		packet_start(SSH2_MSG_USERAUTH_FAILURE);
25060573Skris		packet_put_cstring("publickey,password");	/* XXX dynamic */
25160573Skris		packet_put_char(0);				/* XXX partial success, unused */
25260573Skris		packet_send();
25360573Skris		packet_write_wait();
25460573Skris	}
25560573Skris
25660573Skris	xfree(service);
25760573Skris	xfree(user);
25860573Skris	xfree(method);
25960573Skris}
26060573Skris
26160573Skrisint
26260573Skrisssh2_auth_none(struct passwd *pw)
26360573Skris{
26460573Skris	packet_done();
26560573Skris	return auth_password(pw, "");
26660573Skris}
26760573Skrisint
26860573Skrisssh2_auth_password(struct passwd *pw)
26960573Skris{
27060573Skris	char *password;
27160573Skris	int authenticated = 0;
27260573Skris	int change;
27360573Skris	unsigned int len;
27460573Skris	change = packet_get_char();
27560573Skris	if (change)
27660573Skris		log("password change not supported");
27760573Skris	password = packet_get_string(&len);
27860573Skris	packet_done();
27960573Skris	if (options.password_authentication &&
28060573Skris	    auth_password(pw, password) == 1)
28160573Skris		authenticated = 1;
28260573Skris	memset(password, 0, len);
28360573Skris	xfree(password);
28460573Skris	return authenticated;
28560573Skris}
28660573Skrisint
28765674Skrisssh2_auth_pubkey(struct passwd *pw, char *service)
28860573Skris{
28960573Skris	Buffer b;
29060573Skris	Key *key;
29160573Skris	char *pkalg, *pkblob, *sig;
29260573Skris	unsigned int alen, blen, slen;
29360573Skris	int have_sig;
29460573Skris	int authenticated = 0;
29560573Skris
29660573Skris	if (options.dsa_authentication == 0) {
29760573Skris		debug("pubkey auth disabled");
29860573Skris		return 0;
29960573Skris	}
30060573Skris	have_sig = packet_get_char();
30160573Skris	pkalg = packet_get_string(&alen);
30260573Skris	if (strcmp(pkalg, KEX_DSS) != 0) {
30360573Skris		xfree(pkalg);
30460573Skris		log("bad pkalg %s", pkalg);	/*XXX*/
30560573Skris		return 0;
30660573Skris	}
30760573Skris	pkblob = packet_get_string(&blen);
30860573Skris	key = dsa_key_from_blob(pkblob, blen);
30960573Skris	if (key != NULL) {
31060573Skris		if (have_sig) {
31160573Skris			sig = packet_get_string(&slen);
31260573Skris			packet_done();
31360573Skris			buffer_init(&b);
31465674Skris			if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
31565674Skris				buffer_put_string(&b, session_id2, session_id2_len);
31665674Skris			} else {
31765674Skris				buffer_append(&b, session_id2, session_id2_len);
31865674Skris			}
31965674Skris			/* reconstruct packet */
32060573Skris			buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
32165674Skris			buffer_put_cstring(&b, pw->pw_name);
32265674Skris			buffer_put_cstring(&b,
32365674Skris			    datafellows & SSH_BUG_PUBKEYAUTH ?
32465674Skris			    "ssh-userauth" :
32565674Skris			    service);
32665674Skris			buffer_put_cstring(&b, "publickey");
32765674Skris			buffer_put_char(&b, have_sig);
32865674Skris			buffer_put_cstring(&b, KEX_DSS);
32965674Skris			buffer_put_string(&b, pkblob, blen);
33060573Skris#ifdef DEBUG_DSS
33160573Skris			buffer_dump(&b);
33260573Skris#endif
33360573Skris			/* test for correct signature */
33460573Skris			if (user_dsa_key_allowed(pw, key) &&
33560573Skris			    dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
33660573Skris				authenticated = 1;
33760573Skris			buffer_clear(&b);
33860573Skris			xfree(sig);
33960573Skris		} else {
34060573Skris			packet_done();
34160573Skris			debug("test key...");
34260573Skris			/* test whether pkalg/pkblob are acceptable */
34360573Skris			/* XXX fake reply and always send PK_OK ? */
34460573Skris			/*
34560573Skris			 * XXX this allows testing whether a user is allowed
34660573Skris			 * to login: if you happen to have a valid pubkey this
34760573Skris			 * message is sent. the message is NEVER sent at all
34860573Skris			 * if a user is not allowed to login. is this an
34960573Skris			 * issue? -markus
35060573Skris			 */
35160573Skris			if (user_dsa_key_allowed(pw, key)) {
35260573Skris				packet_start(SSH2_MSG_USERAUTH_PK_OK);
35360573Skris				packet_put_string(pkalg, alen);
35460573Skris				packet_put_string(pkblob, blen);
35560573Skris				packet_send();
35660573Skris				packet_write_wait();
35760573Skris				authenticated = -1;
35860573Skris			}
35960573Skris		}
36060573Skris		key_free(key);
36160573Skris	}
36260573Skris	xfree(pkalg);
36360573Skris	xfree(pkblob);
36460573Skris	return authenticated;
36560573Skris}
36660573Skris
36760573Skris/* set and get current user */
36860573Skris
36960573Skrisstruct passwd*
37060573Skrisauth_get_user(void)
37160573Skris{
37260573Skris	return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
37360573Skris}
37460573Skris
37560573Skrisstruct passwd*
37660573Skrisauth_set_user(char *u, char *s)
37760573Skris{
37860573Skris	struct passwd *pw, *copy;
37960573Skris
38060573Skris	if (authctxt == NULL) {
38160573Skris		authctxt = xmalloc(sizeof(*authctxt));
38260573Skris		authctxt->valid = 0;
38360573Skris		authctxt->user = xstrdup(u);
38460573Skris		authctxt->service = xstrdup(s);
38560573Skris		setproctitle("%s", u);
38660573Skris		pw = getpwnam(u);
38760573Skris		if (!pw || !allowed_user(pw)) {
38860573Skris			log("auth_set_user: illegal user %s", u);
38960573Skris			return NULL;
39060573Skris		}
39160573Skris		copy = &authctxt->pw;
39260573Skris		memset(copy, 0, sizeof(*copy));
39360573Skris		copy->pw_name = xstrdup(pw->pw_name);
39460573Skris		copy->pw_passwd = xstrdup(pw->pw_passwd);
39560573Skris		copy->pw_uid = pw->pw_uid;
39660573Skris		copy->pw_gid = pw->pw_gid;
39765674Skris		copy->pw_class = xstrdup(pw->pw_class);
39860573Skris		copy->pw_dir = xstrdup(pw->pw_dir);
39960573Skris		copy->pw_shell = xstrdup(pw->pw_shell);
40062179Sgreen		copy->pw_class = xstrdup(pw->pw_class);
40162179Sgreen		copy->pw_expire = pw->pw_expire;
40262179Sgreen		copy->pw_change = pw->pw_change;
40360573Skris		authctxt->valid = 1;
40460573Skris	} else {
40560573Skris		if (strcmp(u, authctxt->user) != 0 ||
40660573Skris		    strcmp(s, authctxt->service) != 0) {
40760573Skris			log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
40860573Skris			    u, s, authctxt->user, authctxt->service);
40960573Skris			return NULL;
41060573Skris		}
41160573Skris	}
41260573Skris	return auth_get_user();
41360573Skris}
41460573Skris
41560573Skris/* return 1 if user allows given key */
41660573Skrisint
41760573Skrisuser_dsa_key_allowed(struct passwd *pw, Key *key)
41860573Skris{
41960573Skris	char line[8192], file[1024];
42060573Skris	int found_key = 0;
42160573Skris	unsigned int bits = -1;
42260573Skris	FILE *f;
42360573Skris	unsigned long linenum = 0;
42460573Skris	struct stat st;
42560573Skris	Key *found;
42660573Skris
42760573Skris	/* Temporarily use the user's uid. */
42860573Skris	temporarily_use_uid(pw->pw_uid);
42960573Skris
43060573Skris	/* The authorized keys. */
43160573Skris	snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
43260573Skris	    SSH_USER_PERMITTED_KEYS2);
43360573Skris
43460573Skris	/* Fail quietly if file does not exist */
43560573Skris	if (stat(file, &st) < 0) {
43660573Skris		/* Restore the privileged uid. */
43760573Skris		restore_uid();
43860573Skris		return 0;
43960573Skris	}
44060573Skris	/* Open the file containing the authorized keys. */
44160573Skris	f = fopen(file, "r");
44260573Skris	if (!f) {
44360573Skris		/* Restore the privileged uid. */
44460573Skris		restore_uid();
44560573Skris		return 0;
44660573Skris	}
44760573Skris	if (options.strict_modes) {
44860573Skris		int fail = 0;
44960573Skris		char buf[1024];
45060573Skris		/* Check open file in order to avoid open/stat races */
45160573Skris		if (fstat(fileno(f), &st) < 0 ||
45260573Skris		    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
45360573Skris		    (st.st_mode & 022) != 0) {
45460573Skris			snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
45560573Skris			    "bad ownership or modes for '%s'.", pw->pw_name, file);
45660573Skris			fail = 1;
45760573Skris		} else {
45860573Skris			/* Check path to SSH_USER_PERMITTED_KEYS */
45960573Skris			int i;
46060573Skris			static const char *check[] = {
46160573Skris				"", SSH_USER_DIR, NULL
46260573Skris			};
46360573Skris			for (i = 0; check[i]; i++) {
46460573Skris				snprintf(line, sizeof line, "%.500s/%.100s",
46560573Skris				    pw->pw_dir, check[i]);
46660573Skris				if (stat(line, &st) < 0 ||
46760573Skris				    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
46860573Skris				    (st.st_mode & 022) != 0) {
46960573Skris					snprintf(buf, sizeof buf,
47060573Skris					    "DSA authentication refused for %.100s: "
47160573Skris					    "bad ownership or modes for '%s'.",
47260573Skris					    pw->pw_name, line);
47360573Skris					fail = 1;
47460573Skris					break;
47560573Skris				}
47660573Skris			}
47760573Skris		}
47860573Skris		if (fail) {
47960573Skris			fclose(f);
48065674Skris			log("%s",buf);
48160573Skris			restore_uid();
48260573Skris			return 0;
48360573Skris		}
48460573Skris	}
48560573Skris	found_key = 0;
48660573Skris	found = key_new(KEY_DSA);
48760573Skris
48860573Skris	while (fgets(line, sizeof(line), f)) {
48965674Skris		char *cp, *options = NULL;
49060573Skris		linenum++;
49160573Skris		/* Skip leading whitespace, empty and comment lines. */
49260573Skris		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
49360573Skris			;
49460573Skris		if (!*cp || *cp == '\n' || *cp == '#')
49560573Skris			continue;
49665674Skris
49760573Skris		bits = key_read(found, &cp);
49865674Skris		if (bits == 0) {
49965674Skris			/* no key?  check if there are options for this key */
50065674Skris			int quoted = 0;
50165674Skris			options = cp;
50265674Skris			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
50365674Skris				if (*cp == '\\' && cp[1] == '"')
50465674Skris					cp++;	/* Skip both */
50565674Skris				else if (*cp == '"')
50665674Skris					quoted = !quoted;
50765674Skris			}
50865674Skris			/* Skip remaining whitespace. */
50965674Skris			for (; *cp == ' ' || *cp == '\t'; cp++)
51065674Skris				;
51165674Skris			bits = key_read(found, &cp);
51265674Skris			if (bits == 0) {
51365674Skris				/* still no key?  advance to next line*/
51465674Skris				continue;
51565674Skris			}
51665674Skris		}
51765674Skris		if (key_equal(found, key) &&
51865674Skris		    auth_parse_options(pw, options, linenum) == 1) {
51960573Skris			found_key = 1;
52060573Skris			debug("matching key found: file %s, line %ld",
52160573Skris			    file, linenum);
52260573Skris			break;
52360573Skris		}
52460573Skris	}
52560573Skris	restore_uid();
52660573Skris	fclose(f);
52760573Skris	key_free(found);
52860573Skris	return found_key;
52960573Skris}
530