]> andersk Git - openssh.git/blame - auth-rhosts.c
- Merged very large OpenBSD source code reformat
[openssh.git] / auth-rhosts.c
CommitLineData
8efc0c15 1/*
5260325f 2 *
3 * auth-rhosts.c
4 *
5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 *
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 *
10 * Created: Fri Mar 17 05:12:18 1995 ylo
11 *
12 * Rhosts authentication. This file contains code to check whether to admit
13 * the login based on rhosts authentication. This file also processes
14 * /etc/hosts.equiv.
15 *
16 */
8efc0c15 17
18#include "includes.h"
19RCSID("$Id$");
20
21#include "packet.h"
22#include "ssh.h"
23#include "xmalloc.h"
24#include "uidswap.h"
6fa724bc 25#include "servconf.h"
8efc0c15 26
27/* This function processes an rhosts-style file (.rhosts, .shosts, or
28 /etc/hosts.equiv). This returns true if authentication can be granted
29 based on the file, and returns zero otherwise. */
30
5260325f 31int
32check_rhosts_file(const char *filename, const char *hostname,
33 const char *ipaddr, const char *client_user,
34 const char *server_user)
8efc0c15 35{
5260325f 36 FILE *f;
37 char buf[1024]; /* Must not be larger than host, user, dummy below. */
38
39 /* Open the .rhosts file, deny if unreadable */
40 f = fopen(filename, "r");
41 if (!f)
42 return 0;
43
44 /* Go through the file, checking every entry. */
45 while (fgets(buf, sizeof(buf), f)) {
46 /* All three must be at least as big as buf to avoid overflows. */
47 char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
48 int negated;
49
50 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
51 ;
52 if (*cp == '#' || *cp == '\n' || !*cp)
53 continue;
54
55 /* NO_PLUS is supported at least on OSF/1. We skip it (we
56 don't ever support the plus syntax). */
57 if (strncmp(cp, "NO_PLUS", 7) == 0)
58 continue;
59
60 /* This should be safe because each buffer is as big as
61 the whole string, and thus cannot be overwritten. */
62 switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
63 case 0:
64 packet_send_debug("Found empty line in %.100s.", filename);
65 continue;
66 case 1:
67 /* Host name only. */
68 strlcpy(userbuf, server_user, sizeof(userbuf));
69 break;
70 case 2:
71 /* Got both host and user name. */
72 break;
73 case 3:
74 packet_send_debug("Found garbage in %.100s.", filename);
75 continue;
76 default:
77 /* Weird... */
78 continue;
79 }
80
81 host = hostbuf;
82 user = userbuf;
83 negated = 0;
84
85 /* Process negated host names, or positive netgroups. */
86 if (host[0] == '-') {
87 negated = 1;
88 host++;
89 } else if (host[0] == '+')
90 host++;
91
92 if (user[0] == '-') {
93 negated = 1;
94 user++;
95 } else if (user[0] == '+')
96 user++;
97
98 /* Check for empty host/user names (particularly '+'). */
99 if (!host[0] || !user[0]) {
100 /* We come here if either was '+' or '-'. */
101 packet_send_debug("Ignoring wild host/user names in %.100s.",
102 filename);
103 continue;
104 }
105 /* Verify that host name matches. */
106 if (host[0] == '@') {
107 if (!innetgr(host + 1, hostname, NULL, NULL) &&
108 !innetgr(host + 1, ipaddr, NULL, NULL))
109 continue;
110 } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
111 continue; /* Different hostname. */
112
113 /* Verify that user name matches. */
114 if (user[0] == '@') {
115 if (!innetgr(user + 1, NULL, client_user, NULL))
116 continue;
117 } else if (strcmp(user, client_user) != 0)
118 continue; /* Different username. */
119
120 /* Found the user and host. */
121 fclose(f);
122
123 /* If the entry was negated, deny access. */
124 if (negated) {
125 packet_send_debug("Matched negative entry in %.100s.",
126 filename);
127 return 0;
128 }
129 /* Accept authentication. */
130 return 1;
8efc0c15 131 }
8efc0c15 132
5260325f 133 /* Authentication using this file denied. */
134 fclose(f);
135 return 0;
8efc0c15 136}
137
5260325f 138/* Tries to authenticate the user using the .shosts or .rhosts file.
8efc0c15 139 Returns true if authentication succeeds. If ignore_rhosts is
140 true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
141 are ignored). */
142
5260325f 143int
144auth_rhosts(struct passwd *pw, const char *client_user)
8efc0c15 145{
5260325f 146 extern ServerOptions options;
147 char buf[1024];
148 const char *hostname, *ipaddr;
149 struct stat st;
150 static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
151 unsigned int rhosts_file_index;
152
153 /* Quick check: if the user has no .shosts or .rhosts files,
154 return failure immediately without doing costly lookups from
155 name servers. */
156 /* Switch to the user's uid. */
157 temporarily_use_uid(pw->pw_uid);
158 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
159 rhosts_file_index++) {
160 /* Check users .rhosts or .shosts. */
161 snprintf(buf, sizeof buf, "%.500s/%.100s",
162 pw->pw_dir, rhosts_files[rhosts_file_index]);
163 if (stat(buf, &st) >= 0)
164 break;
8efc0c15 165 }
5260325f 166 /* Switch back to privileged uid. */
167 restore_uid();
168
169 /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
170 if (!rhosts_files[rhosts_file_index] &&
171 stat("/etc/hosts.equiv", &st) < 0 &&
172 stat(SSH_HOSTS_EQUIV, &st) < 0)
173 return 0;
174
175 /* Get the name, address, and port of the remote host. */
176 hostname = get_canonical_hostname();
177 ipaddr = get_remote_ipaddr();
178
179 /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
180 if (pw->pw_uid != 0) {
181 if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
182 pw->pw_name)) {
183 packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
184 hostname, ipaddr);
185 return 1;
186 }
187 if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
188 pw->pw_name)) {
189 packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
190 hostname, ipaddr, SSH_HOSTS_EQUIV);
191 return 1;
192 }
8efc0c15 193 }
5260325f 194 /* Check that the home directory is owned by root or the user, and
195 is not group or world writable. */
196 if (stat(pw->pw_dir, &st) < 0) {
197 log("Rhosts authentication refused for %.100s: no home directory %.200s",
198 pw->pw_name, pw->pw_dir);
199 packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
200 pw->pw_name, pw->pw_dir);
201 return 0;
8efc0c15 202 }
5260325f 203 if (options.strict_modes &&
204 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
205 (st.st_mode & 022) != 0)) {
206 log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
207 pw->pw_name);
208 packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
209 pw->pw_name);
210 return 0;
8efc0c15 211 }
5260325f 212 /* Temporarily use the user's uid. */
213 temporarily_use_uid(pw->pw_uid);
214
215 /* Check all .rhosts files (currently .shosts and .rhosts). */
216 for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
217 rhosts_file_index++) {
218 /* Check users .rhosts or .shosts. */
219 snprintf(buf, sizeof buf, "%.500s/%.100s",
220 pw->pw_dir, rhosts_files[rhosts_file_index]);
221 if (stat(buf, &st) < 0)
222 continue;
223
224 /* Make sure that the file is either owned by the user or
225 by root, and make sure it is not writable by anyone but
226 the owner. This is to help avoid novices accidentally
227 allowing access to their account by anyone. */
228 if (options.strict_modes &&
229 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
230 (st.st_mode & 022) != 0)) {
231 log("Rhosts authentication refused for %.100s: bad modes for %.200s",
232 pw->pw_name, buf);
233 packet_send_debug("Bad file modes for %.200s", buf);
234 continue;
235 }
236 /* Check if we have been configured to ignore .rhosts and .shosts files. */
237 if (options.ignore_rhosts) {
238 packet_send_debug("Server has been configured to ignore %.100s.",
239 rhosts_files[rhosts_file_index]);
240 continue;
241 }
242 /* Check if authentication is permitted by the file. */
243 if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
244 packet_send_debug("Accepted by %.100s.",
245 rhosts_files[rhosts_file_index]);
246 /* Restore the privileged uid. */
247 restore_uid();
248 return 1;
249 }
8efc0c15 250 }
8efc0c15 251
5260325f 252 /* Restore the privileged uid. */
253 restore_uid();
254 return 0;
8efc0c15 255}
This page took 0.07531 seconds and 5 git commands to generate.