Subject: netgroup implementation
To: None <current-users@sun-lamp.cs.berkeley.edu>
From: Christos Zoulas <christos@deshaw.com>
List: current-users
Date: 03/11/1994 14:25:58
I have just finished an implementation of SunOS style netgroups.
I have appended a shar archive of the source and a README file
describing what is done, what needs to be done and how to install
it.

Feed-bug and back reports appreciated.

Enjoy,

christos

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README lib include netgroup_mkdb test lib/getnetgrent.c
#   lib/rcmd.c include/netgroup.h netgroup_mkdb/Makefile
#   netgroup_mkdb/netgroup_mkdb.8 netgroup_mkdb/netgroup_mkdb.c
#   netgroup_mkdb/str.c netgroup_mkdb/str.h netgroup_mkdb/util.c
#   netgroup_mkdb/util.h test/innetgr.c test/netgroup.c
# Wrapped by christos@prefect on Fri Mar 11 14:19:40 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(894 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
XThis is an implementantion of SunOS style netgroups. 
XNote that checking of the netgroup file is stricter than the SunOS one.
XI.e. duplicate netgroups or unreferenced names are errors.
X
XDone:
X
X    - all the functions in the netgroup interface:
X
X	getnetgrent()
X	setnetgrent()
X	endnetgrent()
X	innetgr()
X
X    - a netgroup_mkdb program to generate db(3) format netgroup databases
X
X    - changes to rcmd.c to parse netgroups
X
X
XMissing/Unimplemented:
X
X    - man pages:
X
X	netgroup.5
X	getnetgrent.3
X
X    - src changes:
X	mount, getpwent, getgrent.
X
X
XYou need to install netgroup.h in /usr/src/include and /usr/include.
XYou need to replace rcmd.c and install getnetgrent.c in /usr/src/lib/libc/net
XYou need to install the netgroup_mkdb program in /usr/src/usr.sbin
X
XAnd of course fix all the Makefiles affected.
X
XI am using this code on my machine, so if you find any bugs please let me
Xknow.
X
Xchristos
END_OF_FILE
if test 894 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test ! -d 'lib' ; then
    echo shar: Creating directory \"'lib'\"
    mkdir 'lib'
fi
if test ! -d 'include' ; then
    echo shar: Creating directory \"'include'\"
    mkdir 'include'
fi
if test ! -d 'netgroup_mkdb' ; then
    echo shar: Creating directory \"'netgroup_mkdb'\"
    mkdir 'netgroup_mkdb'
fi
if test ! -d 'test' ; then
    echo shar: Creating directory \"'test'\"
    mkdir 'test'
fi
if test -f 'lib/getnetgrent.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lib/getnetgrent.c'\"
else
echo shar: Extracting \"'lib/getnetgrent.c'\" \(13020 characters\)
sed "s/^X//" >'lib/getnetgrent.c' <<'END_OF_FILE'
X/*
X * getnetgrent.c:
X */
X#include <stdio.h>
X#include <netgroup.h>
X#include <string.h>
X#include <fcntl.h>
X#include <err.h>
X#include <ctype.h>
X#include <stdlib.h>
X#include <db.h>
X
X#define ISSPACE(p)	(isspace((unsigned char) (p)) || (p) == '\n')
X
Xstatic const char _ngoomem[] = "netgroup: %m";
Xstatic struct netgroup *_nghead, *_nglist;
Xstatic DB *_ng_db;
X
Xstruct stringlist;
X
Xstatic void              downcase	__P((char *));
Xstatic char 		*getstring	__P((char **, int));
Xstatic struct netgroup  *getnetgroup	__P((char **));
Xstatic int		 lookup		__P((const char *, char *, char **,
X					     int));
Xstatic void 		 addgroup	__P((char *, struct stringlist *,
X					     char *));
Xstatic int		 in_check	__P((const char *, const char *,
X					     const char *, struct netgroup *));
Xstatic int		 in_find	__P((char *, struct stringlist *,
X					     char *, const char *,
X					     const char *, const char *));
Xstatic char		*in_lookup1	__P((const char *, const char *,
X					     const char *, int));
Xstatic int		 in_lookup	__P((const char *, const char *,
X					     const char *, const char *, int));
X
X/*
X * Simple string list
X */
Xstruct stringlist {
X    char **sl_str;
X    size_t sl_max;
X    size_t sl_cur;
X} stringlist;
X
X
X/* _ng_sl_init():
X *	Initialize a string list
X */
Xstruct stringlist *
X_ng_sl_init()
X{
X    struct stringlist *sl = malloc(sizeof(struct stringlist));
X    sl->sl_cur = 0;
X    sl->sl_max = 20;
X    sl->sl_str = malloc(sl->sl_max * sizeof(char *));
X    if (sl->sl_str == NULL)
X	err(1, _ngoomem);
X    return sl;
X}
X
X
X/* _ng_sl_add():
X *	Add an item to the string list
X */
Xvoid
X_ng_sl_add(sl, name)
X    struct stringlist *sl;
X    char *name;
X{
X    if (sl->sl_cur == sl->sl_max - 1) {
X	sl->sl_max += 20;
X	sl->sl_str = realloc(sl->sl_str, sl->sl_max * sizeof(char *));
X    }
X    sl->sl_str[sl->sl_cur++] = name;
X}
X
X
X/* _ng_sl_free():
X *	Free a stringlist
X */
Xvoid
X_ng_sl_free(sl, all)
X    struct stringlist *sl;
X    int all;
X{
X    size_t i;
X    if (all)
X	for (i = 0; i < sl->sl_cur; i++)
X	    free(sl->sl_str[i]);
X    free(sl->sl_str);
X    free(sl);
X} 
X
X
X/* sl_find():
X *	Find a name in the string list
X */
Xchar *
X_ng_sl_find(sl, name)
X    struct stringlist *sl;
X    char *name;
X{
X    size_t i; 
X    for (i = 0; i < sl->sl_cur; i++)
X	if (strcmp(sl->sl_str[i], name) == 0)
X	    return sl->sl_str[i];
X
X    return NULL;
X}
X
X
X/* downcase():
X *	Make a string low case
X */
Xstatic void
Xdowncase(s)
X    char *s;
X{
X    for (;*s; s++)
X	*s = isupper((unsigned char) *s) ? tolower((unsigned char) *s) : *s;
X}
X
X
X/* getstring():
X *	Get a string delimited by the character, skipping leading and
X *	trailing blanks and advancing the pointer
X */
Xstatic char *
Xgetstring(pp, del)
X    char **pp;
X    int	   del;  
X{
X    char *sp, *ep, *dp;
X
X    /* skip leading blanks */
X    for (sp = *pp; *sp && ISSPACE(*sp); sp++)
X	continue;
X
X    /* accumulate till delimiter or space */
X    for (ep = sp; *ep && *ep != del && !ISSPACE(*ep); ep++)
X	continue;
X
X    /* hunt for the delimiter */
X    for (dp = ep; *dp && *dp != del && ISSPACE(*dp); dp++)
X	continue;
X
X    if (*dp != del) 
X	return NULL;
X
X    *pp = ++dp;
X
X    del = (ep - sp) + 1;
X    dp = malloc(del);
X    if (dp == NULL)
X	err(1, _ngoomem);
X    memcpy(dp, sp, del);
X    dp[del-1] = '\0';
X
X    return dp;
X}
X
X
X/* getnetgroup():
X *	Parse a netgroup, and advance the pointer
X */
Xstatic struct netgroup *
Xgetnetgroup(pp)
X    char **pp;
X{
X    struct netgroup *ng = malloc(sizeof(struct netgroup));
X    if (ng == NULL)
X	err(1, _ngoomem);
X
X    (*pp)++;	/* skip '(' */
X    if ((ng->ng_host = getstring(pp, ',')) == NULL)
X	goto badhost;
X
X    if ((ng->ng_user = getstring(pp, ',')) == NULL)
X	goto baduser;
X
X    if ((ng->ng_domain = getstring(pp, ')')) == NULL)
X	goto baddomain;
X    
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "netgroup(%s,%s,%s)\n", ng->ng_host, ng->ng_user,
X		   ng->ng_domain);
X#endif
X    downcase(ng->ng_host);
X    downcase(ng->ng_user);
X    downcase(ng->ng_domain);
X    return ng;
X
Xbaddomain:
X    free(ng->ng_user);
Xbaduser:
X    free(ng->ng_host);
Xbadhost:
X    free(ng);
X    return NULL;
X}
X
X
X/* lookup():
X *	Find the given key in the database or yp, and return its value
X *	in *line; returns 1 if key was found, 0 otherwise
X */
Xstatic int
Xlookup(ypdom, name, line, bywhat)
X    const char *ypdom;
X    char *name;
X    char **line;
X    int  bywhat;
X{
X#ifdef YP
X    int i;
X    char *map = NULL;
X#endif
X
X    if (_ng_db) {
X	DBT	key, data;
X	char	*ks;
X	size_t	len = strlen(name) + 2;
X	ks = malloc(len);
X	ks[0] = bywhat;
X	memcpy(&ks[1], name, len - 1);
X
X	key.data = (u_char *) ks;
X	key.size = len;
X
X	switch ((_ng_db->get)(_ng_db, &key, &data, 0)) {
X	case 0:
X	    free(ks);
X	    *line = strdup(data.data);
X	    if (*line == NULL)
X		err(1, _ngoomem);
X	    return 1;
X
X	case 1:
X	    break;
X
X	case -1:
X	    warn("netgroup: db get");
X	    break;
X	}
X	free(ks);
X    }
X
X#ifdef YP
X    switch (bywhat) {
X    case _NG_KEYBYNAME:
X	map = "netgroup";
X	break;
X
X    case _NG_KEYBYUSER:
X	map = "netgroup.byuser";
X	break;
X
X    case _NG_KEYBYHOST:
X	map = "netgroup.byhost";
X	break;
X
X    default:
X	abort();
X	break;
X    }
X	
X	
X    if (ypdom && yp_match(ypdom, map, name, strlen(name), line, &i) == 0)
X	return 1;
X#endif
X
X    return 0;
X}
X
X
X/* _ng_parse():
X *	Parse a line and return:
X *	_NG_ERROR: Syntax Error
X *	_NG_NONE:  line was empty or a comment
X *	_NG_GROUP: line had a netgroup definition, returned in ng
X *	_NG_NAME:  line had a netgroup name, returned in name
X *
X * Public since used by netgroup_mkdb
X */
Xint
X_ng_parse(p, name, ng)
X    char **p;
X    char **name;
X    struct netgroup **ng;
X{
X    while (**p) {
X	if (**p == '#')
X	    /* comment */
X	    return _NG_NONE;
X
X	while (**p && ISSPACE(**p))
X	    /* skipblank */
X	    (*p)++;
X
X	if (**p == '(')  {
X	    if ((*ng = getnetgroup(p)) == NULL) {
X		warnx("netgroup: Syntax error `%s'", *p);
X		return _NG_ERROR;
X	    }
X	    return _NG_GROUP;
X	}
X	else {
X	    char *np;
X	    for (np = *p; **p && !ISSPACE(**p); (*p)++)
X		continue;
X	    if (np != *p) {
X		int i = (*p - np) + 1;
X		*name = malloc(i);
X		if (*name == NULL)
X		    err(1, _ngoomem);
X		memcpy(*name, np, i);
X		downcase(*name);
X		(*name)[i - 1] = '\0';
X		return _NG_NAME;
X	    }
X	}
X    }
X    return _NG_NONE;
X}
X
X
X/* addgroup():
X *	Recursively add all the members of the netgroup to this group
X */
Xstatic void
Xaddgroup(ypdom, sl, grp)
X    char *ypdom;
X    struct stringlist *sl;
X    char *grp;
X{
X    char *line, *p;
X
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "addgroup(%s)\n", grp);
X#endif
X    /* check for cycles */
X    if (_ng_sl_find(sl, grp) != NULL) {
X	warnx("netgroup: Cycle in group `%s'", grp);
X	return;
X    }
X    _ng_sl_add(sl, grp);
X
X    /* Lookup this netgroup */
X    if (!lookup(ypdom, grp, &line, _NG_KEYBYNAME))
X	return;
X
X    p = line;
X
X    for (;;) {
X	struct netgroup *ng;
X	char *name;
X	switch (_ng_parse(&p, &name, &ng)) {
X	case _NG_NONE:
X	    /* Done with the line */
X	    free(line);
X	    return;
X
X	case _NG_GROUP:
X	    /* new netgroup */
X	    /* add to the list */
X	    ng->ng_next = _nglist;
X	    _nglist = ng;
X	    break;
X
X	case _NG_NAME:
X	    /* netgroup name */
X	    addgroup(ypdom, sl, name);
X	    break;
X
X	case _NG_ERROR:
X	    return;
X
X	default:
X	    abort();
X	    return;
X	}
X    }
X}
X
X
X/* in_check():
X *	Compare the spec with the netgroup
X */
Xstatic int
Xin_check(host, user, domain, ng)
X    const char *host;
X    const char *user;
X    const char *domain;
X    struct netgroup *ng;
X{
X    if (host != NULL && ng->ng_host[0] != '\0' 
X	&& strcmp(ng->ng_host, host) != 0)
X	return 0;
X
X    if (user != NULL && ng->ng_user[0] != '\0' 
X	&& strcmp(ng->ng_user, user) != 0)
X	return 0;
X
X    if (domain != NULL && ng->ng_domain[0] != '\0' 
X	&& strcmp(ng->ng_domain, domain) != 0)
X	return 0;
X
X    return 1;
X}
X
X
X/* in_find():
X *	Find a match for the host, user, domain spec
X */
Xstatic int
Xin_find(ypdom, sl, grp, host, user, domain)
X    char *ypdom;
X    struct stringlist *sl;
X    char *grp;
X    const char *host;
X    const char *user;
X    const char *domain;
X{
X    char *line, *p;
X    int i;
X
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "in_find(%s)\n", grp);
X#endif
X    /* check for cycles */
X    if (_ng_sl_find(sl, grp) != NULL) {
X	warnx("netgroup: Cycle in group `%s'", grp);
X	return 0;
X    }
X    _ng_sl_add(sl, grp);
X
X    /* Lookup this netgroup */
X    if (!lookup(ypdom, grp, &line, _NG_KEYBYNAME))
X	return 0;
X
X    p = line;
X
X    for (;;) {
X	struct netgroup *ng;
X	char *name;
X	switch (_ng_parse(&p, &name, &ng)) {
X	case _NG_NONE:
X	    /* Done with the line */
X	    free(line);
X	    return 0;
X
X	case _NG_GROUP:
X	    /* new netgroup */
X	    i = in_check(host, user, domain, ng);
X	    free(ng->ng_host);
X	    free(ng->ng_user);
X	    free(ng->ng_domain);
X	    free(ng);
X	    if (i) {
X		free(line);
X		return 1;
X	    }
X	    break;
X
X	case _NG_NAME:
X	    /* netgroup name */
X	    if (in_find(ypdom, sl, name, host, user, domain)) {
X		free(line);
X		return 1;
X	    }
X	    break;
X
X	case _NG_ERROR:
X	    free(line);
X	    return 0;
X
X	default:
X	    abort();
X	    return 0;
X	}
X    }
X}
X		
X
X/* _ng_makekey():
X *	Make a key from the two names given.
X *	The key is of the form <name1>.<name2>
X *	Names strings are replaced with * if they are empty;
X */
Xchar *
X_ng_makekey(s1, s2, len)
X    const char *s1, *s2;
X    size_t len;
X{
X    static const char star[] = "*";
X#define STAR(s) (((s) == NULL || *(s) == '\0') ? star : s)
X    char *buf = malloc(len);
X    if (buf == NULL)
X	err(1, _ngoomem);
X    snprintf(buf, len, "%s.%s", STAR(s1), STAR(s2));
X    return buf;
X}
X	     
X
X/* in_lookup1():
X *	Fast lookup for a key in the appropriate map
X */
Xstatic char *
Xin_lookup1(ypdom, key, domain, map)
X    const char *ypdom;
X    const char *key;
X    const char *domain;
X    int map;
X{
X    char *line;
X    size_t len;
X    char *ptr;
X    int res;
X
X    len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
X    ptr = _ng_makekey(key, domain, len);
X    res = lookup(ypdom, ptr, &line, map);
X    free(ptr);
X    return res ? line : NULL;
X}
X
X
X/* in_lookup():
X *	Fast lookup for a key in the appropriate map
X */
Xstatic int
Xin_lookup(ypdom, group, key, domain, map)
X    const char *ypdom;
X    const char *group;
X    const char *key;
X    const char *domain;
X    int map;
X{
X    size_t len;
X    char *line, *ptr;
X    /*
X     * Look in group.domain group.* *.domain *.*
X     */
X    if ((line = in_lookup1(ypdom, key, domain, map)) == NULL) 
X	if ((line = in_lookup1(ypdom, NULL, domain, map)) == NULL)
X	    if ((line = in_lookup1(ypdom, key, NULL, map)) == NULL)
X		if ((line = in_lookup1(ypdom, NULL, NULL, map)) == NULL)
X		    return 0;
X
X    len = strlen(group);
X
X    for(ptr = line; (ptr = strstr(ptr, group)) != NULL;)
X	/* Make sure we did not find a substring */
X	if ((ptr != line && ptr[-1] != ',') ||
X	    (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
X	    ptr++;
X	else {
X	    free(line);
X	    return 1;
X	}
X
X    free(line);
X    return 0;
X}
X
X
Xvoid
Xendnetgrent()
X{
X    for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
X	_nghead = _nglist->ng_next;
X	free(_nglist->ng_host);
X	free(_nglist->ng_user);
X	free(_nglist->ng_domain);
X	free(_nglist);
X    }
X
X    if (_ng_db) {
X	(void)(_ng_db->close)(_ng_db);
X	_ng_db = NULL;
X    }
X}
X
X    
Xvoid
Xsetnetgrent(ng)
X    const char *ng;
X{
X    struct stringlist *sl = _ng_sl_init();
X#ifdef YP
X    char *line;
X#endif
X    char *ypdom = NULL;
X
X    if (_nghead != NULL)
X	endnetgrent();
X
X    if (_ng_db == NULL)
X	_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
X
X#ifdef YP
X    /* 
X     * We use yp if there is a "+" in the netgroup file,
X     * or if there is no netgroup file at all
X     */
X    if (_ng_db == NULL || lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0)
X	yp_get_default_domain(&ypdom);
X    else
X	free(line);
X#endif
X    addgroup(ypdom, sl, strdup(ng));
X    _nghead = _nglist;
X    _ng_sl_free(sl, 1);
X}
X
X
Xint
Xgetnetgrent(host, user, domain)
X    const char **host;
X    const char **user;
X    const char **domain;
X{
X    if (_nglist) {
X	*host = _nglist->ng_host;
X	*user = _nglist->ng_user;
X	*domain = _nglist->ng_domain;
X	_nglist = _nglist->ng_next;
X	return 1;
X    }
X    else
X	return 0;
X}
X
X
Xint
Xinnetgr(grp, host, user, domain)
X    const char *grp, *host, *user, *domain;
X{
X    char *ypdom = NULL;
X#ifdef YP
X    char *line;
X#endif
X    int found;
X
X    if (_ng_db == NULL)
X	_ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
X
X#ifdef YP
X    /* 
X     * We use yp if there is a "+" in the netgroup file,
X     * or if there is no netgroup file at all
X     */
X    if (_ng_db == NULL) 
X	yp_get_default_domain(&ypdom);
X    else if (lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) {
X	yp_get_default_domain(&ypdom);
X	free(line);
X    }
X#endif
X
X    /* Try the fast lookup first */
X    if (domain != NULL) {
X	if (host != NULL && user == NULL) {
X	    if (in_lookup(ypdom, grp, host, domain, _NG_KEYBYHOST))
X		return 1;
X	}
X	else if (host == NULL && user != NULL) {
X	    if (in_lookup(ypdom, grp, user, domain, _NG_KEYBYUSER))
X		return 1;
X	}
X    }
X
X    {
X	struct stringlist *sl = _ng_sl_init();
X	/* Too bad need the slow recursive way */
X	found = in_find(ypdom, sl, strdup(grp), host, user, domain);
X	_ng_sl_free(sl, 1);
X    }
X    return found;
X}
END_OF_FILE
if test 13020 -ne `wc -c <'lib/getnetgrent.c'`; then
    echo shar: \"'lib/getnetgrent.c'\" unpacked with wrong size!
fi
# end of 'lib/getnetgrent.c'
fi
if test -f 'lib/rcmd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lib/rcmd.c'\"
else
echo shar: Extracting \"'lib/rcmd.c'\" \(10221 characters\)
sed "s/^X//" >'lib/rcmd.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1983 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *	This product includes software developed by the University of
X *	California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
X/*static char *sccsid = "from: @(#)rcmd.c	5.24 (Berkeley) 2/24/91";*/
Xstatic char *rcsid = "$Id: rcmd.c,v 1.1 1994/03/11 19:05:17 christos Exp $";
X#endif /* LIBC_SCCS and not lint */
X
X#include <sys/param.h>
X#include <sys/socket.h>
X#include <sys/stat.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <signal.h>
X#include <fcntl.h>
X#include <netdb.h>
X#include <pwd.h>
X#include <errno.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <unistd.h>
X#include <string.h>
X
Xrcmd(ahost, rport, locuser, remuser, cmd, fd2p)
X	char **ahost;
X	u_short rport;
X	const char *locuser, *remuser, *cmd;
X	int *fd2p;
X{
X	int s, timo = 1, pid;
X	long oldmask;
X	struct sockaddr_in sin, from;
X	char c;
X	int lport = IPPORT_RESERVED - 1;
X	struct hostent *hp;
X	fd_set reads;
X
X	pid = getpid();
X	hp = gethostbyname(*ahost);
X	if (hp == 0) {
X		herror(*ahost);
X		return (-1);
X	}
X	*ahost = hp->h_name;
X	oldmask = sigblock(sigmask(SIGURG));
X	for (;;) {
X		s = rresvport(&lport);
X		if (s < 0) {
X			if (errno == EAGAIN)
X				fprintf(stderr, "socket: All ports in use\n");
X			else
X				perror("rcmd: socket");
X			sigsetmask(oldmask);
X			return (-1);
X		}
X		fcntl(s, F_SETOWN, pid);
X		bzero((char *)&sin, sizeof sin);
X		sin.sin_family = hp->h_addrtype;
X		bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
X		sin.sin_port = rport;
X		if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
X			break;
X		(void) close(s);
X		if (errno == EADDRINUSE) {
X			lport--;
X			continue;
X		}
X		if (errno == ECONNREFUSED && timo <= 16) {
X			sleep(timo);
X			timo *= 2;
X			continue;
X		}
X		if (hp->h_addr_list[1] != NULL) {
X			int oerrno = errno;
X
X			fprintf(stderr,
X			    "connect to address %s: ", inet_ntoa(sin.sin_addr));
X			errno = oerrno;
X			perror(0);
X			hp->h_addr_list++;
X			bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
X			    hp->h_length);
X			fprintf(stderr, "Trying %s...\n",
X				inet_ntoa(sin.sin_addr));
X			continue;
X		}
X		perror(hp->h_name);
X		sigsetmask(oldmask);
X		return (-1);
X	}
X	lport--;
X	if (fd2p == 0) {
X		write(s, "", 1);
X		lport = 0;
X	} else {
X		char num[8];
X		int s2 = rresvport(&lport), s3;
X		int len = sizeof (from);
X
X		if (s2 < 0)
X			goto bad;
X		listen(s2, 1);
X		(void) sprintf(num, "%d", lport);
X		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
X			perror("write: setting up stderr");
X			(void) close(s2);
X			goto bad;
X		}
X		FD_ZERO(&reads);
X		FD_SET(s, &reads);
X		FD_SET(s2, &reads);
X		errno = 0;
X		if (select(32, &reads, 0, 0, 0) < 1 ||
X		    !FD_ISSET(s2, &reads)) {
X			if (errno != 0)
X				perror("select: setting up stderr");
X			else
X			    fprintf(stderr,
X				"select: protocol failure in circuit setup.\n");
X			(void) close(s2);
X			goto bad;
X		}
X		s3 = accept(s2, (struct sockaddr *)&from, &len);
X		(void) close(s2);
X		if (s3 < 0) {
X			perror("accept");
X			lport = 0;
X			goto bad;
X		}
X		*fd2p = s3;
X		from.sin_port = ntohs((u_short)from.sin_port);
X		if (from.sin_family != AF_INET ||
X		    from.sin_port >= IPPORT_RESERVED ||
X		    from.sin_port < IPPORT_RESERVED / 2) {
X			fprintf(stderr,
X			    "socket: protocol failure in circuit setup.\n");
X			goto bad2;
X		}
X	}
X	(void) write(s, locuser, strlen(locuser)+1);
X	(void) write(s, remuser, strlen(remuser)+1);
X	(void) write(s, cmd, strlen(cmd)+1);
X	if (read(s, &c, 1) != 1) {
X		perror(*ahost);
X		goto bad2;
X	}
X	if (c != 0) {
X		while (read(s, &c, 1) == 1) {
X			(void) write(2, &c, 1);
X			if (c == '\n')
X				break;
X		}
X		goto bad2;
X	}
X	sigsetmask(oldmask);
X	return (s);
Xbad2:
X	if (lport)
X		(void) close(*fd2p);
Xbad:
X	(void) close(s);
X	sigsetmask(oldmask);
X	return (-1);
X}
X
Xrresvport(alport)
X	int *alport;
X{
X	struct sockaddr_in sin;
X	int s;
X
X	sin.sin_family = AF_INET;
X	sin.sin_addr.s_addr = INADDR_ANY;
X	s = socket(AF_INET, SOCK_STREAM, 0);
X	if (s < 0)
X		return (-1);
X	for (;;) {
X		sin.sin_port = htons((u_short)*alport);
X		if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
X			return (s);
X		if (errno != EADDRINUSE) {
X			(void) close(s);
X			return (-1);
X		}
X		(*alport)--;
X		if (*alport == IPPORT_RESERVED/2) {
X			(void) close(s);
X			errno = EAGAIN;		/* close */
X			return (-1);
X		}
X	}
X}
X
Xint	_check_rhosts_file = 1;
X
Xruserok(rhost, superuser, ruser, luser)
X	const char *rhost, *ruser, *luser;
X	int superuser;
X{
X	FILE *hostf;
X	char fhost[MAXHOSTNAMELEN];
X	int first = 1;
X	register char *sp, *p;
X	int baselen = -1;
X	char domain[MAXHOSTNAMELEN];
X
X#ifdef YP
X	getdomainname(domain, sizeof(domain));
X#endif
X
X	sp = (char *)rhost;
X	p = fhost;
X	while (*sp) {
X		if (*sp == '.') {
X			if (baselen == -1)
X				baselen = sp - rhost;
X			*p++ = *sp++;
X		} else {
X			*p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
X		}
X	}
X	*p = '\0';
X	hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r");
Xagain:
X	if (hostf) {
X		if (!_validuser(hostf, fhost, luser, ruser, baselen, domain)) {
X			(void) fclose(hostf);
X			return(0);
X		}
X		(void) fclose(hostf);
X	}
X	if (first == 1 && (_check_rhosts_file || superuser)) {
X		struct stat sbuf;
X		struct passwd *pwd;
X		char pbuf[MAXPATHLEN];
X
X		first = 0;
X		if ((pwd = getpwnam(luser)) == NULL)
X			return(-1);
X		(void)strcpy(pbuf, pwd->pw_dir);
X		(void)strcat(pbuf, "/.rhosts");
X		if ((hostf = fopen(pbuf, "r")) == NULL)
X			return(-1);
X		/*
X		 * if owned by someone other than user or root or if
X		 * writeable by anyone but the owner, quit
X		 */
X		if (fstat(fileno(hostf), &sbuf) ||
X		    sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
X		    sbuf.st_mode&022) {
X			fclose(hostf);
X			return(-1);
X		}
X		goto again;
X	}
X	return (-1);
X}
X
X/* don't make static, used by lpd(8) */
X_validuser(hostf, rhost, luser, ruser, baselen, domain)
X	char *rhost, *luser, *ruser;
X	FILE *hostf;
X	int baselen;
X	char *domain;
X{
X	register char *p;
X	char *auser, ahost[MAXHOSTNAMELEN];
X	static int _checkhost();
X	int hostok, userok;	/* -1 = deny, 0 = no match, 1 = accept */
X
X	while (fgets(ahost, sizeof (ahost), hostf)) {
X		p = ahost;
X		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
X			*p = isupper(*p) ? tolower(*p) : *p;
X			p++;
X		}
X		if (*p == ' ' || *p == '\t') {
X			*p++ = '\0';
X			while (*p == ' ' || *p == '\t')
X				p++;
X			auser = p;
X			while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
X				p++;
X		} else
X			auser = p;
X		*p = '\0';
X		auser = *auser ? auser : luser;
X#ifdef YP
X		if (ahost[0] == '+')
X		    switch (ahost[1]) {
X		    case '\0':
X			hostok = 1;
X			break;
X
X		    case '@':
X			hostok = innetgr(&ahost[2], rhost, NULL, domain);
X			break;
X
X		    default:
X			hostok = _checkhost(rhost, &ahost[1], baselen);
X			break;
X		    }
X		else if (ahost[0] == '-')
X		    switch (ahost[1]) {
X		    case '\0':
X			hostok = -1;
X			break;
X
X		    case '@':
X			hostok = -innetgr(rhost, &ahost[2], NULL, baselen);
X			break;
X
X		    default:
X			hostok = -_checkhost(rhost, &ahost[1], baselen);
X			break;
X		    }
X		else
X#endif
X		    hostok = _checkhost(rhost, ahost, baselen);
X
X#ifdef YP
X		if (auser[0] == '+')
X		    switch (auser[1]) {
X		    case '\0':
X			userok = 1;
X			break;
X
X		    case '@':
X			userok = innetgr(ruser, NULL, &auser[2], 0);
X			break;
X
X		    default:
X			userok = strcmp(ruser, &auser[1]) == 0;
X			break;
X		    }
X		else if (auser[0] == '-')
X		    switch (auser[1]) {
X		    case '\0':
X			userok = -1;
X			break;
X
X		    case '@':
X			userok = -innetgr(ruser, NULL, &auser[2], 0);
X			break;
X
X		    default:
X			userok = -(strcmp(ruser, &auser[1]) == 0);
X			break;
X		    }
X		else
X#endif
X		    userok = strcmp(ruser, auser) == 0;
X
X		/* Check if one component did not match */
X		if (hostok == 0 || userok == 0)
X		    continue;
X
X		/* Check if we got a forbidden pair */
X		if (userok == -1 || hostok == -1)
X		    return -1;
X
X		/* Check if we got a valid pair */
X		if (hostok == 1 && userok == 1)
X		    return 0;
X	}
X	return (-1);
X}
X
Xstatic int
X_checkhost(rhost, lhost, len)
X	char *rhost, *lhost;
X	int len;
X{
X	static char ldomain[MAXHOSTNAMELEN + 1];
X	static char *domainp = NULL;
X	static int nodomain = 0;
X	register char *cp;
X
X	if (len == -1)
X		return(!strcmp(rhost, lhost));
X	if (strncmp(rhost, lhost, len))
X		return(0);
X	if (!strcmp(rhost, lhost))
X		return(1);
X	if (*(lhost + len) != '\0')
X		return(0);
X	if (nodomain)
X		return(0);
X	if (!domainp) {
X		if (gethostname(ldomain, sizeof(ldomain)) == -1) {
X			nodomain = 1;
X			return(0);
X		}
X		ldomain[MAXHOSTNAMELEN] = NULL;
X		if ((domainp = index(ldomain, '.')) == (char *)NULL) {
X			nodomain = 1;
X			return(0);
X		}
X		for (cp = ++domainp; *cp; ++cp)
X			if (isupper(*cp))
X				*cp = tolower(*cp);
X	}
X	return(!strcmp(domainp, rhost + len +1));
X}
END_OF_FILE
if test 10221 -ne `wc -c <'lib/rcmd.c'`; then
    echo shar: \"'lib/rcmd.c'\" unpacked with wrong size!
fi
# end of 'lib/rcmd.c'
fi
if test -f 'include/netgroup.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'include/netgroup.h'\"
else
echo shar: Extracting \"'include/netgroup.h'\" \(939 characters\)
sed "s/^X//" >'include/netgroup.h' <<'END_OF_FILE'
X#ifndef _NETGROUP_H_
X#define	_NETGROUP_H_
X
X#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
X
X#define	_PATH_NETGROUP		"/etc/netgroup"
X
X#define	_PATH_NETGROUP_DB	"/etc/netgroup.db"
X
X#define	_PATH_NETGROUP_MKDB	"/usr/sbin/netgroup_mkdb"
X
X#define	_NG_KEYBYNAME		'1'	/* stored by name */
X#define	_NG_KEYBYUSER		'2'	/* stored by user */
X#define	_NG_KEYBYHOST		'3'	/* stored by host */
X
X#define _NG_ERROR	-1
X#define _NG_NONE	 0
X#define _NG_NAME	 1
X#define _NG_GROUP	 2
X
Xstruct netgroup {
X	char		*ng_host;	/* host name */
X	char		*ng_user;	/* user name */
X	char		*ng_domain;	/* domain name */
X	struct netgroup	*ng_next;	/* thread */
X};
X
X#include <sys/cdefs.h>
X
X__BEGIN_DECLS
Xvoid	setnetgrent	__P((const char *));
Xint	getnetgrent	__P((const char **, const char **, const char **));
Xvoid	endnetgrent	__P((void));
Xint	innetgr		__P((const char *, const char *, const char *,
X			     const char *));
X__END_DECLS
X#endif
X
X#endif /* !_NETGROUP_H_ */
END_OF_FILE
if test 939 -ne `wc -c <'include/netgroup.h'`; then
    echo shar: \"'include/netgroup.h'\" unpacked with wrong size!
fi
# end of 'include/netgroup.h'
fi
if test -f 'netgroup_mkdb/Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/Makefile'\"
else
echo shar: Extracting \"'netgroup_mkdb/Makefile'\" \(203 characters\)
sed "s/^X//" >'netgroup_mkdb/Makefile' <<'END_OF_FILE'
X#	from: @(#)Makefile	5.1 (Berkeley) 3/8/91
X#	$Id: Makefile,v 1.1 1994/03/11 19:06:13 christos Exp $
X
XPROG=	netgroup_mkdb
XSRCS=	netgroup_mkdb.c util.c str.c
XMAN8=	netgroup_mkdb.0
X
X.include <bsd.prog.mk>
X
END_OF_FILE
if test 203 -ne `wc -c <'netgroup_mkdb/Makefile'`; then
    echo shar: \"'netgroup_mkdb/Makefile'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/Makefile'
fi
if test -f 'netgroup_mkdb/netgroup_mkdb.8' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/netgroup_mkdb.8'\"
else
echo shar: Extracting \"'netgroup_mkdb/netgroup_mkdb.8'\" \(869 characters\)
sed "s/^X//" >'netgroup_mkdb/netgroup_mkdb.8' <<'END_OF_FILE'
X.Dd February 3, 1994
X.Dt NETGROUP_MKDB 8 
X.Os
X.Sh NAME
X.Nm netgroup_mkdb 
X.Nd generate the netgroup databases
X.Sh SYNOPSIS
X.Nm netgroup_mkdb 
X.Op Fl o Ar database
X.Ar file
X.Sh DESCRIPTION
X.Nm Netgroup_mkdb
Xcreates
X.Xr db 3
Xstyle databases for the specified file.
XThese databases are then installed into 
X.Pa /etc/netgroup.db.
XThe file must be in the correct format (see
X.Xr netgroup 5 ).
X.Pp
XThe options are as follows:
X.Bl -tag -width indent
X.It Fl o Ar database
XPut the output database in the named file.
X.El
X.Pp
XThe databases are used by the C library netgroup routines (see
X.Xr getnetgrent 3 ).
X.Pp
X.Nm Netgroup_mkdb
Xexits zero on success, non-zero on failure.
X.Sh FILES
X.Bl -tag -width 24n -compact
X.It Pa /etc/netgroup.db
XThe current netgroup database
X.It Pa /etc/netgroup
XThe current netgroup file
X.El
X.Sh SEE ALSO
X.Xr db 3 ,
X.Xr getnetgrent 3 ,
X.Xr netgroup 5 
END_OF_FILE
if test 869 -ne `wc -c <'netgroup_mkdb/netgroup_mkdb.8'`; then
    echo shar: \"'netgroup_mkdb/netgroup_mkdb.8'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/netgroup_mkdb.8'
fi
if test -f 'netgroup_mkdb/netgroup_mkdb.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/netgroup_mkdb.c'\"
else
echo shar: Extracting \"'netgroup_mkdb/netgroup_mkdb.c'\" \(11609 characters\)
sed "s/^X//" >'netgroup_mkdb/netgroup_mkdb.c' <<'END_OF_FILE'
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdlib.h>
X#include <stddef.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include <db.h>
X#include <err.h>
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <netgroup.h>
X#include <assert.h>
X
X#include "str.h"
X#include "util.h"
X
X#define NEW(a)	(a *) emalloc(sizeof(a))
X	
Xstruct nentry {
X    int n_type;
X    size_t n_size;	/* Buffer size required for printing */
X    union {
X	char *_name;
X	struct netgroup *_group;
X    } n;
X#define n_name	n._name
X#define n_group n._group
X    struct nentry *n_next;
X};
X
X
Xstruct stringlist;
Xextern struct stringlist *_ng_sl_init	__P((void));
Xextern void _ng_sl_add		__P((struct stringlist *, char *));
Xextern void _ng_sl_free		__P((struct stringlist *, int));
Xextern char *_ng_sl_find	__P((struct stringlist *, char *));
X
Xextern char *_ng_makekey	__P((const char *, const char *, size_t));
Xextern int _ng_parse		__P((char **, char **, struct netgroup **));
X
Xstatic DB *ng_insert	__P((DB *, const char *));
Xstatic void ng_reventry	__P((DB *, DB *, struct nentry *, char *,
X			     size_t, struct stringlist *));
X
Xstatic void ng_print	__P((struct nentry *, struct string *));
Xstatic void ng_rprint	__P((DB *, struct string *));
Xstatic DB *ng_reverse	__P((DB *, size_t));
Xstatic DB *ng_load	__P((const char *));
Xstatic void ng_write	__P((DB *, DB *, int));
Xstatic void ng_rwrite	__P((DB *, DB *, int));
Xstatic void usage	__P((void));
X
X#ifdef DEBUG_NG
Xstatic void ng_dump	__P((DB *));
Xstatic void ng_rdump	__P((DB *));
X#endif /* DEBUG_NG */
X
Xstatic char *dbname = _PATH_NETGROUP_DB;
X
Xint
Xmain(argc, argv)
X    int argc;
X    char **argv;
X{
X    DB *db, *ndb, *hdb, *udb;
X    int ch;
X
X    while ((ch = getopt(argc, argv, "o:")) != EOF)
X	switch(ch) {
X	case 'o':
X	    dbname = optarg;
X	    break;
X
X	case '?':
X	default:
X	    usage();
X	}
X
X    argc -= optind;
X    argv += optind;
X
X    if (argc != 1)
X	usage();
X
X    /* Read and parse the netgroup file */
X    ndb = ng_load(*argv);
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "#### Database\n");
X    ng_dump(ndb);
X#endif
X
X    /* Reverse the database by host */
X    hdb = ng_reverse(ndb, offsetof(struct netgroup, ng_host));
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "#### Reverse by host\n");
X    ng_rdump(hdb);
X#endif
X
X    /* Reverse the database by user */
X    udb = ng_reverse(ndb, offsetof(struct netgroup, ng_user));
X#ifdef DEBUG_NG
X    (void) fprintf(stderr, "#### Reverse by user\n");
X    ng_rdump(udb);
X#endif
X
X    db = dbopen(dbname, O_RDWR|O_CREAT|O_EXCL, 
X		(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH), DB_HASH, NULL);
X    if (!db)
X	err(1, dbname);
X
X    ng_write(db, ndb, _NG_KEYBYNAME);
X    ng_rwrite(db, udb, _NG_KEYBYUSER);
X    ng_rwrite(db, hdb, _NG_KEYBYHOST);
X    (db->close)(db);
X    return 0;
X}
X
X
X/* ng_load():
X *	Load the netgroup database from a file
X */
Xstatic DB * 
Xng_load(fname)
X    const char *fname;
X{
X    FILE *fp;
X    DB *db;
X    char *buf;
X    size_t size;
X
X    /* Open the netgroup file */
X    if ((fp = fopen(fname, "r")) == NULL)
X	err(1, fname);
X
X    db = dbopen(NULL, O_RDWR|O_CREAT|O_EXCL, 0, DB_HASH, NULL);
X
X    if (db == NULL)
X	err(1, "dbopen");
X
X    while ((buf = getline(fp, &size)) != NULL) {
X	struct nentry *tail = NULL, *head = NULL;
X	char *p = buf;
X
X	while (p != NULL) {
X	    char *name;
X	    struct netgroup *ng;
X
X	    switch (_ng_parse(&p, &name, &ng)) {
X	    case _NG_NONE:
X		/* done with this one */
X		p = NULL;
X		free(buf);
X		if (head != NULL) {
X		    DBT data, key;
X		    key.data = (u_char *) head->n_name;
X		    key.size = strlen(head->n_name) + 1;
X		    data.data = (u_char *) &head;
X		    data.size = sizeof(&head);
X		    switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
X		    case 0:
X			break;
X
X		    case 1:
X			warnx("Duplicate entry netgroup `%s'\n", 
X			      head->n_name);
X			break;
X
X		    case -1:
X			err(1, "put");
X			break;
X
X		    default:
X			abort();
X			break;
X		    }
X		}
X		break;
X
X	    case _NG_NAME:
X		{
X		    struct nentry* e = NEW(struct nentry);
X		    e->n_type = _NG_NAME;
X		    e->n_name = name;
X		    e->n_next = NULL;
X		    e->n_size = size;
X		    if (tail == NULL)  {
X			head = tail = e;
X		    }
X		    else {
X			tail->n_next = e;
X			tail = e;
X		    }
X		}
X		break;
X
X	    case _NG_GROUP:
X		if (tail == NULL)
X		    errx(1, "no netgroup key");
X		else {
X		    struct nentry* e = NEW(struct nentry);
X
X		    e->n_type = _NG_GROUP;
X		    e->n_group = ng;
X		    e->n_next = NULL;
X		    e->n_size = size;
X		    tail->n_next = e;
X		    tail = e;
X		}
X		break;
X
X	    default:
X		abort();
X		break;
X	    }
X	}
X    }
X    (void) fclose(fp);
X    return db;
X}
X
X
X/* ng_insert():
X *	Insert named key into the database, 
X *	and return its associated string database
X */
Xstatic DB *
Xng_insert(db, name)
X    DB *db;
X    const char *name;
X{
X    DB *xdb = NULL;
X    DBT key, data;
X
X    key.data = (u_char *) name;
X    key.size = strlen(name) + 1;
X
X    switch ((db->get)(db, &key, &data, 0)) {
X    case 0:
X	xdb = *((DB **) data.data);
X	break;
X
X    case 1:
X	xdb = dbopen(NULL, O_RDWR|O_CREAT|O_EXCL, 0, DB_HASH, NULL);
X	if (xdb == NULL)
X	    err(1, "dbopen");
X
X	data.data = (u_char *) &xdb;
X	data.size = sizeof(&xdb);
X	switch ((db->put)(db, &key, &data, R_NOOVERWRITE)) {
X	case 0:
X	    break;
X
X	case -1:
X	    err(1, "db put `%s'", name);
X	    break;
X
X	case 1:
X	default:
X	    abort();
X	}
X	break;
X
X    case -1:
X	err(1, "db get `%s'", name);
X	break;
X
X    default:
X	abort();
X	break;
X    }
X
X    return xdb;
X}
X
X
X/* ng_reventry():
X *	Recursively add all the netgroups to the group entry.
X */
Xstatic void
Xng_reventry(db, udb, fe, name, s, ss)
X    DB *db, *udb;
X    struct nentry *fe;
X    char *name;
X    size_t s;
X    struct stringlist *ss;
X{
X    DBT key, data;
X    struct nentry *e;
X
X    if (_ng_sl_find(ss, name) != NULL) { 
X	warnx("Cycle in netgroup `%s'", name);
X	return;
X    }
X    _ng_sl_add(ss, name);
X
X    for (e = fe->n_next; e != NULL; e = e->n_next) {
X	switch (e->n_type) {
X	case _NG_GROUP:
X	    {
X		struct netgroup *ng = e->n_group;
X	        char *p = _ng_makekey(*((char **) (((char *) ng) + s)), 
X				      ng->ng_domain, e->n_size);
X		DB *xdb = ng_insert(udb, p);
X		key.data = (u_char *) name;
X		key.size = strlen(name) + 1;
X		data.data = NULL;
X		data.size = 0;
X		switch ((xdb->put)(xdb, &key, &data, R_NOOVERWRITE)) {
X		case 0:
X		case 1:
X		    break;
X
X		case -1:
X		    err(1, "db put `%s'", name);
X		    return;
X
X		default:
X		    abort();
X		    break;
X		}
X		free(p);
X	    }
X	    break;
X
X	case _NG_NAME:
X	    key.data = (u_char *) e->n_name;
X	    key.size = strlen(e->n_name) + 1;
X	    switch ((db->get)(db, &key, &data, 0)) {
X	    case 0:
X		fe = *((struct nentry **) data.data);
X		ng_reventry(db, udb, fe, name, s, ss);
X		break;
X
X	    case 1:
X		break;
X
X	    case -1:
X		err(1, "db get `%s'", e->n_name);
X		return;
X
X	    default:
X		abort();
X		return;
X	    }
X	    break;
X
X	default:
X	    abort();
X	    break;
X	}
X    }
X}
X
X
X/* ng_reverse():
X *	Reverse the database
X */
Xstatic DB *
Xng_reverse(db, s)
X    DB *db;
X    size_t s;
X{
X    int pos;
X    struct stringlist *sl;
X    DBT key, data;
X    DB *udb = dbopen(NULL, O_RDWR|O_CREAT|O_EXCL, 0, DB_HASH, NULL);
X
X    if (udb == NULL)
X	err(1, "dbopen");
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((db->seq)(db, &key, &data, pos)) {
X	case 0: 
X	    sl = _ng_sl_init();
X	    ng_reventry(db, udb, *((struct nentry **) data.data),
X			(char *) key.data, s, sl);
X	    _ng_sl_free(sl, 0);
X	    break;
X
X	case 1:
X	    return udb;
X
X	case -1:
X	    err(1, "seq");
X	    return udb;
X	}
X
X    return udb;
X}
X
X
X/* ng_print():
X *	Pretty print a netgroup entry
X */
Xstatic void
Xng_print(e, str)
X    struct nentry *e;
X    struct string *str;
X{
X    char *ptr = emalloc(e->n_size);
X
X    for (e = e->n_next; e != NULL; e = e->n_next) {
X	switch (e->n_type) {
X	case _NG_NAME:
X	    (void) snprintf(ptr, e->n_size, "%s", e->n_name);
X	    break;
X
X	case _NG_GROUP:
X	    (void) snprintf(ptr, e->n_size, "(%s,%s,%s)", e->n_group->ng_host,
X			    e->n_group->ng_user, e->n_group->ng_domain);
X	    break;
X
X	default:
X	    errx(1, "Internal error: Bad netgroup type\n");
X	    break;
X	}
X	str_append(str, ptr, ' ');
X    }
X    free(ptr);
X    return;
X}
X
X
X/* ng_rprint():
X *	Pretty print all reverse netgroup mappings in the given entry
X */
Xstatic void 
Xng_rprint(db, str)
X    DB *db;
X    struct string *str;
X{
X    int pos;
X    DBT key, data;
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((db->seq)(db, &key, &data, pos)) {
X	case 0: 
X	    str_append(str, (char *) key.data, ',');
X	    break;
X
X	case 1:
X	    return;
X
X	default:
X	    err(1, "seq");
X	    break;
X	}
X
X    return;
X}
X
X
X#ifdef DEBUG_NG
X/* ng_dump():
X *	Pretty print all netgroups in the given database
X */
Xstatic void 
Xng_dump(db)
X    DB *db;
X{
X    int pos;
X    DBT key, data;
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((db->seq)(db, &key, &data, pos)) {
X	case 0: 
X	    {
X		struct nentry *e = *((struct nentry **) data.data);
X		struct string buf;
X		str_init(&buf);
X		assert(e->n_type == _NG_NAME);
X
X		ng_print(e, &buf);
X		(void) fprintf(stderr, "%s\t%s\n", e->n_name,
X			       buf.s_str ? buf.s_str : "");
X		str_free(&buf);
X	    }
X	    break;
X
X	case 1:
X	    return;
X
X	default:
X	    err(1, "seq");
X	    return;
X	}
X}
X
X
X/* ng_rdump():
X *	Pretty print all reverse mappings in the given database
X */
Xstatic void 
Xng_rdump(db)
X    DB *db;
X{
X    int pos;
X    DBT key, data;
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((db->seq)(db, &key, &data, pos)) {
X	case 0: 
X	    {
X		DB *xdb = *((DB **) data.data);
X		struct string buf;
X		str_init(&buf);
X		ng_rprint(xdb, &buf);
X		(void) fprintf(stderr, "%s\t%s\n", (char *) key.data,
X			       buf.s_str ? buf.s_str : "");
X		str_free(&buf);
X	    }
X	    break;
X
X	case 1:
X	    return;
X
X	default:
X	    err(1, "seq");
X	    return;
X	}
X}
X#endif /* DEBUG_NG */
X
X
X/* ng_write():
X *	Dump the database into a file.
X */
Xstatic void 
Xng_write(odb, idb, k)
X    DB *odb, *idb;
X    int k;
X{
X    int pos;
X    DBT key, data;
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((idb->seq)(idb, &key, &data, pos)) {
X	case 0: 
X	    {
X		struct nentry *e = *((struct nentry **) data.data);
X		struct string skey, sdata;
X		str_init(&skey);
X		str_init(&sdata);
X		assert(e->n_type == _NG_NAME);
X
X		str_prepend(&skey, e->n_name, k);
X		ng_print(e, &sdata);
X		key.data = (u_char *) skey.s_str;
X		key.size = skey.s_len + 1;
X		data.data = (u_char *) sdata.s_str;
X		data.size = sdata.s_len + 1;
X
X		switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
X		case 0:
X		    break;
X
X		case -1:
X		    err(1, "put");
X		    break;
X
X		case 1:
X		default:
X		    abort();
X		    break;
X		}
X
X		str_free(&skey);
X		str_free(&sdata);
X	    }
X	    break;
X
X	case 1:
X	    return;
X
X	default:
X	    err(1, "seq");
X	    return;
X	}
X}
X
X
X/* ng_rwrite():
X *	Write the database
X */
Xstatic void 
Xng_rwrite(odb, idb, k)
X    DB *odb;
X    DB *idb;
X    int k;
X{
X    int pos;
X    DBT key, data;
X
X    for (pos = R_FIRST;; pos = R_NEXT)
X	switch ((idb->seq)(idb, &key, &data, pos)) {
X	case 0: 
X	    {
X		DB *xdb = *((DB **) data.data);
X		struct string skey, sdata;
X		str_init(&skey);
X		str_init(&sdata);
X
X		str_prepend(&skey, (char *) key.data, k);
X		ng_rprint(xdb, &sdata);
X		key.data = (u_char *) skey.s_str;
X		key.size = skey.s_len + 1;
X		data.data = (u_char *) sdata.s_str;
X		data.size = sdata.s_len + 1;
X
X		switch ((odb->put)(odb, &key, &data, R_NOOVERWRITE)) {
X		case 0:
X		    break;
X
X		case -1:
X		    err(1, "put");
X		    break;
X
X		case 1:
X		default:
X		    abort();
X		    break;
X		}
X
X		str_free(&skey);
X		str_free(&sdata);
X	    }
X	    break;
X
X	case 1:
X	    return;
X
X	default:
X	    err(1, "seq");
X	    return;
X	}
X}
X
X
X/* usage():
X *	Print usage message and exit
X */
Xstatic void
Xusage()
X{
X    extern const char *__progname;
X    fprintf(stderr, "usage: %s [-o db] file\n", __progname);
X    exit(1);
X}
END_OF_FILE
if test 11609 -ne `wc -c <'netgroup_mkdb/netgroup_mkdb.c'`; then
    echo shar: \"'netgroup_mkdb/netgroup_mkdb.c'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/netgroup_mkdb.c'
fi
if test -f 'netgroup_mkdb/str.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/str.c'\"
else
echo shar: Extracting \"'netgroup_mkdb/str.c'\" \(1295 characters\)
sed "s/^X//" >'netgroup_mkdb/str.c' <<'END_OF_FILE'
X/*
X * Counted strings
X */
X#include <stdlib.h>
X
X#include "util.h"
X#include "str.h"
X
X/* str_init():
X *	Initialize string
X */
Xvoid
Xstr_init(s)
X    struct string *s;
X{
X    s->s_str = NULL;
X    s->s_len = 0;
X}
X
X
X/* str_append():
X *	Append string allocating buffer as necessary
X */
Xvoid
Xstr_append(buf, str, del)
X    struct string *buf;
X    const char *str;
X    int del;
X{
X    size_t len = strlen(str) + 1;
X    if (buf->s_str == NULL)
X	buf->s_str = emalloc(len);
X    else {
X	buf->s_str = erealloc(buf->s_str, buf->s_len + len + 1);
X	if (del)
X	    buf->s_str[buf->s_len++] = del;
X    }
X    memcpy(&buf->s_str[buf->s_len], str, len);
X    buf->s_len += len - 1;
X}
X
X/* str_prepend():
X *	Prepend string allocating buffer as necessary
X */
Xvoid
Xstr_prepend(buf, str, del)
X    struct string *buf;
X    const char *str;
X    int del;
X{
X    size_t len = strlen(str) + 1;
X    char *ptr, *sptr;
X
X    sptr = ptr = emalloc(buf->s_len + len + 1);
X    if (del) 
X	*ptr++ = del;
X    memcpy(ptr, str, len);
X    if (buf->s_str) {
X	memcpy(&ptr[len - 1], buf->s_str, buf->s_len);
X	free(buf->s_str);
X    }
X    buf->s_str = sptr;
X    buf->s_len += len - 1;
X    if (del)
X	buf->s_len++;
X
X}
X
X/* str_free():
X *	Free a string
X */
Xvoid
Xstr_free(s)
X    struct string *s;
X{
X    free(s->s_str);
X    s->s_str = NULL;
X    s->s_len = 0;
X}
END_OF_FILE
if test 1295 -ne `wc -c <'netgroup_mkdb/str.c'`; then
    echo shar: \"'netgroup_mkdb/str.c'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/str.c'
fi
if test -f 'netgroup_mkdb/str.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/str.h'\"
else
echo shar: Extracting \"'netgroup_mkdb/str.h'\" \(350 characters\)
sed "s/^X//" >'netgroup_mkdb/str.h' <<'END_OF_FILE'
X/* Counted strings */
X
X#include <sys/types.h>
X#include <sys/cdefs.h>
X
Xstruct string {
X    char  *s_str;
X    size_t s_len;
X};
X
X__BEGIN_DECLS
Xvoid str_init		__P((struct string *));
Xvoid str_append		__P((struct string *, const char *, int));
Xvoid str_prepend	__P((struct string *, const char *, int));
Xvoid str_free		__P((struct string *));
X__END_DECLS
END_OF_FILE
if test 350 -ne `wc -c <'netgroup_mkdb/str.h'`; then
    echo shar: \"'netgroup_mkdb/str.h'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/str.h'
fi
if test -f 'netgroup_mkdb/util.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/util.c'\"
else
echo shar: Extracting \"'netgroup_mkdb/util.c'\" \(1049 characters\)
sed "s/^X//" >'netgroup_mkdb/util.c' <<'END_OF_FILE'
X#include <err.h>
X#include <stdlib.h>
X
X#include "util.h"
X
X/* emalloc():
X *	Error checked malloc
X */
Xvoid *
Xemalloc(s)
X    size_t s;
X{
X    void *ptr = malloc(s);
X    if (ptr == NULL)
X	/* Crappy gcc warning! */
X	err(1, "%s", "");
X    return ptr;
X}
X
X
X/* erealloc():
X *	Error checked realloc
X */
Xvoid *
Xerealloc(p, s)
X    void *p;
X    size_t s;
X{
X    void *ptr = realloc(p, s);
X    if (ptr == NULL)
X	/* Crappy gcc warning! */
X	err(1, "%s", "");
X    return ptr;
X}
X
X
X/* getline():
X *	Read a line from a file parsing continuations ending in \
X *	and eliminating trailing newlines.
X */
Xchar *
Xgetline(fp, size)
X    FILE *fp;
X    size_t *size;
X{
X    size_t s, len = 0;
X    char *buf = NULL;
X    char *ptr;
X    int cnt = 1;
X
X    while (cnt) {
X	if ((ptr = fgetln(fp, &s)) == NULL) {
X	    *size = len;
X	    return buf;
X	}
X	ptr[--s] = '\0';			/* Nuke newline */
X	if ((cnt = (ptr[s - 1] == '\\')) != 0)	/* check for \\ */
X	    ptr[s--] = '\0';
X
X	buf = erealloc(buf, len + s + 1);
X	memcpy(buf + len, ptr, s + 1);
X	len += s;
X    }
X    *size = len;
X    return buf;
X}
END_OF_FILE
if test 1049 -ne `wc -c <'netgroup_mkdb/util.c'`; then
    echo shar: \"'netgroup_mkdb/util.c'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/util.c'
fi
if test -f 'netgroup_mkdb/util.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'netgroup_mkdb/util.h'\"
else
echo shar: Extracting \"'netgroup_mkdb/util.h'\" \(199 characters\)
sed "s/^X//" >'netgroup_mkdb/util.h' <<'END_OF_FILE'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/cdefs.h>
X
X__BEGIN_DECLS
Xvoid *emalloc	__P((size_t));
Xvoid *erealloc	__P((void *, size_t));
Xchar *getline	__P((FILE *, size_t *));
X__END_DECLS
X
END_OF_FILE
if test 199 -ne `wc -c <'netgroup_mkdb/util.h'`; then
    echo shar: \"'netgroup_mkdb/util.h'\" unpacked with wrong size!
fi
# end of 'netgroup_mkdb/util.h'
fi
if test -f 'test/innetgr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test/innetgr.c'\"
else
echo shar: Extracting \"'test/innetgr.c'\" \(801 characters\)
sed "s/^X//" >'test/innetgr.c' <<'END_OF_FILE'
X/*
X * innetgr - Print if a user domain host is in group group
X * Options:
X *	-u  - user name
X *	-d  - domain name
X *	-h  - hostname
X */
X#include <stdio.h>
X#include <stdlib.h>
X
Xmain(argc, argv)
X	char **argv;
X{
X	char *p[3], *index();
X	int i = 0, c;
X	char *user = NULL;
X	char *host = NULL;
X	char *domain = NULL;
X
X	while ((c = getopt(argc, argv, "h:u:d:")) != EOF)
X		switch (c) {
X		case 'u':
X		   	user = optarg;
X			break;
X		case 'h':
X			host = optarg;
X			break;
X		case 'd':
X			domain = optarg;
X			break;
X		default:
X		usage:
X			fprintf(stderr, "Usage: %s [-h <host>] [-u <user>] [-d <domain>] netgroup\n", argv[0]);
X			exit(1);
X		}
X	if (optind >= argc)
X		goto usage;
X	for(; optind < argc; optind++) {
X		printf("%s: %d\n", argv[optind], 
X		       innetgr(argv[optind], host, user, domain));
X	}
X	exit(0);
X}
END_OF_FILE
if test 801 -ne `wc -c <'test/innetgr.c'`; then
    echo shar: \"'test/innetgr.c'\" unpacked with wrong size!
fi
# end of 'test/innetgr.c'
fi
if test -f 'test/netgroup.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'test/netgroup.c'\"
else
echo shar: Extracting \"'test/netgroup.c'\" \(732 characters\)
sed "s/^X//" >'test/netgroup.c' <<'END_OF_FILE'
X/*
X * netgroup - list netgroup members
X * Options:
X *	-m  - list machine name members (the default)
X *	-u  - list user names
X *	-d  - list domain names
X */
X#include <stdio.h>
X
Xmain(argc, argv)
X	char **argv;
X{
X	char *p[3], *index();
X	int i = 0, c;
X	extern int optind;
X
X	while ((c = getopt(argc, argv, "mud")) != EOF)
X		switch (c) {
X		case 'm':
X		case 'u':
X		case 'd':
X			p[0] = "mud";
X			i = index(p[0], c) - p[0];
X			break;
X		default:
X		usage:
X			fprintf(stderr, "Usage: %s [-mud] netgroup\n", argv[0]);
X			exit(1);
X		}
X	if (optind >= argc)
X		goto usage;
X	for(; optind < argc; optind++) {
X		setnetgrent(argv[optind]);
X		while (getnetgrent(&p[0], &p[1], &p[2]))
X			if (p[i])
X				printf("%s\n", p[i]);
X		endnetgrent();
X	}
X	exit(0);
X}
END_OF_FILE
if test 732 -ne `wc -c <'test/netgroup.c'`; then
    echo shar: \"'test/netgroup.c'\" unpacked with wrong size!
fi
# end of 'test/netgroup.c'
fi
echo shar: End of shell archive.
exit 0

------------------------------------------------------------------------------