#include <ctype.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/errno.h>
static char *_netgr_yp_domain;
int _use_only_yp;
static int _netgr_yp_enabled;
static int _yp_innetgr;
#endif
#ifndef _PATH_NETGROUP
#define _PATH_NETGROUP "/etc/netgroup"
#endif
struct linelist {
struct linelist *l_next;
int l_parsed;
char *l_groupname;
char *l_line;
};
struct netgrp {
struct netgrp *ng_next;
char *ng_str[3];
};
#define NG_HOST 0
#define NG_USER 1
#define NG_DOM 2
static struct linelist *linehead = NULL;
static struct netgrp *nextgrp = NULL;
static struct {
struct netgrp *gr;
char *grname;
} grouphead = {
NULL,
NULL,
};
static FILE *netf = NULL;
static int parse_netgrp(const char *);
static struct linelist *read_for_group(const char *);
#define LINSIZ 1024
void
setnetgrent(const char *group)
{
#ifdef YP
struct stat _yp_statp;
char _yp_plus;
#endif
if (group == NULL || !strlen(group))
return;
if (grouphead.gr == NULL ||
strcmp(group, grouphead.grname)) {
endnetgrent();
#ifdef YP
_use_only_yp = 0;
if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
errno == ENOENT) || _yp_statp.st_size == 0)
_use_only_yp = _netgr_yp_enabled = 1;
if ((netf = fopen(_PATH_NETGROUP,"r")) != NULL ||_use_only_yp){
if (netf) {
fscanf(netf, "%c", &_yp_plus);
rewind(netf);
if (_yp_plus == '+')
_use_only_yp = _netgr_yp_enabled = 1;
}
if (_use_only_yp && _yp_innetgr) {
if (netf != NULL)
fclose(netf);
return;
}
#else
if ((netf = fopen(_PATH_NETGROUP, "r"))) {
#endif
if (parse_netgrp(group))
endnetgrent();
else {
grouphead.grname = (char *)
malloc(strlen(group) + 1);
strcpy(grouphead.grname, group);
}
if (netf)
fclose(netf);
}
}
nextgrp = grouphead.gr;
}
int
getnetgrent(char **hostp, char **userp, char **domp)
{
#ifdef YP
_yp_innetgr = 0;
#endif
if (nextgrp) {
*hostp = nextgrp->ng_str[NG_HOST];
*userp = nextgrp->ng_str[NG_USER];
*domp = nextgrp->ng_str[NG_DOM];
nextgrp = nextgrp->ng_next;
return (1);
}
return (0);
}
void
endnetgrent(void)
{
struct linelist *lp, *olp;
struct netgrp *gp, *ogp;
lp = linehead;
while (lp) {
olp = lp;
lp = lp->l_next;
free(olp->l_groupname);
free(olp->l_line);
free((char *)olp);
}
linehead = NULL;
if (grouphead.grname) {
free(grouphead.grname);
grouphead.grname = NULL;
}
gp = grouphead.gr;
while (gp) {
ogp = gp;
gp = gp->ng_next;
if (ogp->ng_str[NG_HOST])
free(ogp->ng_str[NG_HOST]);
if (ogp->ng_str[NG_USER])
free(ogp->ng_str[NG_USER]);
if (ogp->ng_str[NG_DOM])
free(ogp->ng_str[NG_DOM]);
free((char *)ogp);
}
grouphead.gr = NULL;
nextgrp = NULL;
#ifdef YP
_netgr_yp_enabled = 0;
#endif
}
#ifdef YP
static int
_listmatch(const char *list, const char *group, int len)
{
const char *ptr = list;
const char *cptr;
int glen = strlen(group);
while(isspace((unsigned char)*ptr))
ptr++;
while (ptr < list + len) {
cptr = ptr;
while(*ptr != ',' && *ptr != '\0' && !isspace((unsigned char)*ptr))
ptr++;
if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
return(1);
while(*ptr == ',' || isspace((unsigned char)*ptr))
ptr++;
}
return(0);
}
static int
_revnetgr_lookup(char *lookupdom, char *map, const char *str,
const char *dom, const char *group)
{
int y, rv, rot;
char key[MAXHOSTNAMELEN];
char *result;
int resultlen;
for (rot = 0; ; rot++) {
switch (rot) {
case(0): snprintf(key, MAXHOSTNAMELEN, "%s.%s",
str, dom?dom:lookupdom);
break;
case(1): snprintf(key, MAXHOSTNAMELEN, "%s.*",
str);
break;
case(2): snprintf(key, MAXHOSTNAMELEN, "*.%s",
dom?dom:lookupdom);
break;
case(3): snprintf(key, MAXHOSTNAMELEN, "*.*");
break;
default: return(0);
}
y = yp_match(lookupdom, map, key, strlen(key), &result,
&resultlen);
if (y == 0) {
rv = _listmatch(result, group, resultlen);
free(result);
if (rv) return(1);
} else if (y != YPERR_KEY) {
return(-1);
}
}
}
#endif
int
innetgr(const char *group, const char *host, const char *user, const char *dom)
{
char *hst, *usr, *dm;
if (group == NULL || !strlen(group))
return (0);
#ifdef YP
_yp_innetgr = 1;
#endif
setnetgrent(group);
#ifdef YP
_yp_innetgr = 0;
if (_use_only_yp && (host == NULL) != (user == NULL)) {
int ret;
if(yp_get_default_domain(&_netgr_yp_domain))
return(0);
ret = _revnetgr_lookup(_netgr_yp_domain,
host?"netgroup.byhost":"netgroup.byuser",
host?host:user, dom, group);
if (ret == 1)
return(1);
else if (ret == 0 && dom != NULL)
return(0);
}
setnetgrent(group);
#endif
while (getnetgrent(&hst, &usr, &dm))
if ((host == NULL || hst == NULL || !strcmp(host, hst)) &&
(user == NULL || usr == NULL || !strcmp(user, usr)) &&
( dom == NULL || dm == NULL || !strcmp(dom, dm))) {
endnetgrent();
return (1);
}
endnetgrent();
return (0);
}
static int
parse_netgrp(const char *group)
{
char *spos, *epos;
int len, strpos;
#ifdef DEBUG
int fields;
#endif
char *pos, *gpos;
struct netgrp *grp;
struct linelist *lp = linehead;
while (lp) {
if (!strcmp(group, lp->l_groupname))
break;
lp = lp->l_next;
}
if (lp == NULL &&
(lp = read_for_group(group)) == NULL)
return (1);
if (lp->l_parsed) {
#ifdef DEBUG
fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
#endif
return (1);
} else
lp->l_parsed = 1;
pos = lp->l_line;
while (pos != NULL && *pos != '\0') {
if (*pos == '(') {
grp = (struct netgrp *)malloc(sizeof (struct netgrp));
bzero((char *)grp, sizeof (struct netgrp));
grp->ng_next = grouphead.gr;
grouphead.gr = grp;
pos++;
gpos = strsep(&pos, ")");
#ifdef DEBUG
fields = 0;
#endif
for (strpos = 0; strpos < 3; strpos++) {
if ((spos = strsep(&gpos, ","))) {
#ifdef DEBUG
fields++;
#endif
while (*spos == ' ' || *spos == '\t')
spos++;
if ((epos = strpbrk(spos, " \t"))) {
*epos = '\0';
len = epos - spos;
} else
len = strlen(spos);
if (len > 0) {
grp->ng_str[strpos] = (char *)
malloc(len + 1);
bcopy(spos, grp->ng_str[strpos],
len + 1);
}
} else {
grp->ng_str[strpos] = NULL;
}
}
#ifdef DEBUG
if (fields < 3)
fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
grp->ng_str[NG_USER] == NULL ? "" : ",",
grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
grp->ng_str[NG_DOM] == NULL ? "" : ",",
grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
lp->l_groupname);
#endif
} else {
spos = strsep(&pos, ", \t");
if (parse_netgrp(spos))
continue;
}
if (pos == NULL)
break;
while (*pos == ' ' || *pos == ',' || *pos == '\t')
pos++;
}
return (0);
}
static struct linelist *
read_for_group(const char *group)
{
char *pos, *spos, *linep = NULL, *olinep = NULL;
int len, olen;
int cont;
struct linelist *lp;
char line[LINSIZ + 2];
#ifdef YP
char *result;
int resultlen;
while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
if (_netgr_yp_enabled) {
if(!_netgr_yp_domain)
if(yp_get_default_domain(&_netgr_yp_domain))
continue;
if (yp_match(_netgr_yp_domain, "netgroup", group,
strlen(group), &result, &resultlen)) {
free(result);
if (_use_only_yp)
return (NULL);
else {
_netgr_yp_enabled = 0;
continue;
}
}
snprintf(line, LINSIZ, "%s %s", group, result);
free(result);
}
#else
while (fgets(line, LINSIZ, netf) != NULL) {
#endif
pos = (char *)&line;
#ifdef YP
if (*pos == '+') {
_netgr_yp_enabled = 1;
continue;
}
#endif
if (*pos == '#')
continue;
while (*pos == ' ' || *pos == '\t')
pos++;
spos = pos;
while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
*pos != '\0')
pos++;
len = pos - spos;
while (*pos == ' ' || *pos == '\t')
pos++;
if (*pos != '\n' && *pos != '\0') {
lp = (struct linelist *)malloc(sizeof (*lp));
lp->l_parsed = 0;
lp->l_groupname = (char *)malloc(len + 1);
bcopy(spos, lp->l_groupname, len);
*(lp->l_groupname + len) = '\0';
len = strlen(pos);
olen = 0;
do {
if (*(pos + len - 1) == '\n')
len--;
if (*(pos + len - 1) == '\\') {
len--;
cont = 1;
} else
cont = 0;
if (len > 0) {
linep = (char *)malloc(olen + len + 1);
if (olen > 0) {
bcopy(olinep, linep, olen);
free(olinep);
}
bcopy(pos, linep + olen, len);
olen += len;
*(linep + olen) = '\0';
olinep = linep;
}
if (cont) {
if (fgets(line, LINSIZ, netf)) {
pos = line;
len = strlen(pos);
} else
cont = 0;
}
} while (cont);
lp->l_line = linep;
lp->l_next = linehead;
linehead = lp;
if (!strcmp(lp->l_groupname, group))
return (lp);
}
}
#ifdef YP
rewind(netf);
#endif
return (NULL);
}