#ifndef LINT
static char rcsid[] = "$OpenBSD: acl.c,v 1.5 1997/08/05 09:26:55 maja Exp $";
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <netdb.h>
#include "acl.h"
#define TRUE 1
#define FALSE 0
static struct aclent *acl_root = NULL;
static int acl_read_line(fp, buf, size)
FILE *fp;
char *buf;
int size;
{
int len = 0;
char *c,*p,l;
do {
while (fgets(buf, size, fp)) {
c = buf;
while(*c != '\0') {
if ((*c == '#') || (*c == '\n')) {
*c = '\0';
} else {
c++;
}
}
c = p = buf; l = ' ';
while(*c != '\0') {
if ((isspace(l) != 0) && (isspace(*c) != 0)) {
c++;
} else {
l = *c++; *p = l; p++;
}
}
*p = '\0';
if (p != buf) {
--p;
if (isspace(*p) != 0) {
*p = '\0';
}
}
len = strlen(buf);
return len + 1;
}
} while (size > 0 && !feof(fp));
return len;
}
int
yp_acl_check_host(addr)
struct in_addr *addr;
{
struct aclent *p;
p = acl_root;
while (p != NULL) {
if ((addr->s_addr & p->s_mask) == p->s_addr) {
return(p->allow);
}
p = p->next;
}
return(TRUE);
}
void
acl_add_net(allow,addr,mask)
int allow;
struct in_addr *addr,*mask;
{
struct aclent *acl,*p;
acl = (struct aclent *) malloc((unsigned) sizeof(struct aclent));
acl->next = NULL;
acl->allow = allow;
acl->s_addr = addr->s_addr;
acl->s_mask = mask->s_addr;
if (acl_root == NULL) {
acl_root = acl;
} else {
p = acl_root;
while (p->next != NULL)
p = p->next;
p->next = acl;
}
}
void
acl_add_host(allow,addr)
int allow;
struct in_addr *addr;
{
struct in_addr mask;
mask.s_addr = htonl(0xffffffff);
acl_add_net(allow,addr,&mask);
}
int
yp_acl_init(file)
char *file;
{
char data_line[1024];
int line_no = 0;
int len,i;
int allow = TRUE;
int error_cnt = 0;
char *p,*k;
int state;
struct in_addr addr,mask,*host_addr;
struct hostent *host;
struct netent *net;
FILE *data_file = NULL;
if (file != NULL) {
data_file = fopen(file,"r");
};
while ((data_file != NULL) &&
(acl_read_line(data_file,data_line,sizeof(data_line)))) {
line_no++;
len = strlen(data_line);
if (len == 0) {
continue;
}
p = (char *) &data_line;
state = ACLS_INIT;
addr.s_addr = mask.s_addr = 0;
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
if (strcmp(k,"allow") == 0) {
allow = TRUE;
state = ACLS_ALLOW;
}
if (strcmp(k,"deny") == 0) {
allow = FALSE;
state = ACLS_DENY;
}
if (state == ACLS_INIT) {
state = ACLE_UVERB;
}
if ((*p != '\0') &&
((state == ACLS_ALLOW) || (state == ACLS_DENY))) {
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
if (strcmp(k,"all") == 0) {
state = state + ACLD_ALL;
}
if (strcmp(k,"host") == 0) {
state = state + ACLD_HOST;
}
if (strcmp(k,"net") == 0) {
state = state + ACLD_NET;
}
if ((state == ACLS_ALLOW) || (state == ACLS_DENY)) {
state = ACLE_U2VERB;
}
}
if ((state == ACLS_ALLOW) || (state == ACLS_DENY)) {
state = ACLE_UEOL;
}
if ((*p == '\0') &&
((state == ACLS_ALLOW_ALL) || (state == ACLS_DENY_ALL))) {
acl_add_net(allow,&addr,&mask);
state = ACLE_OK;
}
if ((*p != '\0') &&
(state >= ACLS_ALLOW_HOST) && (state <= ACLS_DENY_NET)) {
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
if ((state == ACLS_ALLOW_HOST) || (state == ACLS_DENY_HOST)) {
if ((*k >= '0') && (*k <= '9')) {
(void)inet_aton(k,&addr);
acl_add_host(allow,&addr);
state = state + ACLD_HOST_DONE;
} else {
host = gethostbyname(k);
if (host == NULL) {
state = ACLE_NOHOST;
} else {
if (host->h_addrtype == AF_INET) {
while ((host_addr = (struct in_addr *) *host->h_addr_list++)
!= NULL)
acl_add_host(allow,host_addr);
}
state = state + ACLD_HOST_DONE;
}
}
}
if ((state == ACLS_ALLOW_NET) || (state == ACLS_DENY_NET)) {
if ((*k >= '0') && (*k <= '9')) {
(void)inet_aton(k,&addr);
state = state + ACLD_NET_DONE;
} else {
net = getnetbyname(k);
if (net == NULL) {
state = ACLE_NONET;
} else {
addr.s_addr = ntohl(net->n_net);
state = state + ACLD_NET_DONE;
}
}
}
}
if ((state >= ACLS_ALLOW_HOST) && (state <= ACLS_DENY_NET)) {
state = ACLE_UEOL;
}
if ((*p == '\0') &&
((state == ACLS_ALLOW_HOST_DONE) || (state == ACLS_DENY_HOST_DONE))) {
state = ACLE_OK;
}
if ((*p == '\0') &&
((state == ACLS_ALLOW_NET_DONE) || (state == ACLS_DENY_NET_DONE))) {
mask.s_addr = htonl(0xffffff00);
if (ntohl(addr.s_addr) < 0xc0000000) {
mask.s_addr = htonl(0xffff0000);
}
if (ntohl(addr.s_addr) < 0x80000000) {
mask.s_addr = htonl(0xff000000);
}
acl_add_net(allow,&addr,&mask);
state = ACLE_OK;
}
if ((*p != '\0') &&
((state == ACLS_ALLOW_NET_DONE) || (state == ACLS_DENY_NET_DONE))) {
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
if (strcmp(k,"netmask") == 0) {
state = state + ACLD_NET_MASK;
}
if ((state == ACLS_ALLOW_NET_DONE) || (state == ACLS_DENY_NET_DONE)) {
state = ACLE_NONETMASK;
}
}
if ((*p != '\0') &&
((state == ACLS_ALLOW_NET_MASK) || (state == ACLS_DENY_NET_MASK))) {
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
if ((state == ACLS_ALLOW_NET_MASK) || (state == ACLS_DENY_NET_MASK)) {
if ((*k >= '0') && (*k <= '9')) {
(void)inet_aton(k,&mask);
state = state + ACLD_NET_EOL;
} else {
net = getnetbyname(k);
if (net == NULL) {
state = ACLE_NONET;
} else {
mask.s_addr = ntohl(net->n_net);
state = state + ACLD_NET_EOL;
}
}
}
}
if ((state == ACLS_ALLOW_NET_MASK) || (state == ACLS_DENY_NET_MASK)) {
state = ACLE_UEOL;
}
if ((*p == '\0') &&
((state == ACLS_ALLOW_NET_EOL) || (state == ACLS_DENY_NET_EOL))) {
acl_add_net(allow,&addr,&mask);
state = ACLE_OK;
}
switch (state) {
case ACLE_NONETMASK:
fprintf(stderr,"acl: excpected \"netmask\" missing at line %d\n",line_no);
break;
case ACLE_NONET:
error_cnt++;
fprintf(stderr,"acl: unknown network at line %d\n",line_no);
break;
case ACLE_NOHOST:
error_cnt++;
fprintf(stderr,"acl: unknown host at line %d\n",line_no);
break;
case ACLE_UVERB:
error_cnt++;
fprintf(stderr,"acl: unknown verb at line %d\n",line_no);
break;
case ACLE_U2VERB:
error_cnt++;
fprintf(stderr,"acl: unknown secondary verb at line %d\n",line_no);
break;
case ACLE_UEOL:
error_cnt++;
fprintf(stderr,"acl: unexpected end of line at line %d\n",line_no);
break;
case ACLE_OK:
break;
default:
error_cnt++;
fprintf(stderr,"acl: unexpected state %d %s\n",state,k);
}
}
if (data_file != NULL) {
(void)fflush(stderr);
(void)fclose(data_file);
}
addr.s_addr = mask.s_addr = 0;
allow = TRUE;
acl_add_net(allow,&addr,&mask);
return(error_cnt);
}
int
yp_acl_securenet(file)
char *file;
{
char data_line[1024];
int line_no = 0;
int len,i;
int allow = TRUE;
int error_cnt = 0;
char *p,*k;
int state;
struct in_addr addr,mask;
struct netent *net;
FILE *data_file = NULL;
if (file != NULL) {
data_file = fopen(file,"r");
};
addr.s_addr = htonl(0x7f000001);
mask.s_addr = htonl(0xffffffff);
allow = TRUE;
acl_add_net(allow,&addr,&mask);
while ((data_file != NULL) &&
(acl_read_line(data_file,data_line,sizeof(data_line)))) {
line_no++;
len = strlen(data_line);
if (len == 0) {
continue;
}
p = (char *) &data_line;
state = ACLS_INIT;
addr.s_addr = mask.s_addr = 0;
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
state = ACLS_ALLOW_NET_MASK;
}
if (state == ACLS_INIT) {
state = ACLE_UEOL;
}
if (state == ACLS_ALLOW_NET_MASK) {
if ((*k >= '0') && (*k <= '9')) {
(void)inet_aton(k,&mask);
state = ACLS_ALLOW_NET;
} else {
net = getnetbyname(k);
if (net == NULL) {
state = ACLE_NONET;
} else {
mask.s_addr = ntohl(net->n_net);
state = ACLS_ALLOW_NET;
}
}
k = p; i = 0;
while ((*p != '\0') &&
(!isspace(*p = tolower(*p)))) {
p++; i++;
};
if (*p != '\0') {
*p++ = '\0';
}
}
if ((state == ACLS_ALLOW_NET_MASK)) {
state = ACLE_UEOL;
}
if (state == ACLS_ALLOW_NET) {
if ((*k >= '0') && (*k <= '9')) {
(void)inet_aton(k,&addr);
state = ACLS_ALLOW_NET_EOL;
} else {
net = getnetbyname(k);
if (net == NULL) {
state = ACLE_NONET;
} else {
addr.s_addr = ntohl(net->n_net);
state = ACLS_ALLOW_NET_EOL;
}
}
}
if ((state == ACLS_ALLOW_NET)) {
state = ACLE_UEOL;
}
if ((*p == '\0') && (state == ACLS_ALLOW_NET_EOL)) {
acl_add_net(allow,&addr,&mask);
state = ACLE_OK;
}
switch (state) {
case ACLE_NONET:
error_cnt++;
fprintf(stderr,"securenet: unknown network at line %d\n",line_no);
break;
case ACLE_UEOL:
error_cnt++;
fprintf(stderr,"securenet: unexpected end of line at line %d\n",line_no);
break;
case ACLE_OK:
break;
default:
error_cnt++;
fprintf(stderr,"securenet: unexpected state %d %s\n",state,k);
}
}
if (data_file != NULL) {
(void)fflush(stderr);
(void)fclose(data_file);
addr.s_addr = mask.s_addr = 0;
allow = FALSE;
acl_add_net(allow,&addr,&mask);
}
addr.s_addr = mask.s_addr = 0;
allow = TRUE;
acl_add_net(allow,&addr,&mask);
return(error_cnt);
}
void
yp_acl_reset()
{
struct aclent *p;
while (acl_root != NULL) {
p = acl_root->next;
free(acl_root);
acl_root = p;
}
}