v08i047: Account creation/manipulation program, Part07/08

sources-request at mirror.UUCP sources-request at mirror.UUCP
Sat Feb 7 07:19:57 AEST 1987


Submitted by: Kyle Jones <xanth!kyle>
Mod.sources: Volume 8, Issue 47
Archive-name: mcp/Part07

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of archive 7 (of 8)."
# Contents:  src/load.c src/main.c src/misc.c src/nitpick src/pwlock.c
#   src/range.c src/range.h src/remove.c src/report.c
# Wrapped by rs at mirror on Fri Feb  6 15:56:11 1987
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'src/load.c'" '(7238 characters)'
if test -f 'src/load.c' ; then 
  echo shar: will not over-write existing file "'src/load.c'"
else
sed 's/^X//' >src/load.c <<'@//E*O*F src/load.c//'
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <lastlog.h>
X#include <strings.h>
X#include "sysdep.h"
X#include "macros.h"
X#include "mem.h"
X#include "gpa.h"
X#include "lists.h"
X#include "account.h"
X#include "groupmap.h"
X#include "save.h"
X#include "sort.h"
X
Xaddr	makeusername(), gethomedir();
Xint	nlformat(), nfformat(), (*format)(), ModBits;
Xextern	addr DEF_SHELL;
Xchar	*crypt(), *sprintf();
X
Xint	lineno;
Xaddr	*filev;
X
Xloadfile(c, v)
Xint c;
Xaddr *v;
X
X{
X	FILE *f;
X	flexaddr p;
X	char line[LONG_BUF];
X	addr user, password, id, dir, *vv;
X	addr *realnamev;
X	addr_t shell[MEDIUM_BUF];
X	struct account *ac;
X	struct groupmap *gm, *gm2;
X	static struct list groups, classes, sigs;
X	int cc, added, gid, uid, i;
X	int totaladded = 0, filesloaded = 0;
X
X	zerolist(&groups);	tmplistadd(&groups);
X	zerolist(&sigs);	tmplistadd(&sigs);
X	zerolist(&classes);	tmplistadd(&classes);
X	if (c == 1) {
X		filev = get_gpa(8);
X		GetFilenames("Files: ", 8, &cc, filev);
X		if (cc == 0)
X			return;
X	}
X	else
X		filev = &v[1];
X	for (; *filev; filev++) {
X		added = 0;
X		lineno = 1;
X		if (access((char *)*filev, F_OK|R_OK) == -1) {
X			perr((char *)*filev);
X			err1("%s: file load aborted", (char *)*filev);
X			continue;
X		}
X		f = fopen((char *)*filev, "r");
X		if (f == NULL) {
X			perr((char *)*filev);
X			err1("%s: file load aborted", (char *)*filev);
X			continue;
X		}
X		if (hascolon(f)) {
X			err1("%s: file has colons in it! (load aborted)",
X				(char *)*filev);
X			continue;
X		}
X		(void) printf("%s:\n",(char *)*filev);
X		/*
X		 * First line should identity the file format
X		 */
X		if (fgets(line, BUFSIZ, f) == NULL) {
X			gag("missing format line");
X			gag("file load aborted");
X			continue;
X		}
X		switch (*line) {
X			/* name first format */
X		case 'N':
X		case 'n': format = nfformat;	break;
X			/* Id first format */
X		case 'I':
X		case 'i': format = nlformat;	break;
X		default:
X			gag1("bad format token \"%.8s\"", line);
X			gag("file load aborted");
X			continue;
X		}
X		lineno++;
X		/*
X		 * Second line should be a list of space separated
X		 * groups that the added users will be put into
X		 * The first group in the list will be the users base
X		 * gid group (the group for the gid in the passwd file).
X		 * It is an error for this line to be empty.
X		 */
X		if (fgets(line, BUFSIZ, f) == NULL) {
X			gag("missing groups line");
X			gag("file load aborted");
X			continue;
X		}
X		parse_line(line, &cc, &vv);
X		if (cc == 0) {
X			gag("groups line empty");
X			gag("file load aborted");
X			continue;
X		}
X		gm = getgmnam((char *)vv[0]);
X		if (!gm) {
X			gag1("%s: no such group", (char *)vv[0]);
X			gag("file load aborted");
X			continue;
X		}
X		gid = gm->gm_gid;
X		for (vv++; *vv; vv++)
X			if (groupexists((char *)*vv))
X				strlistadd(&groups, (char *)*vv);
X			else
X				gag1("%s: no such group", (char *)*vv);
X		lineno++;
X		/*
X		 * Third line should be a space separated list of
X		 * classes for the users to put in.  This line must
X		 * be peresent although it is permitted to be empty.
X		 */
X		if (fgets(line, BUFSIZ, f) == NULL) {
X			gag("missing classes line");
X			gag("file load aborted");
X			continue;
X		}
X		parse_line(line, &cc, &vv);
X		for (; *vv; vv++)
X			if (classexists((char *)*vv))
X				strlistadd(&classes, (char *)*vv);
X			else
X				gag1("%s: no such class", (char *)*vv);
X		lineno++;
X		/*
X		 * Fourth line should be a space separated list of
X		 * sigs for the users to put in.  This line must
X		 * be present although it is permitted to be empty.
X		 */
X		if (fgets(line, BUFSIZ, f) == NULL) {
X			gag("missing sigs line");
X			gag("file load aborted");
X			continue;
X		}
X		parse_line(line, &cc, &vv);
X		for (; *vv; vv++)
X			if (sigexists((char *)*vv))
X				strlistadd(&sigs, (char *)*vv);
X			else
X				gag1("%s: no such sig", (char *)*vv);
X		lineno++;
X		/*
X		 * Fifth line should contain the name of the shell
X		 * the added users should have.  This line must be
X		 * present but it may be blank.
X		 */
X		if (fgets(line, BUFSIZ, f) == NULL) {
X			gag("missing shell line");
X			gag("file load aborted");
X			continue;
X		}
X		parse_line(line, &cc, &vv);
X		if (cc && !fileexists((char *)vv[0])) {
X			gag1("%s: nonexistent shell", (char *)vv[0]);
X			gag("file load aborted");
X		}
X		else if (cc)
X			(void) strcpy((char *)shell, (char *)vv[0]);
X		else
X			(void) strcpy((char *)shell, (char *)DEF_SHELL);
X		lineno++;
X		/*
X		 * Lines from here on should be in the format specified
X		 * above.
X		 */
X		while (fgets(line, LONG_BUF, f) != NULL) {
X			if ((*format)(line, &cc, &realnamev, &id) == 0) {
X				gag("badly formed line");
X				continue;
X			}
X			ac = getacid((char *)id);
X			if (ac) {
X				user = ac->ac_name;
X				(void) orstrlist(&ac->ac_groups, &groups);
X				orstrlist(&ac->ac_classes, &classes)&&
X					ModBits |= AC;
X				orstrlist(&ac->ac_sigs, &sigs)&&
X					ModBits |= AC;
X				for (i=0; i<groups.l_count; i++) {
X				    gm2 = getgmnam((char *)groups.l_list[i]);
X				    if (instrlist(&gm2->gm_mem, (char *)user))
X					continue;
X				    ModBits |= (AC|GR);
X				    strlistadd(&gm2->gm_mem, (char *)user);
X				    sort_list(&gm2->gm_mem, pstrcmp);
X				}
X				(void) printf("%-12s%s\n", ac->ac_name,
X					ac->ac_realname);
X				continue;
X			}
X			uid = findnextuid(gm->gm_name);
X			if (uid == NOMORE) {
X				gag("no more uids");
X				gag("load terminated");
X				goto nextfile;
X			}
X			user = makeusername(cc, realnamev);
X			p.p_cp = crypt((char *)id, CRYPT_SALT);
X			password = p.p_ap;
X			dir = gethomedir((char *)user, gm->gm_name);
X			addu(uid, gid, user, glob(realnamev), password,
X				id, dir, shell);
X			added++;
X			ac = getacnam((char *)user);
X			(void) orstrlist(&ac->ac_groups, &groups);
X			orstrlist(&ac->ac_classes, &classes)&&ModBits|=AC;
X			orstrlist(&ac->ac_sigs, &sigs)&&ModBits|=AC;
X			for (i=0; i<groups.l_count; i++) {
X				gm2 = getgmnam((char *)groups.l_list[i]);
X				if (instrlist(&gm2->gm_mem, (char *)user))
X					continue;
X				ModBits |= (AC|GR);
X				strlistadd(&gm2->gm_mem, (char *)user);
X				sort_list(&gm2->gm_mem, pstrcmp);
X			}
X			(void) printf("%-12s%s\n", ac->ac_name,
X					ac->ac_realname);
X		}
X	nextfile:
X		(void) printf("%s: %d added\n", *filev, added);
X		filesloaded++;
X		totaladded += added;
X		freelist(&groups);
X		freelist(&sigs);
X		freelist(&classes);
X	}
X	if (totaladded) {
X		(void) printf("%d file%s loaded, %d user%s added\n",
X				filesloaded, S(filesloaded),
X				totaladded, S(totaladded));
X#ifndef	DOFILES
X		err("Don't forget to create directories for these users.");
X#endif
X	}
X	return;
X}
X
Xint
Xhascolon(f)
XFILE *f;
X
X{
X	int c;
X
X	rewind(f);
X	while ((c = getc(f)) != EOF)
X		if (c == ':') {
X			rewind(f);
X			return 1;
X		}
X	rewind(f);
X	return 0;
X}
X
Xint
Xnfformat(line, cc, r, id)
Xchar *line;
Xint *cc;
Xaddr **r;
Xaddr *id;
X
X{
X	int c;
X	addr *v;
X
X	parse_line(line, &c, &v);
X	if (c < 2)
X		return 0;
X	*id = v[c-1];
X	v[c-1] = NIL;
X	*cc = c - 1;
X	*r = v;
X	return 1;
X}
X
Xint
Xnlformat(line, cc, r, id)
Xchar *line;
Xint *cc;
Xaddr **r;
Xaddr *id;
X
X{
X	int c;
X	addr *v;
X
X	parse_line(line, &c, &v);
X	if (c < 2)
X		return 0;
X	*id = v[0];
X	*cc = c - 1;
X	*r = &v[1];
X	return 1;
X}
X
Xstatic
Xgag(msg)
Xchar *msg;
X
X{
X	char errmsg[LONG_BUF];
X
X	(void) sprintf(errmsg, "%s: line %d: %s", *filev, lineno, msg);
X	err(errmsg);
X	return;
X}
X
Xstatic
Xgag1(msg, s1)
Xchar *msg;
Xchar *s1;
X
X{
X	char errmsg[LONG_BUF];
X
X	(void) sprintf(errmsg, msg, s1);
X	gag(errmsg);
X	return;
X}
@//E*O*F src/load.c//
if test 7238 -ne "`wc -c <'src/load.c'`"; then
    echo shar: error transmitting "'src/load.c'" '(should have been 7238 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/main.c'" '(4050 characters)'
if test -f 'src/main.c' ; then 
  echo shar: will not over-write existing file "'src/main.c'"
else
sed 's/^X//' >src/main.c <<'@//E*O*F src/main.c//'
X#include <stdio.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/wait.h>
X#include <setjmp.h>
X#include <signal.h>
X#include "sysdep.h"
X#include "macros.h"
X#include "mem.h"
X#include "command.h"
X
X#define		ROOT_PROMPT	"\r(mcp) "
X#define		PROMPT		"\r(   ) "
X#define		CARGS		32	   /* # command line args allowed */
X
X#ifdef sun
X#define	sighandler	(void (*)())
X#else
X#define	sighandler	(int (*)())
X#endif
X
Xextern	int scommcmp(), kids, root, ModBits, NCommands, goodbye(), DevTty;
Xextern	struct command Ctable[];
Xextern	char Working_Directory[];
Xextern	int ReportGoop();
Xextern	Summarize();
Xextern	char *sprintf();
X
Xjmp_buf interrupt, in_continue;			/* setjmp vectors */
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X
X{
X	static char *prompt;
X	static addr v[CARGS+1];
X	int sjval, index, c, found, goop = 0;
X	int buildit, checkem, summary, listem, printversion;
X	char errmsg[MEDIUM_BUF];
X
X	(void) umask(022);
X
X	/*
X	 * Find out if this is the superuser, what the current working 
X	 * directory is, seed random number generator.
X	 * For Sun systems, also find out about file server, etc.
X	 */
X	init_identities();
X
X	buildit = checkem = summary = listem = printversion = 0;
X	while (--argc && **++argv == '-')
X	    for (++*argv; **argv; ++*argv)
X		switch (**argv) {
X		case 'v':
X		    printversion++; break;
X		case 'l':
X		    listem++;	break;
X		case 'B':
X		    buildit++;	break;
X		case 'c':
X		    checkem++;	break;
X		case 's':
X		    summary++;	break;
X		default:
X		    (void) sprintf(errmsg, "mcp: bad option '%c' (ignored)",
X					**argv);
X		    err(errmsg);
X		    break;
X		}
X	/*
X	 * Set up descriptor for /dev/tty or just attached to stderr
X	 * if not running interactively.
X	 */
X	init_tty(buildit || (!checkem && !summary && !listem));
X
X	if (buildit && (checkem || summary || listem))
X		fatal("mcp: can't use -B with any other option.");
X	if (buildit && !root)
X		fatal("mcp: must be the super-user to use -B");
X	if (argc)
X		err("mcp: extra arguments ignored");
X	if (printversion && !buildit) {
X	    ShowVersion();
X	    if (!(checkem || summary || listem))
X	      goodbye(0);
X	}
X	/*
X	 * Must set up some sort of quick 'n dirty signal handling lest
X	 * an interrupt cause the program to exit with the password
X	 * file locked.  So we block all signals except SIGINT, and trap
X	 * SIGINT to goodbye().
X	 */
X	(void) sigsetmask(~mask(SIGINT));
X	(void) signal(SIGINT, sighandler goodbye);
X
X	if ( root && !(checkem || summary || listem)) {
X		msg("Locking password file...");
X		if (!lockpw())
X			fatal("mcp: password file busy");
X		prompt = ROOT_PROMPT;
X	}
X	else
X		prompt = PROMPT;
X
X	if (buildit) Build();	/* Build() doesn't return */
X
X	/*
X	 * Pass a flag to init_lists() to indicate whether all or
X	 * or only some of the global lists need be initialized.
X	 */
X	init_lists(!(checkem || summary || listem));
X
X	if (checkem) goop = ReportGoop();
X	if (listem) ListThemThangs();
X	if (summary) Summarize();
X	if (checkem || summary || listem) goodbye(goop ? 1 : 0);
X
X#if CKPTIME > 0
X	if (root)
X	    (void) alarm(CKPTIME * 60);	/* start checkpointing timer */
X#endif
X	/*
X	 * Trap interrupts back to the main command interpreter.
X	 */
X	sjval = setjmp(interrupt);
X	if (sjval)
X		msg("\r\n");
X
X	setsignals();		/* connect signal handlers */
X
X	/*
X	 * Main command line interpreting loop
X	 */
X	for (;;) {
X		if (kids) reapchild();
X		closefiles();
X		freeargv(v);
X		free_gpa();
X		freetmplists();
X		(void) chdir(Working_Directory);
X		GetCommandLine(prompt, CARGS, &c, v);
X		if (c == 0)
X			continue;
X		index = search_array((char *)Ctable, (char *)v[0], NCommands,
X				sizeof (struct command), scommcmp, &found);
X		if (!found) {
X			err1("%s: unknown command", (char *)v[0]);
X			continue;
X		}
X		(*Ctable[index].c_func)(c, v);
X	}
X}
X
Xreapchild()
X
X{
X	if (wait3((union wait *)0, WNOHANG, (struct rusage *)0) > 0)
X		kids--;
X	return;
X}
X
X#if CKPTIME > 0
Xwakeup()
X
X{
X	kids && reapchild();
X	ModBits && ckpchanges();
X	(void) alarm(CKPTIME * 60);
X	return;
X}
X#endif
X
Xclosefiles()
X
X{
X	register int i, nd = getdtablesize();
X
X	for (i=3; i < nd; i++)
X		if (i != DevTty)
X			(void) close(i);
X	return;
X}
@//E*O*F src/main.c//
if test 4050 -ne "`wc -c <'src/main.c'`"; then
    echo shar: error transmitting "'src/main.c'" '(should have been 4050 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/misc.c'" '(8013 characters)'
if test -f 'src/misc.c' ; then 
  echo shar: will not over-write existing file "'src/misc.c'"
else
sed 's/^X//' >src/misc.c <<'@//E*O*F src/misc.c//'
X/**********************************************************************\
X* 								       *
X* 	misc.c							       *
X* 								       *
X* Miscellaneous routines ranging from password generators to word      *
X* capitalizers to a routine that scrubs untoward characters from user  *
X* names.							       *
X* 								       *
X\**********************************************************************/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/dir.h>
X#include <strings.h>
X#include <ctype.h>
X#include "sysdep.h"
X#include "macros.h"
X#include "mem.h"
X#include "lists.h"
X#include "range.h"
X#include "sort.h"
X
X#define DAY	86400	/* no. of seconds in a day */
X
Xextern	struct list RangeList;
Xchar	*ctime(), *sprintf();
Xlong	random();
X
Xcoloncount(s)
Xregister char *s;
X
X{
X	register int n = 0;
X
X	while (*s)
X		if (*s++ == ':')
X			n++;
X	return n;
X}
X
Xcapitalize(s)
Xchar *s;
X
X{
X	strlower(s);
X	if (isalpha(*s) && islower(*s))
X		*s = toupper(*s);
X}
X
Xstrlower(s)
Xchar *s;
X
X{
X	while (*s) {
X		if (isalpha(*s) && isupper(*s))
X			*s = tolower(*s);
X		s++;
X	}
X	return;
X}
X
X
Xint
Xsearch_array(a, s, nelem, elemsize, compfunc, found)
Xchar *a, *s;
Xint nelem, elemsize, (*compfunc)(), *found;
X
X{
X	int lo = 0, hi = nelem - 1 , middle, compval;
X	int offset;
X
X	*found = 0;
X	while (lo < hi) {
X		middle = (lo + hi) / 2;
X		offset = middle*elemsize;
X		if ((compval = (*compfunc)(s, a+offset)) == 0) {
X			*found = 1;
X			return middle;
X		}
X		else if (compval < 0) {
X			decr(middle);
X			hi = middle;
X		}
X		else
X			lo = middle + 1;
X	}
X	if (nelem && (*compfunc)(s, a+lo*elemsize) == 0)
X		*found = 1;
X	return lo;
X}
X
Xsavestr(cpp, s)
Xchar **cpp, *s;
X
X{
X	*cpp = (char *) MEM(strlen(s)+1);
X	(void) strcpy(*cpp, s);
X	return;
X}
X
Xstatic	char *suf[13] = { 
X	"Jr.",		"Sr.",		"I",
X	"II",		"III",		"IV",
X	"V",		"VI",		"VII",
X	"VIII",		"IX",		"X",
X	"Esq."
X};
X
Xstatic	char *ttl[6] = { "Prof.", "Dr.", "Mr.", "Ms.", "Mrs.", "Rev." };
X
Xstruct	list Suffixes = { 13, 13, (addr *)suf };
Xstruct	list Titles = {	6, 6, (addr *)ttl };
X
Xaddr
Xmakeusername(c, v)
Xint c;
Xaddr *v;
X
X{
X	static addr_t user[SHORT_BUF];
X	int found, tail;
X	flexaddr up;
X
X	up.p_ap = user;
X	(void) search_list(&Titles, (char *)v[0], strcmp, &found);
X	if (found) {
X		v++;
X		c--;
X	}
X	(void) search_list(&Suffixes, (char *)v[c-1], strcmp, &found);
X	if (found)
X		c--;
X	/*
X	 * If last name is seven characters or less and the
X	 * case-lowered version of this isn't taken, use it.
X	 */
X	if (strlen((char *)v[c-1]) < 8) {
X		(void) strcpy((char *)user, (char *)v[c-1]);
X		strlower((char *)user);
X		if (!userexists((char *)user)) {
X			scrub((char *)user);
X			return user;
X		}
X	}
X	/*
X	 * If we have three initials and they aren't already taken, use them.
X	 */
X	if (c == 3) {
X		up.p_cp[0] = ((char *)v[0])[0];
X		up.p_cp[1] = ((char *)v[1])[0];
X		up.p_cp[2] = ((char *)v[2])[0];
X		up.p_cp[3] = '\0';
X		strlower((char *)user);
X		if (!userexists((char *)user)) {
X			scrub((char *)user);
X			return user;
X		}
X	}
X	/*
X	 * Oh, well.  Chop off last name at five characters, append '_' and
X	 * first initial.  If the resulting name is unused, use it.
X	 * If not increment the first initial through the collating
X	 * sequence until we find a name that isn't used.  The latter should
X	 * happen rarely.
X	 */
X	(void) strcpy((char *)user, (char *)v[c-1]);
X	up.p_cp[5] = '\0';
X	tail = strlen((char *)user);
X	up.p_cp[tail++] = '_';
X	up.p_cp[tail++] = ((char *)v[0])[0];
X	up.p_cp[tail--] = '\0';
X	strlower((char *)user);
X	while (userexists((char *)user))
X		up.p_cp[tail]++;
X	scrub((char *)user);
X	return user;
X}
X
X/*
X * Change all unsavory characters in a username to '_'
X */
Xscrub(username)
Xchar *username;
X
X{
X	for (; *username; username++) {
X		if (isalpha(*username) || isdigit(*username))
X			continue;
X		if (*username == '-')
X			continue;
X		*username = '_';
X	}
X	return;
X}
X
X/*
X * This function is used to shut lint up about long to int conversions
X * that I don't CARE about when getting a tiny random number.
X */
Xint rnd()
X{
X	union a { int a_i; long a_l; } il;
X
X	il.a_l = random();
X	return il.a_i;
X}
X
X#define UPPER	(char)(rnd() % 26) + 'A'
X#define LOWER	(char)(rnd() % 26) + 'a'
X#define NUMBER	(char)(rnd() % 10) + '0'
X#define ODD	(rnd() % 2 == 1)
X#define EVEN	!ODD
X
Xchar *
Xmakepass()
X
X{
X	static char password[SHORT_BUF];
X	char *cp;
X
X	cp = password;
X	if (ODD)	*cp++ = UPPER;	else *cp++ = LOWER;
X	if (EVEN)	*cp++ = NUMBER;	else *cp++ = UPPER;
X	if (EVEN)	*cp++ = LOWER;	else *cp++ = NUMBER;
X	if (ODD)	*cp++ = LOWER;	else *cp++ = NUMBER;
X	if (ODD)	*cp++ = NUMBER;	else *cp++ = UPPER;
X	if (EVEN)	*cp++ = UPPER;	else *cp++ = LOWER;
X	return password;
X}
X
Xchar *
Xrsalt()
X
X{
X	static char salt[3];
X
X	if (EVEN)	salt[0] = UPPER;	else salt[0] = LOWER;
X	if (ODD)	salt[1] = LOWER;	else salt[1] = NUMBER;
X	salt[2] = '\0';
X	return salt;
X}
X
Xchar	*re_comp();
X
X/* ARGSUSED1 */
Xaddr
Xgethomedir(user, group)
Xchar *user, *group;
X
X#ifdef xanth
X{
X	static addr_t dbuf[LONG_BUF], defbuf[LONG_BUF+1];
X	char expr[LONG_BUF+1];
X	struct direct *dp;
X	DIR *dirp;
X
X	(void) sprintf((char *)defbuf, "/tmp/U%s", user);
X	dirp = opendir(USERDIR);
X	if (dirp == NULL) {
X		err1("cannot open %s (read)", USERDIR);
X		return(defbuf);
X	}
X	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X		if (dp->d_name[0] == '.')
X			continue;
X		(void) sprintf(expr, "^%s%c%c", dp->d_name, '.', '*');
X		(void) re_comp(expr);
X		if (re_exec(group) == 1) {
X			(void) sprintf((char *)dbuf, "%s/%s/%s", USERDIR,
X					dp->d_name, user);
X			closedir(dirp);
X			return(dbuf);
X		}
X	}
X	closedir(dirp);
X	return(defbuf);
X}
X#else
X{
X	static addr_t dbuf[LONG_BUF];
X
X	(void) sprintf((char *)dbuf, "%s/%s", USERDIR, user);
X	return dbuf;
X}
X#endif
X
X/*
X * Figger out where the next free uid is, taking into
X * consideration the range tables
X */
Xint findnextuid(group)
Xchar *group;
X
X{
X	struct range *rg;
X	int uid, indx;
X	int maxu, minu;
X
X	maxu = minu = 0;
X	uid = NOMORE;
X	for (indx=0; indx < RangeList.l_count; indx++) {
X		rg = (struct range *) RangeList.l_list[indx];
X		if (!eq(group, rg->rg_name))
X			continue;
X		if (rg->rg_from > rg->rg_to)
X			uid = rnextuid(rg->rg_from, rg->rg_to);
X		else
X			uid = nextuid(rg->rg_from, rg->rg_to);
X		if (uid != NOMORE)
X			return(uid);
X		maxu = max(maxu, rg->rg_from);
X		maxu = max(maxu, rg->rg_to);
X		minu = min(minu, rg->rg_from);
X		minu = min(minu, rg->rg_to);
X	}
X	/*
X	 *  No preference or no space available so now we look for space
X	 *  in shared ranges.
X	 */
X	for (indx=0; indx < RangeList.l_count; indx++) {
X		rg = (struct range *) RangeList.l_list[indx];
X		if (rg->rg_mode == RG_EXCLUSIVE || eq(rg->rg_name, group))
X			continue;
X		if (rg->rg_from > rg->rg_to)
X			uid = rnextuid(rg->rg_from, rg->rg_to);
X		else
X			uid = nextuid(rg->rg_from, rg->rg_to);
X		if (uid != NOMORE)
X			break;
X		maxu = max(maxu, rg->rg_from);
X		maxu = max(maxu, rg->rg_to);
X		minu = min(minu, rg->rg_from);
X		minu = min(minu, rg->rg_to);
X	}
X	uid = nextuid(0, minu-1);
X	if (uid == -1) uid = nextuid(maxu+1, 1000);
X	return(uid);
X}
X
Xint nextuid(lo, hi)
Xint lo, hi;
X
X{
X	int i;
X
X	for (i=lo; i<=hi; i++)
X		if (!uidexists(i))
X			return(i);
X	return(NOMORE);
X}
X
Xint rnextuid(hi, lo)
Xint hi, lo;
X
X{
X	int i;
X
X	for (i=hi; i>=lo; i--)
X		if (!uidexists(i))
X			return(i);
X	return(NOMORE);
X}
X
X/*
X * Max is a function here, because it is used in places where macro side
X * effects are not desired.
X */
Xint
Xmax(a, b)
Xint a, b;
X
X{
X	return (a > b ? a : b);
X}
X
Xint
Xmin(a, b)
Xint a, b;
X
X{
X	return (a < b ? a : b);
X}
X
Xdirscan(dir, l)
Xchar *dir;
Xregister struct list *l;
X
X{
X	struct direct *dp;
X	DIR *dirp;
X
X	zerolist(l);
X	dirp = opendir(dir);
X	if (dirp == NULL)
X		return;
X	for (dp=readdir(dirp); dp != NULL; dp=readdir(dirp)) {
X		if (eq(dp->d_name, ".") || eq(dp->d_name, ".."))
X			continue;
X		strlistadd(l, dp->d_name);
X	}
X	closedir(dirp);
X	sort_list(l, pstrcmp);
X	return;
X}
X
Xint
Xisdir(name)
Xchar *name;
X
X{
X	struct stat sb;
X
X	if (stat(name, &sb) == -1)
X		return 0;
X	return ((sb.st_mode&S_IFMT) == S_IFDIR) ? 1 : 0;
X}
X
Xvalidint(str)
Xchar *str;
X
X{
X	if (!str || !*str)
X		return 0;
X	while (*str)
X		if (!isdigit(*str))
X			return 0;
X		else
X			str++;
X	return 1;
X}
@//E*O*F src/misc.c//
if test 8013 -ne "`wc -c <'src/misc.c'`"; then
    echo shar: error transmitting "'src/misc.c'" '(should have been 8013 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/nitpick'" '(606 characters)'
if test -f 'src/nitpick' ; then 
  echo shar: will not over-write existing file "'src/nitpick'"
else
sed 's/^X//' >src/nitpick <<'@//E*O*F src/nitpick//'
X#! /bin/sh
X
X#
X# Script to lint individual source modules and maintain lint
X# dependencies.
X#
X# Is invoked through 'make lintbrush'
X#
X# Works great if you have jove.  Works even better if you can use
X# jove. |-)
X#
X
Xfor file
Xdo
X	if test ! -f Lint/$file ; then
X		touch Lint/$file
X	# if the lint marker is younger than the source don't lint
X	elif test `ls -t $file Lint/$file | head -1` != $file ; then
X		continue;
X	fi
X	while test `lint -a -b -h -u $file | tee LintErrors | wc -l` != "1"
X	do
X		echo Uh, oh.  Trouble with $file...
X		jove -p LintErrors $file
X	done
X	echo $file ok.
X	touch Lint/$file
Xdone
X
Xexit 0
@//E*O*F src/nitpick//
if test 606 -ne "`wc -c <'src/nitpick'`"; then
    echo shar: error transmitting "'src/nitpick'" '(should have been 606 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/pwlock.c'" '(712 characters)'
if test -f 'src/pwlock.c' ; then 
  echo shar: will not over-write existing file "'src/pwlock.c'"
else
sed 's/^X//' >src/pwlock.c <<'@//E*O*F src/pwlock.c//'
X#include <sys/types.h>
X#include <sys/file.h>
X#include "sysdep.h"
X
Xextern	time_t PWLockTime;
Xstatic	int pwlocked;
X
Xlockpw()
X
X{
X	int fd, i;
X	time_t time();
X
X	for (i=1; i<5; i++) {
X		if ((fd=open(PWDLOCK, O_WRONLY|O_CREAT|O_EXCL, 0644)) >= 0) {
X			(void) time(&PWLockTime);
X			(void) close(fd);
X			pwlocked++;
X			return(1);
X		}
X		else switch (i) {
X			case 2: msg("Waiting for passwd lock...");	break;
X			case 3: msg("Still waiting...");		break;
X			case 4: msg("Pacing angrily...");		break;
X			default: break;
X		}
X		sleep(2 * (unsigned)i);
X	}
X	return(0);
X}
X
Xunlockpw()
X
X{
X	if (!pwlocked) return;
X	if (unlink(PWDLOCK) == -1) {
X		perr("Warning: unable to unlock password file");
X		return;
X	}
X	pwlocked = 0;
X	return;
X}
@//E*O*F src/pwlock.c//
if test 712 -ne "`wc -c <'src/pwlock.c'`"; then
    echo shar: error transmitting "'src/pwlock.c'" '(should have been 712 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/range.c'" '(1138 characters)'
if test -f 'src/range.c' ; then 
  echo shar: will not over-write existing file "'src/range.c'"
else
sed 's/^X//' >src/range.c <<'@//E*O*F src/range.c//'
X#include <stdio.h>
X#include "sysdep.h"
X#include "mem.h"
X#include "lists.h"
X#include "range.h"
X
Xextern	struct list RangeList;
Xextern	int srangecmp();
X
Xstatic FILE *rgf = NULL;
Xstatic char line[BUFSIZ];
Xstatic char namebuf[SHORT_BUF+1], modebuf[SHORT_BUF+1];
Xstatic struct range rg;
X
Xsetrgent()
X
X{
X	rg.rg_name = namebuf;
X	if( rgf == NULL ) {
X		rgf = fopen( RANGEFILE, "r" );
X		if (rgf == NULL) {
X			perr(RANGEFILE);
X			goodbye(1);
X		}
X		rewind(rgf);
X	}
X	else
X		rewind( rgf );
X}
X
Xendrgent()
X
X{
X	if( rgf != NULL ){
X		(void) fclose( rgf );
X		rgf = NULL;
X	}
X}
X
Xstruct range *
Xgetrgent()
X
X{
X	register char *p;
X	int n;
X
X	if (rgf == NULL)
X		setrgent();
X	p = fgets(line, BUFSIZ, rgf);
X	if (p==NULL)
X		return(0);
X	n = sscanf(line, "%s%d%d%s",rg.rg_name,
X				&rg.rg_from,
X				&rg.rg_to,
X				modebuf);
X	if (n != 4) fatal("badly formatted range file line!");
X	rg.rg_mode = (modebuf[0] == 'e' ? RG_EXCLUSIVE : RG_SHARED);
X	return(&rg);
X}
X
Xstruct range *
Xgetrgnam(name)
Xchar *name;
X
X{
X	int indx, found;
X
X	indx = search_list(&RangeList, name, srangecmp, &found);
X	if (found)
X		return (struct range *) RangeList.l_list[indx];
X	return (struct range *) 0;
X}
@//E*O*F src/range.c//
if test 1138 -ne "`wc -c <'src/range.c'`"; then
    echo shar: error transmitting "'src/range.c'" '(should have been 1138 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/range.h'" '(158 characters)'
if test -f 'src/range.h' ; then 
  echo shar: will not over-write existing file "'src/range.h'"
else
sed 's/^X//' >src/range.h <<'@//E*O*F src/range.h//'
Xstruct range {
X	char	*rg_name;
X	int	rg_from;
X	int	rg_to;
X	int	rg_mode;
X};
X
X#define RG_EXCLUSIVE	1
X#define RG_SHARED	2
X
Xstruct range *getrgent(), *getrgnam();
@//E*O*F src/range.h//
if test 158 -ne "`wc -c <'src/range.h'`"; then
    echo shar: error transmitting "'src/range.h'" '(should have been 158 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/remove.c'" '(14203 characters)'
if test -f 'src/remove.c' ; then 
  echo shar: will not over-write existing file "'src/remove.c'"
else
sed 's/^X//' >src/remove.c <<'@//E*O*F src/remove.c//'
X#include <stdio.h>
X#include <sys/types.h>
X#include <lastlog.h>
X#include "sysdep.h"
X#include "macros.h"
X#include "mem.h"
X#include "lists.h"
X#include "gpa.h"
X#include "sort.h"
X#include "account.h"
X#ifdef SENDMAIL
X#include "alias.h"
X#endif
X#include "groupmap.h"
X#include "class.h"
X#include "job.h"
X#include "range.h"
X#include "sig.h"
X#include "save.h"
X
X#ifdef SENDMAIL
Xextern	struct list AliasList, Aliases;
X#endif SENDMAIL
Xextern	struct list AccountList, Classes, ClassList;
Xextern	struct list GroupMapList, Groups, SigList, Sigs, RangeList, Ranges;
Xextern	struct list Users, Vigs;
Xextern	int ModBits;
Xchar	*sprintf();
X
X#ifdef SENDMAIL
Xrmalias(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct alias *al;
X	struct class *cs;
X	struct sig *sg;
X	struct groupmap *gm;
X	struct account *ac;
X	char *name;
X	register int i;
X
X	if ( c > 2 ) {
X	    err1("%s: too many arguments", (char *)v[0]);
X	    return;
X	}
X	if ( c != 2 ) {
X	    err1("usage: %s <alias>", (char *)v[0]);
X	    return;
X	}
X
X	al = getalnam((char *)v[1]);
X	if (!al) {
X	    err1("%s: no such alias", (char *)v[1]);
X	    return;
X	}
X
X	critical();
X	name = al->al_name;
X	freelist(&al->al_addresses);
X	freelist(&al->al_groups);
X	freelist(&al->al_classes);
X	freelist(&al->al_sigs);
X	strlistdel(&Aliases, (char *)v[1]);
X	genlistdel(&AliasList, v[1], saliascmp);
X	FREEMEM(name);
X	for (i=0; i < AliasList.l_count; i++) {
X	    al = (struct alias *) AliasList.l_list[i];
X	    if (instrlist(&al->al_addresses, (char *)v[1]))
X		strlistdel(&al->al_addresses, (char *)v[1]);
X	}
X	for (i=0; i < GroupMapList.l_count; i++) {
X	    gm = (struct groupmap *) GroupMapList.l_list[i];
X	    if (instrlist(&gm->gm_aliases, (char *)v[1]))
X		strlistdel(&gm->gm_aliases, (char *)v[1]);
X	}
X	for (i=0; i < ClassList.l_count; i++) {
X	    cs = (struct class *) ClassList.l_list[i];
X	    if (instrlist(&cs->cs_aliases, (char *)v[1]))
X		strlistdel(&cs->cs_aliases, (char *)v[1]);
X	}
X	for (i=0; i < SigList.l_count; i++) {
X	    sg = (struct sig *) SigList.l_list[i];
X	    if (instrlist(&sg->sg_aliases, (char *)v[1]))
X		strlistdel(&sg->sg_aliases, (char *)v[1]);
X	}
X	for (i=0; i < AccountList.l_count; i++) {
X	    ac = (struct account *) AccountList.l_list[i];
X	    if (instrlist(&ac->ac_aliases, (char *)v[1])) {
X		strlistdel(&ac->ac_aliases, (char *)v[1]);
X		ModBits |= AC;
X	    }
X	}
X	ModBits |= AL;
X	puts("removed");
X	non_critical();
X
X	return;
X}
X#endif
X
Xrmclass(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct class *cs;
X#ifdef SENDMAIL
X	struct alias *al;
X#endif
X	struct account *ac;
X	char *name;
X	int i;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <class>", (char *)v[0]);
X		return;
X	}
X
X	cs = getcsnam((char *)v[1]);
X	if (!cs) {
X		err1("%s: no such class", (char *)v[1]);
X		return;
X	}
X
X	critical();
X
X#ifdef SENDMAIL
X	for (i=0; i < AliasList.l_count; i++) {
X	    al = (struct alias *) AliasList.l_list[i];
X	    if (instrlist(&al->al_classes, (char *)v[1])) {
X		strlistdel(&al->al_classes, (char *)v[1]);
X		ModBits |= AL;
X	    }
X	}
X#endif
X	for (i=0; i < AccountList.l_count; i++) {
X		ac = (struct account *) AccountList.l_list[i];
X		if (instrlist(&ac->ac_classes, (char *)v[1])) {
X			strlistdel(&ac->ac_classes, (char *)v[1]);
X#ifdef SENDMAIL
X			if (cs->cs_aliases.l_count)
X			    RXBindings(ac);
X#endif
X			ModBits |= AC;
X		}
X	}
X
X	name = cs->cs_name;
X	FREEMEM(cs->cs_desc);
X	genlistdel(&ClassList, v[1], sclasscmp);
X	strlistdel(&Classes, (char *)v[1]);
X	FREEMEM(name);
X
X	ModBits |= CS;
X
X	puts("removed");
X	non_critical();
X	return;
X}
X
Xrmcryos(c, v)
Xint c;
Xchar **v;
X
X{
X	register struct account *ac;
X	register int indx;
X	int removed = 0;
X
X	if ( c > 1 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	critical();
X	for (indx=0; indx < AccountList.l_count; indx++) {
X		ac = (struct account *) AccountList.l_list[indx];
X		if (eq(ac->ac_shell, FREEZE_SH)) {
X			rmu(ac, 1);
X			removed++;
X			/* someone else is in this spot now */
X			indx--;
X		}
X	}
X	if (removed) {
X		(void) printf("%d removed\n", removed);
X#ifndef DOFILES
X		err("Do not forget to remove the user directories.");
X#endif
X	}
X	else
X		puts("No cryos.");
X	non_critical();
X	return;
X}
X
X#ifdef SENDMAIL
Xrmfromalias(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct alias *al;
X	struct account *ac;
X	addr *addressv;
X	int cc, removed = 0;
X	register int indx;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if (c != 2) {
X		err1("usage: %s <alias>", (char *)v[0]);
X		return;
X	}
X	al = getalnam((char *)v[1]);
X	if (!al) {
X		err1("%s: no such alias", (char *)v[1]);
X		return;
X	}
X
X	addressv = get_gpa(65);
X	GetLine("Addresses: ", 64, &cc, addressv, &al->al_addresses);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X	for (indx=0; indx < cc; indx++) {
X		if (!instrlist(&al->al_addresses, (char *)addressv[indx])) {
X			err1("%s: not in alias", (char *)addressv[indx]);
X			continue;
X		}
X		strlistdel(&al->al_addresses, (char *)addressv[indx]);
X		ac = getacnam((char *)addressv[indx]);
X		if (ac&&instrlist(&ac->ac_aliases, (char *)addressv[indx])) {
X			strlistdel(&ac->ac_aliases, al->al_name);
X			ModBits |= AC;
X		}
X		removed++;
X	}
X	if (removed) {
X		ModBits |= AL;
X		(void) printf("%d removed\n", removed);
X	}
X	else
X		err("no change");
X	non_critical();
X
X	return;
X}
X#endif SENDMAIL
X
Xrmfromclass(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct class *cs;
X	struct account *ac;
X	addr *userv;
X	int cc;
X	register int i, removed = 0;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if (c != 2) {
X		err1("usage: %s <class>", (char *)v[0]);
X		return;
X	}
X	cs = getcsnam((char *)v[1]);
X	if (!cs) {
X		err1("%s: no such class", (char *)v[1]);
X		return;
X	}
X	userv = get_gpa(65);
X	GetLine("Users: ", 64, &cc, userv, &Users);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X
X	for (i=0; i < cc; i++) {
X		ac = getacnam((char *)userv[i]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[i]);
X			continue;
X		}
X		if (!instrlist(&ac->ac_classes, (char *)v[1])) {
X			err1("%s: not in class", (char *)userv[i]);
X			continue;
X		}
X		strlistdel(&ac->ac_classes, (char *)v[1]);
X#ifdef SENDMAIL
X		if (cs->cs_aliases.l_count)
X		    RXBindings(ac);
X#endif
X		removed++;
X	}
X	if (removed) {
X		(void) printf("%d removed\n");
X		ModBits |= AC;
X	}
X	else
X		err("no change");
X
X	non_critical();
X	return;
X}
X
Xrmfromgroup(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct groupmap *gm;
X	struct account *ac;
X	addr *userv;
X	int cc;
X	register int i, removed = 0;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if (c != 2) {
X		err1("usage: %s <group>", (char *)v[0]);
X		return;
X	}
X	gm = getgmnam((char *)v[1]);
X	if (!gm) {
X		err1("%s: no such group", (char *)v[1]);
X		return;
X	}
X	userv = get_gpa(65);
X	GetLine("Users: ", 64, &cc, userv, &gm->gm_mem);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X	for (i=0; i < cc; i++) {
X		ac = getacnam((char *)userv[i]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[i]);
X			continue;
X		}
X		if (!instrlist(&gm->gm_mem, (char *)userv[i])) {
X			err1("%s: not in group", (char *)userv[i]);
X			continue;
X		}
X		strlistdel(&ac->ac_groups, (char *)v[1]);
X		strlistdel(&gm->gm_mem, (char *)userv[i]);
X#ifdef SENDMAIL
X		if (gm->gm_aliases.l_count)
X		    RXBindings(ac);
X#endif
X		removed++;
X	}
X	if (removed) {
X		(void) printf("%d removed\n");
X		ModBits |= AC|GR;
X	}
X	else
X		err("no change");
X	non_critical();
X
X	return;
X}
X
Xrmfromsig(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct sig *sg;
X	struct account *ac;
X	addr *userv;
X	int cc;
X	register int i, removed = 0;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if (c != 2) {
X		err1("usage: %s <sig>", (char *)v[0]);
X		return;
X	}
X	sg = getsgnam((char *)v[1]);
X	if (!sg) {
X		err1("%s: no such sig", (char *)v[1]);
X		return;
X	}
X	userv = get_gpa(65);
X	GetLine("Users: ", 64, &cc, userv, &Users);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X	for (i=0; i < cc; i++) {
X		ac = getacnam((char *)userv[i]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[i]);
X			continue;
X		}
X		if (!instrlist(&ac->ac_sigs, (char *)v[1])) {
X			err1("%s: not in sig", (char *)userv[i]);
X			continue;
X		}
X		strlistdel(&ac->ac_sigs, (char *)v[1]);
X#ifdef SENDMAIL
X		if (sg->sg_aliases.l_count)
X		    RXBindings(ac);
X#endif
X		removed++;
X	}
X	if (removed) {
X		(void) printf("%d removed\n");
X		ModBits |= AC;
X	}
X	else
X		err("no change");
X	non_critical();
X
X	return;
X}
X
Xrmgroup(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct groupmap *gm;
X	struct account *ac;
X#ifdef SENDMAIL
X	struct alias *al;
X#endif
X	char *name;
X	int i, removed = 0;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <group>", (char *)v[0]);
X		return;
X	}
X
X	gm = getgmnam((char *)v[1]);
X	if (!gm) {
X		err1("%s: no such group", (char *)v[1]);
X		return;
X	}
X
X	critical();
X
X#ifdef SENDMAIL
X	for (i=0; i < AliasList.l_count; i++) {
X	    al = (struct alias *) AliasList.l_list[i];
X	    if (instrlist(&al->al_groups, (char *)v[1])) {
X		strlistdel(&al->al_groups, (char *)v[1]);
X		ModBits |= AL;
X	    }
X	}
X#endif
X	for (i=0; i < gm->gm_mem.l_count; i++) {
X		ac = getacnam((char *)gm->gm_mem.l_list[i]);
X		if (!ac) continue;
X		if (instrlist(&ac->ac_groups, (char *)v[1])) {
X			strlistdel(&ac->ac_groups, (char *)v[1]);
X#ifdef SENDMAIL
X			if (gm->gm_aliases.l_count)
X			    RXBindings(ac);
X#endif
X			removed++;
X		}
X	}
X
X	if (removed) ModBits |= AC;
X
X	if (rangeexists((char *)v[1])) {
X		ModBits |= RG;
X		genlistdel(&RangeList, v[1], srangecmp);
X		strlistdel(&Ranges, (char *)v[1]);
X	}
X	if (vigexists((char *)v[1])) {
X		ModBits |= VG;
X		strlistdel(&Vigs, (char *)v[1]);
X	}
X
X	ModBits |= GR;
X
X	name = gm->gm_name;
X	freelist(&gm->gm_mem);
X	genlistdel(&GroupMapList, (addr)&gm->gm_gid, igmapcmp);
X	strlistdel(&Groups, (char *)v[1]);
X	FREEMEM(name);
X	puts("removed");
X	non_critical();
X
X	return;
X}
X
Xrmrange(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct range *rg;
X	char *name;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <group>", (char *)v[0]);
X		return;
X	}
X
X	rg = getrgnam((char *)v[1]);
X	if (!rg) {
X		err1("%s: no such range", (char *)v[1]);
X		return;
X	}
X
X	critical();
X	name = rg->rg_name;
X	genlistdel(&RangeList, v[1], srangecmp);
X	strlistdel(&Ranges, (char *)v[1]);
X	FREEMEM(name);
X	ModBits |= RG;
X	puts("removed");
X	non_critical();
X
X	return;
X}
X
Xrmsig(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct sig *sg;
X	struct account *ac;
X#ifdef SENDMAIL
X	struct alias *al;
X#endif
X	char *name;
X	int i;
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <sig>\n", (char *)v[0]);
X		return;
X	}
X
X	sg = getsgnam((char *)v[1]);
X	if (!sg) {
X		err1("%s: no such sig", (char *)v[1]);
X		return;
X	}
X
X	critical();
X
X#ifdef SENDMAIL
X	for (i=0; i < AliasList.l_count; i++) {
X	    al = (struct alias *) AliasList.l_list[i];
X	    if (instrlist(&al->al_sigs, (char *)v[1])) {
X		strlistdel(&al->al_sigs, (char *)v[1]);
X		ModBits |= AL;
X	    }
X	}
X#endif
X	for (i=0; i < AccountList.l_count; i++) {
X		ac = (struct account *) AccountList.l_list[i];
X		if (instrlist(&ac->ac_sigs, (char *)v[1])) {
X			strlistdel(&ac->ac_sigs, (char *)v[1]);
X#ifdef SENDMAIL
X			if (sg->sg_aliases.l_count)
X			    RXBindings(ac);
X#endif
X			ModBits |= AC;
X		}
X	}
X
X	name = sg->sg_name;
X	FREEMEM(sg->sg_desc);
X	genlistdel(&SigList, v[1], ssigcmp);
X	strlistdel(&Sigs, (char *)v[1]);
X	FREEMEM(name);
X
X	ModBits |= SG;
X
X	puts("removed");
X	non_critical();
X
X	return;
X}
X
Xrmuser(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct account *ac;
X	int zapdir;
X#ifdef DOFILES
X	char prompt[LONG_BUF];
X#endif
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <user>", (char *)v[0]);
X		return;
X	}
X	ac = getacnam((char *)v[1]);
X	if (!ac) {
X		err1("%s: no such user", (char *)v[1]);
X		return;
X	}
X
X#ifdef DOFILES
X	if (fileexists((char *)ac->ac_dir)) {
X	    (void) sprintf(prompt, "Home directory is %s, remove it? ",
X			   ac->ac_dir);
X	    zapdir = yesno(prompt);
X	}
X	else
X	  err1("hmmm... home directory %s non-existent", (char *)ac->ac_dir);
X#else
X	err("Do not forget to remove the user's home directory.");
X	zapdir = 0;
X#endif
X	rmu(ac, zapdir);
X
X	(void) printf("%s removed\n", v[1]);
X	return;
X}
X
Xrmvig(c, v)
Xint c;
Xaddr *v;
X
X{
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if ( c != 2 ) {
X		err1("usage: %s <vig>", (char *)v[0]);
X		return;
X	}
X
X	if (!vigexists((char *)v[1])) {
X		err1("%s: no such vig", (char *)v[1]);
X		return;
X	}
X
X	critical();
X
X	strlistdel(&Vigs, (char *)v[1]);
X	ModBits |= VG;
X
X	puts("removed");
X	non_critical();
X	return;
X}
X
X/*
X * This is the routine that actually removes a user from the data
X * structures.  rmuser() is just a front end to this routine.
X */
X/* ARGSUSED */
Xrmu(ac, zapdir)
Xstruct account *ac;
Xint zapdir;
X
X{
X	register int i, j;
X	register struct groupmap *gm;
X#ifdef SENDMAIL
X	struct alias *al;
X#endif
X	
X	critical();
X	
X#ifdef DOFILES
X	zapdir && add_job(JB_RMDIR, ac->ac_dir, NIL, NIL);
X	add_job(JB_RMMAIL, ac->ac_name, NIL, NIL);
X#endif
X
X	for (i=0; i < GroupMapList.l_count; i++) {
X		gm = (struct groupmap *) GroupMapList.l_list[i];
X		if (instrlist(&gm->gm_mem, (char *)ac->ac_name)) {
X			strlistdel(&gm->gm_mem, (char *)ac->ac_name);
X			ModBits |= GR;
X		}
X	}
X	strlistdel(&Users, (char *)ac->ac_name);
X
X#ifdef SENDMAIL
X	for (i=0; i < AliasList.l_count; i++) {
X	    al = (struct alias *) AliasList.l_list[i];
X	    if (instrlist(&al->al_addresses, (char *)ac->ac_name)) {
X		strlistdel(&al->al_addresses, (char *)ac->ac_name);
X		ModBits |= AL;
X	    }
X	}
X#endif
X
X	FREEMEM((char *)ac->ac_name);
X	FREEMEM((char *)ac->ac_realname);
X	FREEMEM((char *)ac->ac_gecos);
X	FREEMEM((char *)ac->ac_passwd);
X	FREEMEM((char *)ac->ac_id);
X	FREEMEM((char *)ac->ac_dir);
X	FREEMEM((char *)ac->ac_shell);
X	freelist(&ac->ac_groups);
X	freelist(&ac->ac_classes);
X	freelist(&ac->ac_sigs);
X#ifdef SENDMAIL
X	freelist(&ac->ac_aliases);
X#endif
X
X	/*
X	 * Cannot use genlistdel() because AccountList is sorted by uid, and
X	 * not by name.
X	 */
X	for (i=0; i < AccountList.l_count; i++)
X		if (ac == (struct account *) AccountList.l_list[i])
X			break;
X	for (j=i; j < AccountList.l_count-1; j++)
X		AccountList.l_list[j] = AccountList.l_list[j+1];
X	AccountList.l_count--;
X	FREEMEM((char *)ac);
X
X	ModBits |= AC|PW;
X
X	non_critical();
X
X	return;
X}
@//E*O*F src/remove.c//
if test 14203 -ne "`wc -c <'src/remove.c'`"; then
    echo shar: error transmitting "'src/remove.c'" '(should have been 14203 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/report.c'" '(6824 characters)'
if test -f 'src/report.c' ; then 
  echo shar: will not over-write existing file "'src/report.c'"
else
sed 's/^X//' >src/report.c <<'@//E*O*F src/report.c//'
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <lastlog.h>
X#include "sysdep.h"
X#include "macros.h"
X#include "mem.h"
X#include "lists.h"
X#include "account.h"
X#ifdef SENDMAIL
X#include "alias.h"
X#endif
X#include "class.h"
X#include "groupmap.h"
X#include "range.h"
X#include "sig.h"
X#include "sort.h"
X
X#ifdef BSD4_3
Xtime_t	time();
X#endif
X
X#ifdef SENDMAIL
Xextern	struct list AliasList;
X#endif
Xextern	struct list AccountList, ClassList, GroupMapList, RangeList, SigList;
Xextern	int root;
Xextern	char *when();
X
XSummarize()
X
X{
X	(void) printf("%d user%s, %d group%s, %d class%s, %d sig%s",
X		AccountList.l_count, S(AccountList.l_count),
X		GroupMapList.l_count, S(GroupMapList.l_count),
X		ClassList.l_count, ES(ClassList.l_count),
X		SigList.l_count, S(SigList.l_count));
X#ifdef SENDMAIL
X	(void) printf(", %d alias%s\n", AliasList.l_count,
X			ES(AliasList.l_count));
X#else
X	(void) puts("");
X#endif
X	return;
X}
X
Xint
XReportGoop()
X
X{
X	struct account *ac;
X	struct groupmap *gm;
X	struct class *cs;
X	struct sig *sg;
X	struct stat sb;
X	struct list c, s;
X#ifdef SENDMAIL
X	struct alias *al;
X	char *cp;
X#endif
X	time_t now;
X	int goop = 0;
X	register int indx, i;
X
X	zerolist(&c);	zerolist(&s);
X	for (indx=0; indx < AccountList.l_count; indx++) {
X		ac = (struct account *) AccountList.l_list[indx];
X		/*
X		 * For root and vig members, howl if no password.
X		 */
X		if (ac->ac_passwd[0] == '\0') {
X		    if (ac->ac_uid == 0) {
X			(void) printf("user \"%s\" has no password!\n", ac->ac_name);
X			continue;
X		    }
X		    gm = getgmgid(ac->ac_gid);
X		    if (gm && vigexists((char *)gm->gm_name))
X			(void) printf("user \"%s\" has no password\n", ac->ac_name);
X		}
X		/*
X		 * Report users with base gids that do not correspond
X		 * to a group in /etc/group.
X		 */
X		if (!gidexists(ac->ac_gid))
X		    (void) printf("user \"%s\" has nonexistent gid of (%d)\n",
X				ac->ac_name, ac->ac_gid);
X		/*
X		 * Report references to non-existent classes
X		 */
X		for (i=0; i < ac->ac_classes.l_count; i++) {
X			if (!classexists((char *)ac->ac_classes.l_list[i])) {
X(void) printf("user \"%s\" is member of nonexistent class \"%s\"\n",
X				ac->ac_name, ac->ac_classes.l_list[i]);
X				goop++;
X				continue;
X			}
X			if (!instrlist(&c, (char *)ac->ac_classes.l_list[i]))
X			    strlistadd(&c, (char *)ac->ac_classes.l_list[i]);
X		}
X		/*
X		 * Report references to non-existent sigs
X		 */
X		for (i=0; i < ac->ac_sigs.l_count; i++) {
X			if (!sigexists((char *)ac->ac_sigs.l_list[i])) {
X(void) printf("user \"%s\" is member of nonexistent sig \"%s\"\n",
X				ac->ac_name, ac->ac_sigs.l_list[i]);
X				goop++;
X				continue;
X			}
X			if (!instrlist(&s, (char *)ac->ac_sigs.l_list[i]))
X			    strlistadd(&s, (char *)ac->ac_sigs.l_list[i]);
X		}
X		/*
X		 * Skip home directory and shell check if not the super-user,
X		 * since not some shells may not be accessible to non
X		 * super-users.
X		 */
X		if (!root)
X			continue;
X		if (!fileexists((char *)ac->ac_dir))
X(void) printf("user \"%s\"'s home directory (%s) not found\n",
X				ac->ac_name, ac->ac_dir);
X		if (stat((char *)ac->ac_dir, &sb) == 0)
X		    if (sb.st_uid != ac->ac_uid)
X(void) printf("user \"%s\" does not own his home directory (%s)\n", ac->ac_name, ac->ac_dir);
X		if (!fileexists((char *)ac->ac_shell))
X(void) printf("user \"%s\" login shell (%s) not found\n",
X				ac->ac_name, ac->ac_shell);
X	}
X	sort_list(&s, pstrcmp);
X	sort_list(&c, pstrcmp);
X	for (indx=0; indx < GroupMapList.l_count; indx++) {
X		gm = (struct groupmap *) GroupMapList.l_list[indx];
X		for (i=0; i < gm->gm_mem.l_count; i++) {
X			if (!userexists((char *)gm->gm_mem.l_list[i])) {
X(void) printf("group \"%s\" contains nonexistent user \"%s\"\n",
X				gm->gm_name, gm->gm_mem.l_list[i]);
X				goop++;
X			}
X		}
X	}
X	(void) time(&now);
X	for (indx=0; indx < ClassList.l_count; indx++) {
X		cs = (struct class *) ClassList.l_list[indx];
X		if (!instrlist(&c, (char *)cs->cs_name)) {
X		    (void) printf("class \"%s\" is empty\n", cs->cs_name);
X		    goop++;
X		}
X		if (cs->cs_exptime && (now >= cs->cs_exptime)) {
X		    (void) printf("class \"%s\" expired %s\n", cs->cs_name,
X				when(cs->cs_exptime));
X		    goop++;
X		}
X	}
X	for (indx=0; indx < SigList.l_count; indx++) {
X		sg = (struct sig *) SigList.l_list[indx];
X		if (!instrlist(&s, (char *)sg->sg_name)) {
X		    (void) printf("sig \"%s\" is empty\n", sg->sg_name);
X		    goop++;
X		}
X		if (sg->sg_exptime && (now >= sg->sg_exptime)) {
X		    (void) printf("sig \"%s\" expired %s\n", sg->sg_name,
X				when(sg->sg_exptime));
X		    goop++;
X		}
X	}
X#ifdef SENDMAIL
X	for (indx=0; indx < AliasList.l_count; indx++) {
X		al = (struct alias *) AliasList.l_list[indx];
X		for (i=0; i < al->al_groups.l_count; i++) {
X		    cp = (char *)al->al_groups.l_list[i];
X		    if (!groupexists(cp)) {
X(void) printf("alias \"%s\" bound to nonexistent group \"%s\"\n", al->al_name, cp);
X			goop++;
X		    }
X		}
X		for (i=0; i < al->al_classes.l_count; i++) {
X		    cp = (char *)al->al_classes.l_list[i];
X		    if (!classexists(cp)) {
X(void) printf("alias \"%s\" bound to nonexistent class \"%s\"\n", al->al_name, cp);
X			goop++;
X		    }
X		}
X		for (i=0; i < al->al_sigs.l_count; i++) {
X		    cp = (char *)al->al_sigs.l_list[i];
X		    if (!sigexists(cp)) {
X(void) printf("alias \"%s\" bound to nonexistent sig \"%s\"\n", al->al_name, cp);
X			goop++;
X		    }
X		}
X	}
X#endif
X	return goop;
X}
X
XListThemThangs()
X
X{
X  struct groupmap *gm;
X  struct class *cs;
X  struct sig *sg;
X  struct account *ac;
X  register int i, j;
X  int memcount;
X
X  if (GroupMapList.l_count) puts("== Groups ==");
X  for (i=0; i < GroupMapList.l_count; i++) {
X    gm = (struct groupmap *) GroupMapList.l_list[i];
X    memcount = gm->gm_mem.l_count;
X    for (j=0; j < AccountList.l_count; j++) {
X      ac = (struct account *) AccountList.l_list[j];
X      if (ac->ac_gid == gm->gm_gid)
X	memcount++;
X    }
X    printf("\"%s\", %d member%s, %d groupie%s\n", gm->gm_name,
X	   memcount - gm->gm_mem.l_count, S(memcount - gm->gm_mem.l_count),
X	   gm->gm_mem.l_count, S(gm->gm_mem.l_count));
X  }
X  if (ClassList.l_count) puts("== Classes ==");
X  for (i=0; i < ClassList.l_count; i++) {
X    memcount = 0;
X    cs = (struct class *) ClassList.l_list[i];
X    for (j=0; j < AccountList.l_count; j++) {
X      ac = (struct account *) AccountList.l_list[j];
X      if (instrlist(&ac->ac_classes, cs->cs_name))
X	memcount++;
X    }
X    printf("\"%s\", %d member%s, ends %s\n", cs->cs_name,
X	   memcount, S(memcount), when(cs->cs_exptime));
X  }
X  if (SigList.l_count) puts("== Sigs ==");
X  for (i=0; i < SigList.l_count; i++) {
X    memcount = 0;
X    sg = (struct sig *) SigList.l_list[i];
X    for (j=0; j < AccountList.l_count; j++) {
X      ac = (struct account *) AccountList.l_list[j];
X      if (instrlist(&ac->ac_sigs, sg->sg_name))
X	memcount++;
X    }
X    printf("\"%s\", %d member%s, ends %s\n", sg->sg_name,
X	   memcount, S(memcount), when(sg->sg_exptime));
X  }
X  return;
X}
@//E*O*F src/report.c//
if test 6824 -ne "`wc -c <'src/report.c'`"; then
    echo shar: error transmitting "'src/report.c'" '(should have been 6824 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 7 (of 8)."
cp /dev/null ark7isdone
DONE=true
for I in 1 2 3 4 5 6 7 8; do
    if test -! f ark${I}isdone; then
        echo "You still need to run archive ${I}."
        DONE=false
    fi
done
case $DONE in
    true)
        echo "You have run all 8 archives."
        echo 'See the README file'
        ;;
esac
##  End of shell archive.
exit 0



More information about the Mod.sources mailing list