/* Portions taken from the skey distribution on Oct 21 1993 */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <netdb.h> #include <arpa/inet.h> #include <stdio.h> #include <pwd.h> #include <syslog.h> #include <unistd.h> #include <stdlib.h> #include <skey.h> #if (MAXHOSTNAMELEN < 64) /* AIX weirdness */ #undef MAXHOSTNAMELEN #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 255 #endif #include "pathnames.h" static int isaddr(); static int rdnets(); #define MAXADDR 16 /* how many addresses can a machine * have? */ /* * Turn host into an IP address and then look it up in the authorization * database to determine if ordinary password logins are OK */ int authfile(host) char *host; { char *addr[MAXADDR]; char **ap; long n; struct hostent *hp; char **lp; struct hostent *xp; int addr_length; if (strlen(host) == 0) { /* Local login, okay */ return 1; } if (isaddr(host)) { return rdnets(inet_addr(host)); } else { /* * Stash away a copy of the host address list because it will be * clobbered by other gethostbyXXX() calls. */ hp = gethostbyname(host); if (hp == NULL) { syslog(LOG_ERR, "unknown host: %s", host); return 0; } if (hp->h_addrtype != AF_INET) { syslog(LOG_ERR, "unknown network family: %d", hp->h_addrtype); return 0; } for (lp = hp->h_addr_list, ap = addr; ap < addr + MAXADDR; lp++, ap++) { if (*lp == NULL) { *ap = 0; break; } else { if ((*ap = malloc(hp->h_length)) == 0) { syslog(LOG_ERR, "out of memory"); return 0; } memcpy(*ap, *lp, hp->h_length); } } addr_length = hp->h_length; /* * See if any of the addresses matches a pattern in the control file. * Report and skip the address if it does not belong to the remote * host. Assume localhost == localhost.domain. */ #define NEQ(x,y) (strcasecmp((x),(y)) != 0) while (ap-- > addr) { memcpy((char *) &n, *ap, addr_length); if (rdnets(n)) { if ((hp = gethostbyaddr(*ap, addr_length, AF_INET)) == 0 || (NEQ(host, hp->h_name) && NEQ(host, "localhost"))) { syslog(LOG_ERR, "IP address %s not registered for host %s", inet_ntoa(*(struct in_addr *) * ap), host); continue; } return 1; } } return 0; } } static int rdnets(host) unsigned long host; { FILE *fp; char buf[128], *cp; long pattern, mask; char *strtok(); int permit_it = 0; /* * If auth file not found, be backwards compatible with standard login * and allow hard coded passwords in from anywhere. Some may consider * this a security hole, but backwards compatibility is more desirable * than others. If you don't like it, change the return value to be zero. */ if ((fp = fopen(_PATH_SKEYACCESS, "r")) == NULL) return 1; while (fgets(buf, sizeof(buf), fp), !feof(fp)) { if (buf[0] == '#') continue; /* Comment */ cp = strtok(buf, " \t"); if (cp == NULL) continue; /* two choices permit or deny */ if (strncasecmp(cp, "permit", 4) == 0) { permit_it = 1; } else { if (strncasecmp(cp, "deny", 4) == 0) { permit_it = 0; } else { continue; /* ignore this it is not * permit/deny */ } } cp = strtok(NULL, " \t"); if (cp == NULL) continue; /* Invalid line */ pattern = inet_addr(cp); cp = strtok(NULL, " \t"); if (cp == NULL) continue; /* Invalid line */ mask = inet_addr(cp); if ((host & mask) == pattern) { fclose(fp); return permit_it; } } fclose(fp); return 0; } /* * Return TRUE if string appears to be an IP address in dotted decimal; * return FALSE otherwise (i.e., if string is a domain name) */ static int isaddr(s) register char *s; { char c; if (s == NULL) return 1; /* Can't happen */ while ((c = *s++) != '\0') { if (c != '[' && c != ']' && !isdigit(c) && c != '.') return 0; } return 1; }