freebsd-src/lib/libskey/authfile.c
Paul Traina 0d92fee747 Clean up S/key library (libskey.a) so that filename access is via the
standard 4.4bsd pathnames mechanism.

Also document a potential security hole vs backwards compatibility tradeoff.
1994-05-27 07:50:08 +00:00

178 lines
4.0 KiB
C

/* 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>
#if (MAXHOSTNAMELEN < 64) /* AIX weirdness */
#undef MAXHOSTNAMELEN
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 255
#endif
#include "skey.h"
#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;
}