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

Diff for /src/usr.bin/ssh/auth-rhosts.c between version 1.8 and 1.9

version 1.8, 1999/11/18 14:00:47 version 1.9, 1999/11/23 22:25:52
Line 28 
Line 28 
    /etc/hosts.equiv).  This returns true if authentication can be granted     /etc/hosts.equiv).  This returns true if authentication can be granted
    based on the file, and returns zero otherwise. */     based on the file, and returns zero otherwise. */
   
 int check_rhosts_file(const char *filename, const char *hostname,  int
                       const char *ipaddr, const char *client_user,  check_rhosts_file(const char *filename, const char *hostname,
                       const char *server_user)                    const char *ipaddr, const char *client_user,
                     const char *server_user)
 {  {
   FILE *f;          FILE *f;
   char buf[1024]; /* Must not be larger than host, user, dummy below. */          char buf[1024]; /* Must not be larger than host, user, dummy below. */
   
   /* Open the .rhosts file. */  
   f = fopen(filename, "r");  
   if (!f)  
     return 0; /* Cannot read the .rhosts - deny access. */  
   
   /* Go through the file, checking every entry. */          /* Open the .rhosts file, deny if unreadable */
   while (fgets(buf, sizeof(buf), f))          f = fopen(filename, "r");
     {          if (!f)
       /* All three must be at least as big as buf to avoid overflows. */                  return 0;
       char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;  
       int negated;  
   
       for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)  
         ;  
       if (*cp == '#' || *cp == '\n' || !*cp)  
         continue;  
   
       /* NO_PLUS is supported at least on OSF/1.  We skip it (we don't ever          /* Go through the file, checking every entry. */
          support the plus syntax). */          while (fgets(buf, sizeof(buf), f)) {
       if (strncmp(cp, "NO_PLUS", 7) == 0)                  /* All three must be at least as big as buf to avoid overflows. */
         continue;                  char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
                   int negated;
   
       /* This should be safe because each buffer is as big as the whole                  for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
          string, and thus cannot be overwritten. */                          ;
       switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy))                  if (*cp == '#' || *cp == '\n' || !*cp)
         {                          continue;
         case 0:  
           packet_send_debug("Found empty line in %.100s.", filename);  
           continue; /* Empty line? */  
         case 1:  
           /* Host name only. */  
           strlcpy(userbuf, server_user, sizeof(userbuf));  
           break;  
         case 2:  
           /* Got both host and user name. */  
           break;  
         case 3:  
           packet_send_debug("Found garbage in %.100s.", filename);  
           continue; /* Extra garbage */  
         default:  
           continue; /* Weird... */  
         }  
   
       host = hostbuf;                  /* NO_PLUS is supported at least on OSF/1.  We skip it (we
       user = userbuf;                     don't ever support the plus syntax). */
       negated = 0;                  if (strncmp(cp, "NO_PLUS", 7) == 0)
                           continue;
   
       /* Process negated host names, or positive netgroups. */                  /* This should be safe because each buffer is as big as
       if (host[0] == '-')                     the whole string, and thus cannot be overwritten. */
         {                  switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) {
           negated = 1;                  case 0:
           host++;                          packet_send_debug("Found empty line in %.100s.", filename);
         }                          continue;
       else                  case 1:
         if (host[0] == '+')                          /* Host name only. */
           host++;                          strlcpy(userbuf, server_user, sizeof(userbuf));
                           break;
                   case 2:
                           /* Got both host and user name. */
                           break;
                   case 3:
                           packet_send_debug("Found garbage in %.100s.", filename);
                           continue;
                   default:
                           /* Weird... */
                           continue;
                   }
   
       if (user[0] == '-')                  host = hostbuf;
         {                  user = userbuf;
           negated = 1;                  negated = 0;
           user++;  
         }  
       else  
         if (user[0] == '+')  
           user++;  
   
       /* Check for empty host/user names (particularly '+'). */                  /* Process negated host names, or positive netgroups. */
       if (!host[0] || !user[0])                  if (host[0] == '-') {
         {                          negated = 1;
           /* We come here if either was '+' or '-'. */                          host++;
           packet_send_debug("Ignoring wild host/user names in %.100s.",                  } else if (host[0] == '+')
                             filename);                          host++;
           continue;  
         }  
   
       /* Verify that host name matches. */  
       if (host[0] == '@')  
         {  
           if (!innetgr(host + 1, hostname, NULL, NULL) &&  
               !innetgr(host + 1, ipaddr, NULL, NULL))  
             continue;  
         }  
       else  
         if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)  
           continue; /* Different hostname. */  
   
       /* Verify that user name matches. */                  if (user[0] == '-') {
       if (user[0] == '@')                          negated = 1;
         {                          user++;
           if (!innetgr(user + 1, NULL, client_user, NULL))                  } else if (user[0] == '+')
             continue;                          user++;
         }  
       else  
         if (strcmp(user, client_user) != 0)  
           continue; /* Different username. */  
   
       /* Found the user and host. */                  /* Check for empty host/user names (particularly '+'). */
       fclose(f);                  if (!host[0] || !user[0]) {
                           /* We come here if either was '+' or '-'. */
                           packet_send_debug("Ignoring wild host/user names in %.100s.",
                                             filename);
                           continue;
                   }
                   /* Verify that host name matches. */
                   if (host[0] == '@') {
                           if (!innetgr(host + 1, hostname, NULL, NULL) &&
                               !innetgr(host + 1, ipaddr, NULL, NULL))
                                   continue;
                   } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0)
                           continue;       /* Different hostname. */
   
       /* If the entry was negated, deny access. */                  /* Verify that user name matches. */
       if (negated)                  if (user[0] == '@') {
         {                          if (!innetgr(user + 1, NULL, client_user, NULL))
           packet_send_debug("Matched negative entry in %.100s.",                                  continue;
                             filename);                  } else if (strcmp(user, client_user) != 0)
           return 0;                          continue;       /* Different username. */
   
                   /* Found the user and host. */
                   fclose(f);
   
                   /* If the entry was negated, deny access. */
                   if (negated) {
                           packet_send_debug("Matched negative entry in %.100s.",
                                             filename);
                           return 0;
                   }
                   /* Accept authentication. */
                   return 1;
         }          }
   
       /* Accept authentication. */          /* Authentication using this file denied. */
       return 1;          fclose(f);
     }          return 0;
   
   /* Authentication using this file denied. */  
   fclose(f);  
   return 0;  
 }  }
   
 /* Tries to authenticate the user using the .shosts or .rhosts file.  /* Tries to authenticate the user using the .shosts or .rhosts file.
    Returns true if authentication succeeds.  If ignore_rhosts is     Returns true if authentication succeeds.  If ignore_rhosts is
    true, only /etc/hosts.equiv will be considered (.rhosts and .shosts     true, only /etc/hosts.equiv will be considered (.rhosts and .shosts
    are ignored). */     are ignored). */
   
 int auth_rhosts(struct passwd *pw, const char *client_user)  int
   auth_rhosts(struct passwd *pw, const char *client_user)
 {  {
   extern ServerOptions options;          extern ServerOptions options;
   char buf[1024];          char buf[1024];
   const char *hostname, *ipaddr;          const char *hostname, *ipaddr;
   struct stat st;          struct stat st;
   static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL };          static const char *rhosts_files[] = {".shosts", ".rhosts", NULL};
   unsigned int rhosts_file_index;          unsigned int rhosts_file_index;
   
   /* Quick check: if the user has no .shosts or .rhosts files, return failure          /* Quick check: if the user has no .shosts or .rhosts files,
      immediately without doing costly lookups from name servers. */             return failure immediately without doing costly lookups from
   /* Switch to the user's uid. */             name servers. */
   temporarily_use_uid(pw->pw_uid);          /* Switch to the user's uid. */
   for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];          temporarily_use_uid(pw->pw_uid);
        rhosts_file_index++)          for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
     {               rhosts_file_index++) {
       /* Check users .rhosts or .shosts. */                  /* Check users .rhosts or .shosts. */
       snprintf(buf, sizeof buf, "%.500s/%.100s",                  snprintf(buf, sizeof buf, "%.500s/%.100s",
               pw->pw_dir, rhosts_files[rhosts_file_index]);                           pw->pw_dir, rhosts_files[rhosts_file_index]);
       if (stat(buf, &st) >= 0)                  if (stat(buf, &st) >= 0)
         break;                          break;
     }          }
   /* Switch back to privileged uid. */          /* Switch back to privileged uid. */
   restore_uid();          restore_uid();
   
   if (!rhosts_files[rhosts_file_index] && stat("/etc/hosts.equiv", &st) < 0 &&          /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */
       stat(SSH_HOSTS_EQUIV, &st) < 0)          if (!rhosts_files[rhosts_file_index] &&
     return 0; /* The user has no .shosts or .rhosts file and there are no              stat("/etc/hosts.equiv", &st) < 0 &&
                  system-wide files. */              stat(SSH_HOSTS_EQUIV, &st) < 0)
                   return 0;
   
   /* Get the name, address, and port of the remote host.  */          /* Get the name, address, and port of the remote host.  */
   hostname = get_canonical_hostname();          hostname = get_canonical_hostname();
   ipaddr = get_remote_ipaddr();          ipaddr = get_remote_ipaddr();
   
   /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */          /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */
   if (pw->pw_uid != 0)          if (pw->pw_uid != 0) {
     {                  if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,
       if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user,                                        pw->pw_name)) {
                             pw->pw_name))                          packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",
         {                                            hostname, ipaddr);
           packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.",                          return 1;
                             hostname, ipaddr);                  }
           return 1;                  if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,
                                         pw->pw_name)) {
                           packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",
                                         hostname, ipaddr, SSH_HOSTS_EQUIV);
                           return 1;
                   }
         }          }
       if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user,          /* Check that the home directory is owned by root or the user, and
                             pw->pw_name))             is not group or world writable. */
         {          if (stat(pw->pw_dir, &st) < 0) {
           packet_send_debug("Accepted for %.100s [%.100s] by %.100s.",                  log("Rhosts authentication refused for %.100s: no home directory %.200s",
                             hostname, ipaddr, SSH_HOSTS_EQUIV);                      pw->pw_name, pw->pw_dir);
           return 1;                  packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",
                                     pw->pw_name, pw->pw_dir);
                   return 0;
         }          }
     }          if (options.strict_modes &&
               ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
   /* Check that the home directory is owned by root or the user, and is not               (st.st_mode & 022) != 0)) {
      group or world writable. */                  log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
   if (stat(pw->pw_dir, &st) < 0)                      pw->pw_name);
     {                  packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",
       log("Rhosts authentication refused for %.100s: no home directory %.200s",                                    pw->pw_name);
           pw->pw_name, pw->pw_dir);                  return 0;
       packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s",  
                         pw->pw_name, pw->pw_dir);  
       return 0;  
     }  
   if (options.strict_modes &&  
       ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
        (st.st_mode & 022) != 0))  
     {  
       log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",  
           pw->pw_name);  
       packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.",  
                         pw->pw_name);  
       return 0;  
     }  
   
   /* Check all .rhosts files (currently .shosts and .rhosts). */  
   /* Temporarily use the user's uid. */  
   temporarily_use_uid(pw->pw_uid);  
   for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];  
        rhosts_file_index++)  
     {  
       /* Check users .rhosts or .shosts. */  
       snprintf(buf, sizeof buf, "%.500s/%.100s",  
               pw->pw_dir, rhosts_files[rhosts_file_index]);  
       if (stat(buf, &st) < 0)  
         continue; /* No such file. */  
   
       /* Make sure that the file is either owned by the user or by root,  
          and make sure it is not writable by anyone but the owner.  This is  
          to help avoid novices accidentally allowing access to their account  
          by anyone. */  
       if (options.strict_modes &&  
           ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
            (st.st_mode & 022) != 0))  
         {  
           log("Rhosts authentication refused for %.100s: bad modes for %.200s",  
               pw->pw_name, buf);  
           packet_send_debug("Bad file modes for %.200s", buf);  
           continue;  
         }          }
           /* Temporarily use the user's uid. */
           temporarily_use_uid(pw->pw_uid);
   
       /* Check if we have been configured to ignore .rhosts and .shosts          /* Check all .rhosts files (currently .shosts and .rhosts). */
          files. */          for (rhosts_file_index = 0; rhosts_files[rhosts_file_index];
       if (options.ignore_rhosts)               rhosts_file_index++) {
         {                  /* Check users .rhosts or .shosts. */
           packet_send_debug("Server has been configured to ignore %.100s.",                  snprintf(buf, sizeof buf, "%.500s/%.100s",
                             rhosts_files[rhosts_file_index]);                           pw->pw_dir, rhosts_files[rhosts_file_index]);
           continue;                  if (stat(buf, &st) < 0)
         }                          continue;
   
       /* Check if authentication is permitted by the file. */                  /* Make sure that the file is either owned by the user or
       if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name))                     by root, and make sure it is not writable by anyone but
         {                     the owner.  This is to help avoid novices accidentally
           packet_send_debug("Accepted by %.100s.",                     allowing access to their account by anyone. */
                             rhosts_files[rhosts_file_index]);                  if (options.strict_modes &&
           /* Restore the privileged uid. */                      ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
           restore_uid();                       (st.st_mode & 022) != 0)) {
           return 1;                          log("Rhosts authentication refused for %.100s: bad modes for %.200s",
                               pw->pw_name, buf);
                           packet_send_debug("Bad file modes for %.200s", buf);
                           continue;
                   }
                   /* Check if we have been configured to ignore .rhosts and .shosts files. */
                   if (options.ignore_rhosts) {
                           packet_send_debug("Server has been configured to ignore %.100s.",
                                             rhosts_files[rhosts_file_index]);
                           continue;
                   }
                   /* Check if authentication is permitted by the file. */
                   if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) {
                           packet_send_debug("Accepted by %.100s.",
                                             rhosts_files[rhosts_file_index]);
                           /* Restore the privileged uid. */
                           restore_uid();
                           return 1;
                   }
         }          }
     }  
   
   /* Rhosts authentication denied. */          /* Restore the privileged uid. */
   /* Restore the privileged uid. */          restore_uid();
   restore_uid();          return 0;
   return 0;  
 }  }

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9