source: trunk/third/openssh/auth-rhosts.c @ 18759

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