[BACK]Return to auth-rhosts.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/auth-rhosts.c, Revision 1.8

1.1       deraadt     1: /*
                      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: */
                     17:
                     18: #include "includes.h"
1.8     ! markus     19: RCSID("$Id: auth-rhosts.c,v 1.7 1999/11/14 23:20:09 markus Exp $");
1.1       deraadt    20:
                     21: #include "packet.h"
                     22: #include "ssh.h"
                     23: #include "xmalloc.h"
                     24: #include "uidswap.h"
1.6       markus     25: #include "servconf.h"
1.1       deraadt    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:
                     31: int check_rhosts_file(const char *filename, const char *hostname,
                     32:                      const char *ipaddr, const char *client_user,
                     33:                      const char *server_user)
                     34: {
                     35:   FILE *f;
                     36:   char buf[1024]; /* Must not be larger than host, user, dummy below. */
                     37:
                     38:   /* Open the .rhosts file. */
                     39:   f = fopen(filename, "r");
                     40:   if (!f)
                     41:     return 0; /* Cannot read the .rhosts - deny access. */
                     42:
                     43:   /* Go through the file, checking every entry. */
                     44:   while (fgets(buf, sizeof(buf), f))
                     45:     {
                     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 don't ever
                     56:         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 the whole
                     61:         string, and thus cannot be overwritten. */
                     62:       switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy))
                     63:        {
                     64:        case 0:
                     65:          packet_send_debug("Found empty line in %.100s.", filename);
                     66:          continue; /* Empty line? */
                     67:        case 1:
                     68:          /* Host name only. */
1.3       deraadt    69:          strlcpy(userbuf, server_user, sizeof(userbuf));
1.1       deraadt    70:          break;
                     71:        case 2:
                     72:          /* Got both host and user name. */
                     73:          break;
                     74:        case 3:
                     75:          packet_send_debug("Found garbage in %.100s.", filename);
                     76:          continue; /* Extra garbage */
                     77:        default:
                     78:          continue; /* Weird... */
                     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:        {
                     88:          negated = 1;
                     89:          host++;
                     90:        }
                     91:       else
                     92:        if (host[0] == '+')
                     93:          host++;
                     94:
                     95:       if (user[0] == '-')
                     96:        {
                     97:          negated = 1;
                     98:          user++;
                     99:        }
                    100:       else
                    101:        if (user[0] == '+')
                    102:          user++;
                    103:
                    104:       /* Check for empty host/user names (particularly '+'). */
                    105:       if (!host[0] || !user[0])
                    106:        {
                    107:          /* We come here if either was '+' or '-'. */
                    108:          packet_send_debug("Ignoring wild host/user names in %.100s.",
                    109:                            filename);
                    110:          continue;
                    111:        }
                    112:
                    113:       /* Verify that host name matches. */
                    114:       if (host[0] == '@')
                    115:        {
                    116:          if (!innetgr(host + 1, hostname, NULL, NULL) &&
                    117:              !innetgr(host + 1, ipaddr, NULL, NULL))
                    118:            continue;
                    119:        }
                    120:       else
1.5       deraadt   121:        if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
1.1       deraadt   122:          continue; /* Different hostname. */
                    123:
                    124:       /* Verify that user name matches. */
                    125:       if (user[0] == '@')
                    126:        {
                    127:          if (!innetgr(user + 1, NULL, client_user, NULL))
                    128:            continue;
                    129:        }
                    130:       else
                    131:        if (strcmp(user, client_user) != 0)
                    132:          continue; /* Different username. */
                    133:
                    134:       /* Found the user and host. */
                    135:       fclose(f);
                    136:
                    137:       /* If the entry was negated, deny access. */
                    138:       if (negated)
                    139:        {
                    140:          packet_send_debug("Matched negative entry in %.100s.",
                    141:                            filename);
                    142:          return 0;
                    143:        }
                    144:
                    145:       /* Accept authentication. */
                    146:       return 1;
                    147:     }
                    148:
                    149:   /* Authentication using this file denied. */
                    150:   fclose(f);
                    151:   return 0;
                    152: }
                    153:
                    154: /* Tries to authenticate the user using the .shosts or .rhosts file.
                    155:    Returns true if authentication succeeds.  If ignore_rhosts is
                    156:    true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
                    157:    are ignored). */
                    158:
1.6       markus    159: int auth_rhosts(struct passwd *pw, const char *client_user)
1.1       deraadt   160: {
1.6       markus    161:   extern ServerOptions options;
1.1       deraadt   162:   char buf[1024];
                    163:   const char *hostname, *ipaddr;
                    164:   struct stat st;
                    165:   static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL };
                    166:   unsigned int rhosts_file_index;
                    167:
                    168:   /* Quick check: if the user has no .shosts or .rhosts files, return failure
                    169:      immediately without doing costly lookups from name servers. */
                    170:   /* Switch to the user's uid. */
                    171:   temporarily_use_uid(pw->pw_uid);
                    172:   for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
                    173:        rhosts_file_index++)
                    174:     {
                    175:       /* Check users .rhosts or .shosts. */
1.3       deraadt   176:       snprintf(buf, sizeof buf, "%.500s/%.100s",
1.1       deraadt   177:              pw->pw_dir, rhosts_files[rhosts_file_index]);
                    178:       if (stat(buf, &st) >= 0)
                    179:        break;
                    180:     }
                    181:   /* Switch back to privileged uid. */
                    182:   restore_uid();
                    183:
                    184:   if (!rhosts_files[rhosts_file_index] && stat("/etc/hosts.equiv", &st) < 0 &&
                    185:       stat(SSH_HOSTS_EQUIV, &st) < 0)
                    186:     return 0; /* The user has no .shosts or .rhosts file and there are no
                    187:                 system-wide files. */
                    188:
                    189:   /* Get the name, address, and port of the remote host.  */
                    190:   hostname = get_canonical_hostname();
                    191:   ipaddr = get_remote_ipaddr();
                    192:
                    193:   /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
                    194:   if (pw->pw_uid != 0)
                    195:     {
                    196:       if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
                    197:                            pw->pw_name))
                    198:        {
                    199:          packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
                    200:                            hostname, ipaddr);
                    201:          return 1;
                    202:        }
                    203:       if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
                    204:                            pw->pw_name))
                    205:        {
                    206:          packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
                    207:                            hostname, ipaddr, SSH_HOSTS_EQUIV);
                    208:          return 1;
                    209:        }
                    210:     }
                    211:
                    212:   /* Check that the home directory is owned by root or the user, and is not
                    213:      group or world writable. */
                    214:   if (stat(pw->pw_dir, &st) < 0)
                    215:     {
1.8     ! markus    216:       log("Rhosts authentication refused for %.100s: no home directory %.200s",
1.1       deraadt   217:          pw->pw_name, pw->pw_dir);
                    218:       packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
                    219:                        pw->pw_name, pw->pw_dir);
                    220:       return 0;
                    221:     }
1.6       markus    222:   if (options.strict_modes &&
1.1       deraadt   223:       ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
                    224:        (st.st_mode & 022) != 0))
                    225:     {
                    226:       log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
                    227:          pw->pw_name);
                    228:       packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
                    229:                        pw->pw_name);
                    230:       return 0;
                    231:     }
                    232:
                    233:   /* Check all .rhosts files (currently .shosts and .rhosts). */
                    234:   /* Temporarily use the user's uid. */
                    235:   temporarily_use_uid(pw->pw_uid);
                    236:   for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
                    237:        rhosts_file_index++)
                    238:     {
                    239:       /* Check users .rhosts or .shosts. */
1.3       deraadt   240:       snprintf(buf, sizeof buf, "%.500s/%.100s",
1.1       deraadt   241:              pw->pw_dir, rhosts_files[rhosts_file_index]);
                    242:       if (stat(buf, &st) < 0)
                    243:        continue; /* No such file. */
                    244:
                    245:       /* Make sure that the file is either owned by the user or by root,
                    246:         and make sure it is not writable by anyone but the owner.  This is
                    247:         to help avoid novices accidentally allowing access to their account
                    248:         by anyone. */
1.6       markus    249:       if (options.strict_modes &&
1.1       deraadt   250:          ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
                    251:           (st.st_mode & 022) != 0))
                    252:        {
                    253:          log("Rhosts authentication refused for %.100s: bad modes for %.200s",
                    254:              pw->pw_name, buf);
                    255:          packet_send_debug("Bad file modes for %.200s", buf);
                    256:          continue;
                    257:        }
                    258:
                    259:       /* Check if we have been configured to ignore .rhosts and .shosts
                    260:         files. */
1.6       markus    261:       if (options.ignore_rhosts)
1.1       deraadt   262:        {
                    263:          packet_send_debug("Server has been configured to ignore %.100s.",
                    264:                            rhosts_files[rhosts_file_index]);
                    265:          continue;
                    266:        }
                    267:
                    268:       /* Check if authentication is permitted by the file. */
                    269:       if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name))
                    270:        {
                    271:          packet_send_debug("Accepted by %.100s.",
                    272:                            rhosts_files[rhosts_file_index]);
                    273:          /* Restore the privileged uid. */
                    274:          restore_uid();
                    275:          return 1;
                    276:        }
                    277:     }
                    278:
                    279:   /* Rhosts authentication denied. */
                    280:   /* Restore the privileged uid. */
                    281:   restore_uid();
                    282:   return 0;
                    283: }