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

Revision 16801, 8.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16800, 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.24 2001/06/23 15:12:17 itojun Exp $");
18
19#include "packet.h"
20#include "xmalloc.h"
21#include "uidswap.h"
22#include "pathnames.h"
23#include "log.h"
24#include "servconf.h"
25#include "canohost.h"
26#include "auth.h"
27
28/* import */
29extern ServerOptions options;
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                        packet_send_debug("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                        packet_send_debug("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                        packet_send_debug("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                        packet_send_debug("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        int ret;
158
159        hostname = get_canonical_hostname(options.reverse_mapping_check);
160        ipaddr = get_remote_ipaddr();
161        ret = auth_rhosts2(pw, client_user, hostname, ipaddr);
162        return ret;
163}
164
165int
166auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
167    const char *ipaddr)
168{
169        char buf[1024];
170        struct stat st;
171        static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
172        u_int rhosts_file_index;
173
174        debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s",
175            client_user, hostname, ipaddr);
176
177        /* no user given */
178        if (pw == NULL)
179                return 0;
180
181        /* Switch to the user's uid. */
182        temporarily_use_uid(pw);
183        /*
184         * Quick check: if the user has no .shosts or .rhosts files, return
185         * failure immediately without doing costly lookups from name
186         * servers.
187         */
188        for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
189             rhosts_file_index++) {
190                /* Check users .rhosts or .shosts. */
191                snprintf(buf, sizeof buf, "%.500s/%.100s",
192                         pw->pw_dir, rhosts_files[rhosts_file_index]);
193                if (stat(buf, &st) >= 0)
194                        break;
195        }
196        /* Switch back to privileged uid. */
197        restore_uid();
198
199        /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
200        if (!rhosts_files[rhosts_file_index] &&
201            stat(_PATH_RHOSTS_EQUIV, &st) < 0 &&
202            stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0)
203                return 0;
204
205        /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
206        if (pw->pw_uid != 0) {
207                if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, client_user,
208                                      pw->pw_name)) {
209                        packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
210                                          hostname, ipaddr);
211                        return 1;
212                }
213                if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
214                                      pw->pw_name)) {
215                        packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
216                                      hostname, ipaddr, _PATH_SSH_HOSTS_EQUIV);
217                        return 1;
218                }
219        }
220        /*
221         * Check that the home directory is owned by root or the user, and is
222         * not group or world writable.
223         */
224        if (stat(pw->pw_dir, &st) < 0) {
225                log("Rhosts authentication refused for %.100s: no home directory %.200s",
226                    pw->pw_name, pw->pw_dir);
227                packet_send_debug("Rhosts authentication refused for %.100s: no home directory %.200s",
228                                  pw->pw_name, pw->pw_dir);
229                return 0;
230        }
231        if (options.strict_modes &&
232            ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
233             (st.st_mode & 022) != 0)) {
234                log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
235                    pw->pw_name);
236                packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
237                                  pw->pw_name);
238                return 0;
239        }
240        /* Temporarily use the user's uid. */
241        temporarily_use_uid(pw);
242
243        /* Check all .rhosts files (currently .shosts and .rhosts). */
244        for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
245             rhosts_file_index++) {
246                /* Check users .rhosts or .shosts. */
247                snprintf(buf, sizeof buf, "%.500s/%.100s",
248                         pw->pw_dir, rhosts_files[rhosts_file_index]);
249                if (stat(buf, &st) < 0)
250                        continue;
251
252                /*
253                 * Make sure that the file is either owned by the user or by
254                 * root, and make sure it is not writable by anyone but the
255                 * owner.  This is to help avoid novices accidentally
256                 * allowing access to their account by anyone.
257                 */
258                if (options.strict_modes &&
259                    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
260                     (st.st_mode & 022) != 0)) {
261                        log("Rhosts authentication refused for %.100s: bad modes for %.200s",
262                            pw->pw_name, buf);
263                        packet_send_debug("Bad file modes for %.200s", buf);
264                        continue;
265                }
266                /* Check if we have been configured to ignore .rhosts and .shosts files. */
267                if (options.ignore_rhosts) {
268                        packet_send_debug("Server has been configured to ignore %.100s.",
269                                          rhosts_files[rhosts_file_index]);
270                        continue;
271                }
272                /* Check if authentication is permitted by the file. */
273                if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
274                        packet_send_debug("Accepted by %.100s.",
275                                          rhosts_files[rhosts_file_index]);
276                        /* Restore the privileged uid. */
277                        restore_uid();
278                        return 1;
279                }
280        }
281
282        /* Restore the privileged uid. */
283        restore_uid();
284        return 0;
285}
Note: See TracBrowser for help on using the repository browser.