1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: auth-rhosts.c,v 1.46 2014/12/23 22:42:48 djm Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Author: Tatu Ylonen <ylo@cs.hut.fi>
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *                    All rights reserved
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Rhosts authentication.  This file contains code to check whether to admit
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * the login based on rhosts authentication.  This file also processes
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * /etc/hosts.equiv.
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * As far as I am concerned, the code I have written for this software
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * can be used freely for any purpose.  Any derived versions of this
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * software must be clearly marked as such, and if the derived work is
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * incompatible with the protocol description in the RFC file, it must be
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * called by a name other than "ssh" or "Secure Shell".
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h>
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_NETGROUP_H
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <netgroup.h>
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <pwd.h>
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h>
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h>
29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h>
30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h>
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "packet.h"
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "buffer.h"
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "uidswap.h"
35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "pathnames.h"
36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h"
37d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "misc.h"
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "servconf.h"
39bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "canohost.h"
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "key.h"
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "hostfile.h"
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "auth.h"
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* import */
45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern ServerOptions options;
46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern int use_privsep;
47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * This function processes an rhosts-style file (.rhosts, .shosts, or
50bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * /etc/hosts.equiv).  This returns true if authentication can be granted
51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * based on the file, and returns zero otherwise.
52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancheck_rhosts_file(const char *filename, const char *hostname,
56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		  const char *ipaddr, const char *client_user,
57bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		  const char *server_user)
58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	FILE *f;
60d059297112922cabb0c674840589be8db821fd9aAdam Langley#define RBUFLN 1024
61d059297112922cabb0c674840589be8db821fd9aAdam Langley	char buf[RBUFLN];/* Must not be larger than host, user, dummy below. */
62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int fd;
63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct stat st;
64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Open the .rhosts file, deny if unreadable */
66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((fd = open(filename, O_RDONLY|O_NONBLOCK)) == -1)
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
68bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fstat(fd, &st) == -1) {
69bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
70bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
72bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (!S_ISREG(st.st_mode)) {
73bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		logit("User %s hosts file %s is not a regular file",
74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    server_user, filename);
75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
76bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
77bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
78bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	unset_nonblock(fd);
79bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((f = fdopen(fd, "r")) == NULL) {
80bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
81bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
82bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
83bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	while (fgets(buf, sizeof(buf), f)) {
84d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* All three must have length >= buf to avoid overflows. */
85d059297112922cabb0c674840589be8db821fd9aAdam Langley		char hostbuf[RBUFLN], userbuf[RBUFLN], dummy[RBUFLN];
86d059297112922cabb0c674840589be8db821fd9aAdam Langley		char *host, *user, *cp;
87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		int negated;
88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
90bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			;
91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (*cp == '#' || *cp == '\n' || !*cp)
92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/*
95bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * NO_PLUS is supported at least on OSF/1.  We skip it (we
96bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * don't ever support the plus syntax).
97bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 */
98bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (strncmp(cp, "NO_PLUS", 7) == 0)
99bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/*
102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * This should be safe because each buffer is as big as the
103bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * whole string, and thus cannot be overwritten.
104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 */
105bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (sscanf(buf, "%1023s %1023s %1023s", hostbuf, userbuf,
106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    dummy)) {
107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 0:
108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			auth_debug_add("Found empty line in %.100s.", filename);
109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 1:
111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* Host name only. */
112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			strlcpy(userbuf, server_user, sizeof(userbuf));
113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 2:
115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* Got both host and user name. */
116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case 3:
118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			auth_debug_add("Found garbage in %.100s.", filename);
119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		default:
121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* Weird... */
122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		host = hostbuf;
126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		user = userbuf;
127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		negated = 0;
128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
129bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Process negated host names, or positive netgroups. */
130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (host[0] == '-') {
131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			negated = 1;
132bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			host++;
133bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else if (host[0] == '+')
134bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			host++;
135bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (user[0] == '-') {
137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			negated = 1;
138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			user++;
139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else if (user[0] == '+')
140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			user++;
141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Check for empty host/user names (particularly '+'). */
143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (!host[0] || !user[0]) {
144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* We come here if either was '+' or '-'. */
145d059297112922cabb0c674840589be8db821fd9aAdam Langley			auth_debug_add("Ignoring wild host/user names "
146d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "in %.100s.", filename);
147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Verify that host name matches. */
150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (host[0] == '@') {
151bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (!innetgr(host + 1, hostname, NULL, NULL) &&
152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    !innetgr(host + 1, ipaddr, NULL, NULL))
153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				continue;
154d059297112922cabb0c674840589be8db821fd9aAdam Langley		} else if (strcasecmp(host, hostname) &&
155d059297112922cabb0c674840589be8db821fd9aAdam Langley		    strcmp(host, ipaddr) != 0)
156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;	/* Different hostname. */
157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Verify that user name matches. */
159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (user[0] == '@') {
160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (!innetgr(user + 1, NULL, client_user, NULL))
161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				continue;
162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		} else if (strcmp(user, client_user) != 0)
163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;	/* Different username. */
164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Found the user and host. */
166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		fclose(f);
167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* If the entry was negated, deny access. */
169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (negated) {
170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			auth_debug_add("Matched negative entry in %.100s.",
171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    filename);
172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return 0;
173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Accept authentication. */
175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 1;
176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Authentication using this file denied. */
179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fclose(f);
180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return 0;
181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Tries to authenticate the user using the .shosts or .rhosts file. Returns
185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * true if authentication succeeds.  If ignore_rhosts is true, only
186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
187bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanauth_rhosts(struct passwd *pw, const char *client_user)
191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	const char *hostname, *ipaddr;
193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	hostname = get_canonical_hostname(options.use_dns);
195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	ipaddr = get_remote_ipaddr();
196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return auth_rhosts2(pw, client_user, hostname, ipaddr);
197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanauth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostname,
201bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    const char *ipaddr)
202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char buf[1024];
204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct stat st;
205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int rhosts_file_index;
207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    client_user, hostname, ipaddr);
210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Switch to the user's uid. */
212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	temporarily_use_uid(pw);
213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
214d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * Quick check: if the user has no .shosts or .rhosts files and
215d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * no system hosts.equiv/shosts.equiv files exist then return
216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * failure immediately without doing costly lookups from name
217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * servers.
218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    rhosts_file_index++) {
221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Check users .rhosts or .shosts. */
222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		snprintf(buf, sizeof buf, "%.500s/%.100s",
223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 pw->pw_dir, rhosts_files[rhosts_file_index]);
224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (stat(buf, &st) >= 0)
225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			break;
226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Switch back to privileged uid. */
228bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	restore_uid();
229bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
230d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
231d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * Deny if The user has no .shosts or .rhosts file and there
232d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * are no system-wide files.
233d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (!rhosts_files[rhosts_file_index] &&
235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
236d059297112922cabb0c674840589be8db821fd9aAdam Langley	    stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) {
237d059297112922cabb0c674840589be8db821fd9aAdam Langley		debug3("%s: no hosts access files exist", __func__);
238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
239d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
241d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
242d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * If not logging in as superuser, try /etc/hosts.equiv and
243d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * shosts.equiv.
244d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
245d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (pw->pw_uid == 0)
246d059297112922cabb0c674840589be8db821fd9aAdam Langley		debug3("%s: root user, ignoring system hosts files", __func__);
247d059297112922cabb0c674840589be8db821fd9aAdam Langley	else {
248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr,
249bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    client_user, pw->pw_name)) {
250d059297112922cabb0c674840589be8db821fd9aAdam Langley			auth_debug_add("Accepted for %.100s [%.100s] by "
251d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "/etc/hosts.equiv.", hostname, ipaddr);
252bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return 1;
253bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
254bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr,
255bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    client_user, pw->pw_name)) {
256d059297112922cabb0c674840589be8db821fd9aAdam Langley			auth_debug_add("Accepted for %.100s [%.100s] by "
257d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "%.100s.", hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
258bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return 1;
259bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
260bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
261d059297112922cabb0c674840589be8db821fd9aAdam Langley
262bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Check that the home directory is owned by root or the user, and is
264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * not group or world writable.
265bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
266bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (stat(pw->pw_dir, &st) < 0) {
267bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		logit("Rhosts authentication refused for %.100s: "
268bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    "no home directory %.200s", pw->pw_name, pw->pw_dir);
269bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		auth_debug_add("Rhosts authentication refused for %.100s: "
270bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    "no home directory %.200s", pw->pw_name, pw->pw_dir);
271bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
272bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
273bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (options.strict_modes &&
274bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
275bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    (st.st_mode & 022) != 0)) {
276bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		logit("Rhosts authentication refused for %.100s: "
277bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    "bad ownership or modes for home directory.", pw->pw_name);
278bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		auth_debug_add("Rhosts authentication refused for %.100s: "
279bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    "bad ownership or modes for home directory.", pw->pw_name);
280bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
281bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
282bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Temporarily use the user's uid. */
283bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	temporarily_use_uid(pw);
284bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Check all .rhosts files (currently .shosts and .rhosts). */
286bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
287bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    rhosts_file_index++) {
288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Check users .rhosts or .shosts. */
289bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		snprintf(buf, sizeof buf, "%.500s/%.100s",
290bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			 pw->pw_dir, rhosts_files[rhosts_file_index]);
291bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (stat(buf, &st) < 0)
292bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
293bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
294bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/*
295bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * Make sure that the file is either owned by the user or by
296bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * root, and make sure it is not writable by anyone but the
297bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * owner.  This is to help avoid novices accidentally
298bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 * allowing access to their account by anyone.
299bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		 */
300bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (options.strict_modes &&
301bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
302bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    (st.st_mode & 022) != 0)) {
303bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
304bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    pw->pw_name, buf);
305bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			auth_debug_add("Bad file modes for %.200s", buf);
306bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
307bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
308d059297112922cabb0c674840589be8db821fd9aAdam Langley		/*
309d059297112922cabb0c674840589be8db821fd9aAdam Langley		 * Check if we have been configured to ignore .rhosts
310d059297112922cabb0c674840589be8db821fd9aAdam Langley		 * and .shosts files.
311d059297112922cabb0c674840589be8db821fd9aAdam Langley		 */
312bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (options.ignore_rhosts) {
313d059297112922cabb0c674840589be8db821fd9aAdam Langley			auth_debug_add("Server has been configured to "
314d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "ignore %.100s.", rhosts_files[rhosts_file_index]);
315bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
316bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
317bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Check if authentication is permitted by the file. */
318d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (check_rhosts_file(buf, hostname, ipaddr,
319d059297112922cabb0c674840589be8db821fd9aAdam Langley		    client_user, pw->pw_name)) {
320bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			auth_debug_add("Accepted by %.100s.",
321bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    rhosts_files[rhosts_file_index]);
322bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			/* Restore the privileged uid. */
323bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			restore_uid();
324d059297112922cabb0c674840589be8db821fd9aAdam Langley			auth_debug_add("Accepted host %s ip %s client_user "
325d059297112922cabb0c674840589be8db821fd9aAdam Langley			    "%s server_user %s", hostname, ipaddr,
326d059297112922cabb0c674840589be8db821fd9aAdam Langley			    client_user, pw->pw_name);
327bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return 1;
328bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
329bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
330bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Restore the privileged uid. */
332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	restore_uid();
333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return 0;
334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
335bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
337bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanauth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
338bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    const char *ipaddr)
339bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
340bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman       return auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
341bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
342