v08i043: Account creation/manipulation program, Part03/08

sources-request at mirror.UUCP sources-request at mirror.UUCP
Sat Feb 7 07:11:30 AEST 1987


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

#! /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 3 (of 8)."
# Contents:  man/sigs.n man/vigs.n misc/freeze misc/sorry src/Copyright
#   src/Makefile src/account.c src/account.h src/add.c src/alias.c
#   src/backup.c src/class.c src/class.h src/command.h src/gpa.h
# Wrapped by rs at mirror on Fri Feb  6 15:55:53 1987
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'man/sigs.n'" '(608 characters)'
if test -f 'man/sigs.n' ; then 
  echo shar: will not over-write existing file "'man/sigs.n'"
else
sed 's/^X//' >man/sigs.n <<'@//E*O*F man/sigs.n//'
X.TH SIGS 5
X.SH NAME
Xsigs \- mcp Special Interest Groups
X.SH SYNOPSIS
XSIGFILE
X.SH DESCRIPTION
X.I Sigs
Xcontains the names and descriptions of all the 
X.I mcp(l)
Xsigs.
XThe format for the file is:
X.sp
Xname <sp> description length <sp> expiration time <nl>
X.br
Xdescription...
X.sp
XThe description length is the number of characters in the description
Xwhich beigns immedaitely after the name line.
XThe expiration date is given in the number of seconds since Jan. 1, 1970.
XUnless this file is munged by some calamity, it need never be edited manually
Xas
X.I mcp
Xhandles all modification of it.
X.SH SEE ALSO
X.I mcp(l)
@//E*O*F man/sigs.n//
if test 608 -ne "`wc -c <'man/sigs.n'`"; then
    echo shar: error transmitting "'man/sigs.n'" '(should have been 608 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'man/vigs.n'" '(498 characters)'
if test -f 'man/vigs.n' ; then 
  echo shar: will not over-write existing file "'man/vigs.n'"
else
sed 's/^X//' >man/vigs.n <<'@//E*O*F man/vigs.n//'
X.TH VIGS 5
X.SH NAME
Xvigs \- mcp Very Importans Groups file
X.SH SYNOPSIS
XVIGFILE
X.SH DESCRIPTION
X.I Vigs
Xcontains a list of groups, one per line, that the
X.I mcp(l)
Xprogram is to consider important.
XUsers with numerical group ID's that map to a group that is a
X.I vig
Xget special treatment; they are not considered
X.I deadbeats
Xeven when not a member of a class or sig.  When executing
X.B freeze-user,
Xconfirmation is requested before freezing a member of a
X.I vig.
X.SH SEE ALSO
X.I mcp(l), group(5)
@//E*O*F man/vigs.n//
if test 498 -ne "`wc -c <'man/vigs.n'`"; then
    echo shar: error transmitting "'man/vigs.n'" '(should have been 498 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'misc/freeze'" '(424 characters)'
if test -f 'misc/freeze' ; then 
  echo shar: will not over-write existing file "'misc/freeze'"
else
sed 's/^X//' >misc/freeze <<'@//E*O*F misc/freeze//'
X#!/bin/sh
X
X/bin/cat << Brrrrr!
X
XYour account has been whisked to the mylar deep freeze. There it will
Xremain for a period of one (1) year, at which point your files and other
Xhallucinogens will serve as a repast for David Letterman's hounds.
X
XIf you are outraged by this, curse loudly... someplace else.
X
XBrrrrr!
X
X/usr/ucb/mail -s "climate" tadguy at amon-re kyle at amon-re << Hey!
XGad it's cold in here.
XHey!
X
X/usr/bin/sleep 15
@//E*O*F misc/freeze//
if test 424 -ne "`wc -c <'misc/freeze'`"; then
    echo shar: error transmitting "'misc/freeze'" '(should have been 424 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'misc/sorry'" '(346 characters)'
if test -f 'misc/sorry' ; then 
  echo shar: will not over-write existing file "'misc/sorry'"
else
sed 's/^X//' >misc/sorry <<'@//E*O*F misc/sorry//'
X#!/bin/sh
X
X/bin/cat << Aughghghgh!!!
X
XSorry, your account has been disabled.  Why?  Heh, heh you know why.
XTo make arrangements for restitution to the aggrieved parties, contact
Xtheir attorneys.  For now, go away.
X
XAughghghgh!!!
X
X/usr/ucb/mail -s "the rogue returneth" syskids << Yawn...
XHey!!  Where'd my account go?!
XYawn...
X
X/usr/bin/sleep 15
@//E*O*F misc/sorry//
if test 346 -ne "`wc -c <'misc/sorry'`"; then
    echo shar: error transmitting "'misc/sorry'" '(should have been 346 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/Copyright'" '(385 characters)'
if test -f 'src/Copyright' ; then 
  echo shar: will not over-write existing file "'src/Copyright'"
else
sed 's/^X//' >src/Copyright <<'@//E*O*F src/Copyright//'
X(c) 1986 by Kyle E. Jones
X
XAll sources and documentation of this mcp distribution are
Xincluded in this copyright, but permission is granted to
Xcopy and redistribute any part of this distribution, provided
Xthat this notice is a conspicuous part of the redistribution,
Xand that no part of this distribution is sold.
X
XThis software is distributed 'as is', without warranties of any kind.
@//E*O*F src/Copyright//
if test 385 -ne "`wc -c <'src/Copyright'`"; then
    echo shar: error transmitting "'src/Copyright'" '(should have been 385 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/Makefile'" '(6105 characters)'
if test -f 'src/Makefile' ; then 
  echo shar: will not over-write existing file "'src/Makefile'"
else
sed 's/^X//' >src/Makefile <<'@//E*O*F src/Makefile//'
X#
X# DESTDIR should be where the executable is to be installed
X#
XDESTDIR = /etc
X
X# For Suns:
X#
X# If CLIENTS is defined 'make install' will use rcp and rsh to install
X# mcp on the client machines.
X#
X# CLIENTS = io ganymede callisto amalthea europa 
X
X#
X# Mcp when installed will only be executable by the super-user
X# and members of GROUP.
X#
XGROUP	= account
X
X#
X# Using -O under Sun UNIX 3.0 is not advivsed
X#
XCFLAGS	= -O
X
XSRCS =	init.c\
X	account.c add.c alias.c backup.c bind.c build.c ckp.c class.c\
X	complete.c date.c describe.c disable.c edit.c errmsg.c exists.c\
X	exit.c exits.c freeze.c gpa.c groupmap.c job.c lastlog.c list.c\
X	lists.c load.c main.c mem.c misc.c pause.c pwlock.c range.c\
X	remove.c report.c save.c shell.c sig.c signals.c sort.c tty.c\
X	update.c version.c yesno.c
X
XOBJS =	init.o\
X	account.o add.o alias.o backup.o bind.o build.o ckp.o class.o\
X	complete.o date.o describe.o disable.o edit.o errmsg.o exists.o\
X	exit.o exits.o freeze.o gpa.o groupmap.o job.o lastlog.o list.o\
X	lists.o load.o main.o mem.o misc.o pause.o pwlock.o range.o\
X	remove.o report.o save.o shell.o sig.o signals.o sort.o tty.o\
X	update.o version.o yesno.o
X
XMYH =	account.h alias.h class.h command.h gpa.h groupmap.h\
X	history.h job.h lastlog.h lists.h macros.h mem.h\
X	range.h sig.h sort.h sysdep.h
X
Xmcp:	$(OBJS) xs.o
X	@echo "Loading executable ..."
X	@cc $(CFLAGS) -o mcp $(OBJS) xs.o
X	@size mcp
X
Xinstall:	mcp
X	@echo Installing mcp on `hostname`...
X	@install -c -s -g $(GROUP) -m 750 mcp $(DESTDIR)
X	@echo 'if test -z "$(CLIENTS)" ; then'		> i_script
X	@echo 'exit 0'					>>i_script
X	@echo 'fi'					>>i_script
X	@echo 'for host in $(CLIENTS)'			>>i_script
X	@echo 'do'					>>i_script
X	@echo 'echo Installing mcp on $$host...'	>>i_script
X	@echo 'rcp /etc/mcp $$host:$(DESTDIR)/mcp'	>>i_script
X	@echo 'rsh $$host chmod 750 $(DESTDIR)/mcp'	>>i_script
X	@echo 'rsh $$host chgrp $(GROUP) $(DESTDIR)/mcp'>>i_script
X	@echo 'done'					>>i_script
X	@echo 'exit 0'					>>i_script
X	@sh i_script
X	@rm i_script
X
Xxs.o:	strings
X	xstr
X	cc $(CFLAGS) -c -R xs.c
X
Xversion.o:	version.c
X	cc $(CFLAGS) -c version.c
X
X.c.o:
X	cc $(CFLAGS) -E $< | xstr -c -
X	cc $(CFLAGS) -c x.c
X	mv x.o $@
Xlint:
X	@echo "lint -a -b -h -x $$(SRCS)"
X	@lint -a -b -h -x $(SRCS)
X
Xlintbrush:
X	@PATH=.:$$PATH nitpick $(SRCS)
X	@echo "All source modules successfully linted!"
X
Xtags:	$(SRCS) $(MYH)
X	@echo Making function and typedef tags file...
X	@ctags -t $(SRCS) $(MYH)
X
Xclean:
X	@echo Removing compilation, lint, and installation flotsam...
X	@rm -f $(OBJS) core i_script exdep makedep mcp mon.out gmon.out\
X		strings xs.c xs.o x.c LintErrors
X	
Xdepend:
X	@echo Making header file dependencies...
X	@(grep '^#[ 	]*include[ 	]*"' /dev/null $(SRCS) | sed \
X		-e 's/:[^"]*"\([^"]*\)".*/: \1/' \
X		-e 's/\.c/.o/' | awk \
X	'BEGIN\
X			{ i = 0 }\
X			{ len2 = length($$2) + 1}\
X	FILE != $$1\
X			{ name[i++] = $$1; FILE = $$1;\
X			  line[FILE] = sprintf("\\\n\t%s", $$2);\
X			  currlen = len2 + 8; H = $$2}\
X	FILE == $$1 && currlen + len2 > 75 && H != $$2\
X			{ line[FILE] = sprintf("%s\\\n\t%s",line[FILE], $$2);\
X			  currlen = len2 + 8; H = $$2}\
X	FILE == $$1 && H != $$2\
X			{ line[FILE] = sprintf("%s %s", line[FILE], $$2);\
X			  currlen += len2; }\
X	END\
X			{ for (j = 0; j < i; j++)\
X				printf("%s%s\n", name[j], line[name[j]]); }\
X			' >> makedep)
X	@echo '/^# DO NOT DELETE THIS LINE/+5,$$d' >exdep
X	@echo '$$r makedep' >>exdep
X	@echo 'w' >>exdep
X	@cp Makefile Makefile.b
X	@ex - Makefile < exdep
X	@rm exdep makedep
X
X# DO NOT DELETE THIS LINE -- if you do, you'll be sorrrrrrry!!!
X
X# LINES BEYOND THIS POINT ARE USED BY 'make depend' .
X# IF YOU PUT STUFF HERE, IT WILL GO AWAY.
X
Xinit.o:\
X	sysdep.h macros.h mem.h sort.h lists.h save.h sig.h class.h\
X	account.h command.h groupmap.h range.h alias.h
Xaccount.o:\
X	sysdep.h macros.h mem.h sort.h lists.h account.h
Xadd.o:\
X	sysdep.h macros.h mem.h gpa.h lists.h account.h alias.h class.h\
X	groupmap.h job.h range.h sig.h sort.h save.h
Xalias.o:\
X	sysdep.h mem.h macros.h lists.h alias.h sort.h
Xbackup.o:\
X	sysdep.h mem.h save.h
Xbind.o:\
X	sysdep.h macros.h mem.h gpa.h lists.h account.h alias.h class.h\
X	groupmap.h sig.h sort.h save.h
Xbuild.o:\
X	sysdep.h macros.h mem.h lists.h alias.h account.h groupmap.h\
X	sort.h save.h
Xckp.o:\
X	sysdep.h macros.h mem.h lists.h alias.h account.h class.h sig.h\
X	range.h groupmap.h save.h
Xclass.o:\
X	sysdep.h mem.h lists.h class.h
Xcomplete.o:\
X	sysdep.h macros.h mem.h history.h lists.h
Xdate.o:\
X	macros.h mem.h
Xdescribe.o:\
X	sysdep.h macros.h mem.h lists.h job.h account.h alias.h class.h\
X	groupmap.h range.h sig.h save.h sort.h
Xdisable.o:\
X	sysdep.h mem.h lists.h account.h save.h
Xedit.o:\
X	sysdep.h macros.h mem.h
Xerrmsg.o:\
X	mem.h
Xexists.o:\
X	sysdep.h mem.h lists.h sort.h account.h groupmap.h class.h sig.h
Xexit.o:\
X	mem.h lists.h
Xexits.o:\
X	sysdep.h mem.h
Xfreeze.o:\
X	sysdep.h macros.h mem.h lists.h account.h groupmap.h save.h sort.h
Xgpa.o:\
X	sysdep.h mem.h gpa.h
Xgroupmap.o:\
X	sysdep.h macros.h mem.h lists.h groupmap.h
Xjob.o:\
X	sysdep.h mem.h lists.h job.h
Xlastlog.o:\
X	sysdep.h mem.h save.h
Xlist.o:\
X	sysdep.h macros.h mem.h lists.h account.h alias.h groupmap.h job.h
Xlists.o:\
X	sysdep.h macros.h mem.h gpa.h lists.h sort.h
Xload.o:\
X	sysdep.h macros.h mem.h gpa.h lists.h account.h groupmap.h save.h\
X	sort.h
Xmain.o:\
X	sysdep.h macros.h mem.h command.h
Xmem.o:\
X	mem.h
Xmisc.o:\
X	sysdep.h macros.h mem.h lists.h range.h sort.h
Xpwlock.o:\
X	sysdep.h
Xrange.o:\
X	sysdep.h mem.h lists.h range.h
Xremove.o:\
X	sysdep.h macros.h mem.h lists.h gpa.h sort.h account.h alias.h\
X	groupmap.h class.h job.h range.h sig.h save.h
Xreport.o:\
X	sysdep.h macros.h mem.h lists.h account.h alias.h class.h\
X	groupmap.h range.h sig.h sort.h
Xsave.o:\
X	sysdep.h macros.h mem.h lists.h account.h alias.h class.h sig.h\
X	range.h groupmap.h save.h
Xshell.o:\
X	sysdep.h macros.h mem.h
Xsig.o:\
X	sysdep.h mem.h lists.h sig.h
Xsignals.o:\
X	sysdep.h macros.h
Xsort.o:\
X	sysdep.h mem.h lists.h account.h alias.h class.h command.h sig.h\
X	range.h groupmap.h
Xupdate.o:\
X	sysdep.h macros.h mem.h gpa.h lists.h account.h alias.h class.h\
X	groupmap.h job.h range.h sig.h sort.h save.h
Xyesno.o:\
X	sysdep.h mem.h lists.h gpa.h
@//E*O*F src/Makefile//
if test 6105 -ne "`wc -c <'src/Makefile'`"; then
    echo shar: error transmitting "'src/Makefile'" '(should have been 6105 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/account.c'" '(3317 characters)'
if test -f 'src/account.c' ; then 
  echo shar: will not over-write existing file "'src/account.c'"
else
sed 's/^X//' >src/account.c <<'@//E*O*F src/account.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 "sort.h"
X#include "lists.h"
X#include "account.h"
X
Xextern	struct list AccountList;
X
Xstatic FILE *acf = NULL;
Xstatic addr_t line[LONG_BUF];
Xstatic struct account acct;
X
Xsetacent()
X
X{
X	if ( !acf ) {
X		acf = fopen (ACFILE, "r" );
X		if (!acf) {
X			perr(ACFILE);
X			goodbye(1);
X		}
X	}
X	else
X		rewind( acf );
X	return;
X}
X
Xendacent()
X
X{
X	if ( acf ) {
X		(void) fclose( acf );
X		acf = NULL;
X	}
X}
X
Xaddr
Xacskip(pp,c)
Xaddr pp;
Xregister c;
X{
X	flexaddr p;
X	register char *cp;
X
X	cp = (char *) pp;
X	while( *cp && *cp != c && (*cp != ':' || c != ',') )
X		++cp;
X	if ( *cp == ':' && c != ':' ) {
X		*(p.p_cp = cp) = '\0';
X		return( p.p_ap );
X	}
X	if ( *cp ) *cp++ = '\0';
X	p.p_cp = cp;
X	return( p.p_ap );
X}
X
Xstruct account *
Xgetacent()
X
X{
X	flexaddr p, oldp;
X	register struct list *q;
X
X	if (!acf)
X		setacent();
X	zerolist(&acct.ac_groups);
X	zerolist(&acct.ac_classes);
X	zerolist(&acct.ac_sigs);
X#ifdef SENDMAIL
X	zerolist(&acct.ac_aliases);
X#endif
X	if( !(p.p_cp = fgets( (char *)line, BUFSIZ, acf )) )
X		return(NULL);
X	acct.ac_name = p.p_ap;
X	acct.ac_realname = p.p_ap = acskip(p.p_ap, ':');
X	acct.ac_id = p.p_ap = acskip(p.p_ap, ':');
X	p.p_ap = acskip(p.p_ap,':');
X	acct.ac_uid = atoi(p.p_cp);
X	p.p_ap = acskip(p.p_ap,':');
X	acct.ac_gid = atoi(p.p_cp);
X	(void) acskip(p.p_ap,'\n');
X	oldp.p_ap = p.p_ap = acskip(p.p_ap,':');
X	q = &acct.ac_groups;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = acskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X	p.p_cp++;
X	q = &acct.ac_classes;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = acskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X	p.p_cp++;
X	q = &acct.ac_sigs;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = acskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X#ifdef SENDMAIL
X	p.p_cp++;
X	q = &acct.ac_aliases;
X	while( *p.p_cp ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = acskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X#endif
X	return &acct;
X}
X
Xstruct account *
Xgetacuid(uid)
Xint  uid;
X
X{
X	int found, index;
X
X	index = search_list(&AccountList, (char *)&uid, iacctcmp, &found);
X	if (found)
X		return (struct account *) AccountList.l_list[index];
X	return (struct account *) 0;
X}
X
Xstruct account *
Xgetacid(id)
Xchar *id;
X{
X	int indx;
X	struct account *a;
X
X	for (indx=0; indx < AccountList.l_count; indx++) {
X		a = (struct account *) AccountList.l_list[indx];
X		if (eq(a->ac_id, id))
X			return a;
X	}
X	return (struct account *) 0;
X}
X
Xstruct account *
Xgetacnam(name)
Xchar *name;
X{
X	struct account *a;
X	register int indx;
X
X	if (!userexists(name))
X		return (struct account *) 0;
X	for (indx=0; indx < AccountList.l_count; indx++) {
X		a = (struct account *) AccountList.l_list[indx];
X		if (eq(a->ac_name, name))
X			return a;
X	}
X	return (struct account *) 0;
X}
X
X/*
X * Do a simply format check of the accounts file.
X */
Xint
Xacck()
X
X{
X	FILE *f;
X	char b[BUFSIZ];
X
X	f = fopen(ACFILE, "r");
X	if (f == NULL) {
X		err1("can't open %s (read)", ACFILE);
X		return 0;
X	}
X	while (fgets(b, BUFSIZ, f) != NULL) {
X		if (coloncount(b) != 8) {
X			err1("%s: badly formed line", ACFILE);
X			return 0;
X		}
X	}
X	(void) fclose(f);
X	return 1;
X}
@//E*O*F src/account.c//
if test 3317 -ne "`wc -c <'src/account.c'`"; then
    echo shar: error transmitting "'src/account.c'" '(should have been 3317 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/account.h'" '(636 characters)'
if test -f 'src/account.h' ; then 
  echo shar: will not over-write existing file "'src/account.h'"
else
sed 's/^X//' >src/account.h <<'@//E*O*F src/account.h//'
Xstruct account {
X	int	ac_uid;
X	int	ac_gid;
X	addr	ac_name;			/* login name */
X	addr	ac_gecos;			/* pw_gecos */
X	addr	ac_realname;			/* in real life... */
X	addr	ac_passwd;			/* encrypted password */
X	addr	ac_id;				/* unqiue id (e.g. SSN) */
X	addr	ac_dir;				/* home directory */
X	addr	ac_shell;			/* login shell */
X	struct 	list 	ac_groups;
X	struct	list	ac_classes;
X	struct	list	ac_sigs;
X#ifdef SENDMAIL
X	/*
X	 * Alias memberships that were not obtained indirectly through
X	 * class, sig, or group bindings.
X	 */
X	struct	list	ac_aliases;
X#endif
X	struct	lastlog ac_ll;
X};
X
Xstruct account *getacent(), *getacuid(), *getacid(), *getacnam();
@//E*O*F src/account.h//
if test 636 -ne "`wc -c <'src/account.h'`"; then
    echo shar: error transmitting "'src/account.h'" '(should have been 636 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/add.c'" '(21617 characters)'
if test -f 'src/add.c' ; then 
  echo shar: will not over-write existing file "'src/add.c'"
else
sed 's/^X//' >src/add.c <<'@//E*O*F src/add.c//'
X/***************************************************************\
X* 							        *
X* 	add.c						        *
X* 							        *
X* Routines to add various things, users, groups, classes, etc.  *
X* 							        *
X\***************************************************************/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <strings.h>
X#include <ctype.h>
X#include <lastlog.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#ifdef SENDMAIL
X#include "alias.h"
X#endif
X#include "class.h"
X#include "groupmap.h"
X#include "job.h"
X#include "range.h"
X#include "sig.h"
X#include "sort.h"
X#include "save.h"
X
X#define DAY	(4*21600)
X
X#ifdef SENDMAIL
Xextern	struct list AliasList, Aliases;
X#endif
Xextern	struct list AccountList, Users, ClassList, Classes, GroupMapList;
Xextern	struct list Groups, RangeList, Ranges, Sigs, SigList, Vigs, Shells;
Xextern	struct list Null_List;
Xextern	int ModBits, validint();
Xextern	addr gethomedir();
Xextern	addr makeusername(), DEF_SHELL;
Xextern	char *crypt(), *mktemp(), *sprintf(), *makepass(), *when();
Xextern	time_t choosedate();
X
Xstatic	char *XXXXXX = "/mcpXXXXXX";
Xstatic	char desc[DESCSIZE+1];
X
Xstatic	char *idl[1] = { "exception" };
Xstatic	char *pwl[3] = { "generate", "none", "unused" };
Xstatic	char *rnl[1];
Xstatic	char *mdl[2] = { "exclusive", "shared" };
X
Xstruct	list idlist = {	1, 1, (addr *)idl };
Xstruct	list pwlist = { 3, 3, (addr *)pwl };
Xstruct	list rnlist = { 1, 1, (addr *)rnl };
Xstruct	list mdlist = { 2, 2, (addr *)mdl };
X
X#ifdef SENDMAIL
X/*
X * Add an alias
X */
Xaddalias(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct alias al;
X	struct account *ac;
X	addr *addressv;
X	int cc;
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 <name>", (char *)v[0]);
X		return;
X	}
X	if (aliasexists((char *)v[1])) {
X		err1("%s: alias exists", (char *)v[1]);
X		return;
X	}
X	addressv = get_gpa(257);
X	GetLine("Addresses: ", 256, &cc, addressv, &Null_List);
X
X	critical();
X	savestr(&al.al_name, (char *)v[1]);
X	zerolist(&al.al_addresses);
X	zerolist(&al.al_classes);
X	zerolist(&al.al_sigs);
X	zerolist(&al.al_groups);
X	for (i=0; i < cc; i++) {
X		strlistadd(&al.al_addresses, (char *)addressv[i]);
X		ac = getacnam((char *)addressv[i]);
X		if (ac)
X			strlistadd(&ac->ac_aliases, (char *)addressv[i]);
X	}
X	sort_list(&al.al_addresses, pstrcmp);
X	strlistadd(&Aliases, (char *)v[1]);
X	genlistadd(&AliasList, (addr)&al, sizeof (struct alias));
X	sort_list(&Aliases, pstrcmp);
X	sort_list(&AliasList, aliascmp);
X	ModBits |= AL;
X	puts("added");
X	non_critical();
X
X	return;
X}
X#endif
X	
X/*
X * Add a class
X */
Xaddclass(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct class cs;
X	struct stat statbuf;
X	char tempf[MEDIUM_BUF], errmsg[LONG_BUF];
X	FILE *f, *fopen();
X	time_t now, time();
X	int tries, i, ch;
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	if (classexists((char *)v[1])) {
X		err1("%s: class exists", (char *)v[1]);
X		return;
X	}
X	if (yesno("Should the class expire? ") == 0)
X		cs.cs_exptime = (time_t) 0;
X	else {
X		(void) time(&now);
X		err("Set the expiration date.");
X		cs.cs_exptime = choosedate(now);
X		(void) printf("Ends %s\n", when(cs.cs_exptime));
X	}
X	(void) strcpy(tempf, TMPDIR);
X	(void) strcat(tempf, XXXXXX);
X	(void) mktemp(tempf);
X	tries = 0;
Xedit_it:
X	tries++;
X	f = fopen(tempf, "w");
X	if (f == NULL) {
X		err1("%s: cannot open (write)", tempf);
X		return;
X	}
X	(void) fprintf(f, "Instructor: \n\n");
X	(void) fprintf(f, "...\n");
X	(void) fclose(f);
Xre_edit:
X	edit(tempf);
X	if (stat(tempf, &statbuf) == -1) {
X		perr(tempf);
X		if (tries < 5) {
X			sleep(2);
X			goto edit_it;
X		}
X		else {
X			err1("%s aborted", (char *)v[0]);
X			(void) unlink(tempf);
X			return;
X		}
X	}
X	if (statbuf.st_size > DESCSIZE) {
X		(void)sprintf(errmsg, "description is %d characters too long",
X			DESCSIZE - statbuf.st_size);
X		err(errmsg);
X		sleep(2);
X		goto re_edit;
X	}
X
X	critical();
X	f = fopen(tempf, "r");
X	if (f == NULL) {
X		err1("%s: cannot open (read)", tempf);
X		non_critical();
X		return;
X	}
X	savestr(&cs.cs_name, (char *)v[1]);
X	i = 0;
X	while ((ch = getc(f)) != EOF)
X		desc[i++] = (char) ch;
X	desc[i] = '\0';
X	cs.cs_dsize = i;
X	savestr(&cs.cs_desc, desc);
X	(void) fclose(f);
X#ifdef SENDMAIL
X	zerolist(&cs.cs_aliases);
X#endif
X	genlistadd(&ClassList, (addr) &cs, sizeof (struct class));
X	strlistadd(&Classes, cs.cs_name);
X	sort_list(&ClassList, classcmp);
X	sort_list(&Classes, pstrcmp);
X	(void) unlink(tempf);
X	ModBits |= CS;
X	puts("added");
X	non_critical();
X
X	return;
X}
X
X/*
X * Add a group
X */
Xaddgroup(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct groupmap gm;
X	char prompt[SHORT_BUF];
X	addr *gidv;
X	int cc, gid;
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 <name>", (char *)v[0]);
X		return;
X	}
X	if (groupexists((char *)v[1])) {
X		err1("%s: group exists", (char *)v[1]);
X		return;
X	}
X	gm.gm_gid = nextgid();
X	(void) sprintf(prompt, "Gid [%d]: ", gm.gm_gid);
X	gidv = get_gpa(2);
X	do {
X	    GetLine(prompt, 1, &cc, gidv, &Null_List);
X	    if (cc) {
X		if (!validint((char *)*gidv)) {
X		    err1("%s makes no sense to me", (char *)*gidv);
X		    continue;
X		}
X		gid = atoi((char *)*gidv);
X		if (gidexists(gid))
X		    err("that gid is taken");
X		else {
X		    gm.gm_gid = gid;
X		    break;
X		}
X	    }
X	    else
X			break;
X	} while (clear_gpa(gidv, 2));
X
X	critical();
X	savestr(&gm.gm_name, (char *)v[1]);
X	savestr(&gm.gm_passwd, "*");
X	zerolist(&gm.gm_mem);
X#ifdef SENDMAIL
X	zerolist(&gm.gm_aliases);
X#endif
X	genlistadd(&GroupMapList, (addr) &gm, sizeof (struct groupmap));
X	sort_list(&GroupMapList, gmapcmp);
X	strlistadd(&Groups, gm.gm_name);
X	sort_list(&Groups, pstrcmp);
X	ModBits |= GR;
X	puts("added");
X	non_critical();
X
X	return;
X}
X
Xint nextgid()
X
X{
X	register int i, next = 0;
X	struct groupmap *gm;
X
X	for (i=0; i<GroupMapList.l_count; i++) {
X		gm = (struct groupmap *) GroupMapList.l_list[i];
X		if (gm->gm_gid > next)
X			return next;
X		/*
X		 * Since gid's may be shared (gag) by two or more group names
X		 * the seemingly obvious next++ actually must be...
X		 */
X		next = gm->gm_gid + 1;
X	}
X	return next;
X}
X
X/*
X * Add a range
X */
Xaddrange(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct range r, *rg;
X	char prompt[SHORT_BUF];
X	addr *fromv, *tov, *modev;
X	int cc, 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 <name>", (char *)v[0]);
X		return;
X	}
X	if (!groupexists((char *)v[1])) {
X		err1("%s: no such group", (char *)v[1]);
X		return;
X	}
X	(void) strcpy(prompt, "From: ");
X	fromv = get_gpa(2);
X	do {
X		GetLine(prompt, 1, &cc, fromv, &Null_List);
X		if (cc && !validint((char *)*fromv)) {
X			cc = 0;
X			continue;
X		}
X	} while (cc == 0 && clear_gpa(fromv, 2));
X
X	(void) strcpy(prompt, "To  : ");
X	tov = get_gpa(2);
X	do {
X		GetLine(prompt, 1, &cc, tov, &Null_List);
X		if (cc && !validint((char *)*tov)) {
X			cc = 0;
X			continue;
X		}
X	} while (cc == 0 && clear_gpa(tov, 2));
X
X	(void) strcpy(prompt, "Mode: ");
X	modev = get_gpa(2);
X	do {
X		GetLine(prompt, 1, &cc, modev, &mdlist);
X	} while (cc == 0 && clear_gpa(modev, 2));
X
X	if (eq(*modev, "shared"))
X		r.rg_mode = RG_SHARED;
X	else if (eq(*modev, "exclusive"))
X		r.rg_mode = RG_EXCLUSIVE;
X	else {
X		err1("%s: unknown mode", (char *)*modev);
X		return;
X	}
X	r.rg_from = atoi((char *)*fromv);
X	r.rg_to = atoi((char *)*tov);
X
X	for (indx=0; indx < RangeList.l_count; indx++) {
X		rg = (struct range *) RangeList.l_list[indx];
X		if (rg->rg_mode == RG_SHARED && r.rg_mode == RG_SHARED)
X			continue;
X		if (INRANGE(r.rg_from, rg->rg_from, rg->rg_to)) {
X			err1("conflicts with range of group %s", rg->rg_name);
X			return;
X		}
X		if (INRANGE(r.rg_to, rg->rg_from, rg->rg_to)) {
X			err1("conflicts with range of group %s", rg->rg_name);
X			return;
X		}
X	}
X
X	critical();
X	savestr(&r.rg_name, (char *)v[1]);
X	genlistadd(&RangeList, (addr) &r, sizeof (struct range));
X	sort_list(&RangeList, rangecmp);
X	strlistadd(&Ranges, (char *)v[1]);
X	sort_list(&Ranges, pstrcmp);
X	ModBits |= RG;
X	puts("added");
X	non_critical();
X	return;
X}
X
X/*
X * Add a sig
X */
Xaddsig(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct sig sg;
X	struct stat statbuf;
X	FILE *f, *fopen();
X	time_t now, time();
X	int tries, i, ch;
X	char tempf[SHORT_BUF+1], errmsg[LONG_BUF];
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 <name>", (char *)v[0]);
X		return;
X	}
X	if (sigexists((char *)v[1])) {
X		err1("%s: sig exists", (char *)v[1]);
X		return;
X	}
X	if (yesno("Should the sig expire? ") == 0)
X		sg.sg_exptime = (time_t) 0;
X	else {
X		(void) time(&now);
X		err("Set the expiration date.");
X		sg.sg_exptime = choosedate(now);
X		(void) printf("Sig ends %s\n", when(sg.sg_exptime));
X	}
X	(void) strcpy(tempf, TMPDIR);
X	(void) strcat(tempf, XXXXXX);
X	(void) mktemp(tempf);
X	tries = 0;
Xedit_it:
X	tries++;
X	f = fopen(tempf, "w");
X	if (f == NULL) {
X		err1("%s: cannot open (write)", tempf);
X		return;
X	}
X	(void) fprintf(f, "Guru: \n\n");
X	(void) fprintf(f, "...\n");
X	(void) fclose(f);
Xre_edit:
X	edit(tempf);
X	if (stat(tempf, &statbuf) == -1) {
X		perr(tempf);
X		if (tries < 5) {
X			sleep(2);
X			goto edit_it;
X		}
X		else {
X			err1("%s aborted", (char *)v[0]);
X			(void) unlink(tempf);
X			return;
X		}
X	}
X	if (statbuf.st_size > DESCSIZE) {
X		(void) sprintf(errmsg, 
X				"description is %d characters too long",
X				DESCSIZE - statbuf.st_size);
X		err(errmsg);
X		sleep(2);
X		goto re_edit;
X	}
X
X	critical();
X	f = fopen(tempf, "r");
X	if (f == NULL) {
X		err1("%s: cannot open (read)", tempf);
X		non_critical();
X		return;
X	}
X	savestr(&sg.sg_name, (char *)v[1]);
X	i = 0;
X	while ((ch = getc(f)) != EOF)
X		desc[i++] = (char) ch;
X	desc[i] = '\0';
X	sg.sg_dsize = i;
X	savestr(&sg.sg_desc, desc);
X	(void) fclose(f);
X#ifdef SENDMAIL
X	zerolist(&sg.sg_aliases);
X#endif
X	genlistadd(&SigList, (addr) &sg, sizeof (struct sig));
X	strlistadd(&Sigs, sg.sg_name);
X	sort_list(&SigList, sigcmp);
X	sort_list(&Sigs, pstrcmp);
X	(void) unlink(tempf);
X	ModBits |= SG;
X	puts("added");
X	non_critical();
X
X	return;
X}
X
X#ifdef SENDMAIL
Xaddtoalias(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct alias *al;
X	struct account *ac;
X	addr *addressv;
X	int cc, added = 0, notes = 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, &Null_List);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X	for (indx=0; indx < cc; indx++) {
X	    ac = getacnam((char *)addressv[indx]);
X	    if (ac) {
X		if (!instrlist(&ac->ac_aliases, (char *)v[1])) {
X		    strlistadd(&ac->ac_aliases, (char *)v[1]);
X		    sort_list(&ac->ac_aliases, pstrcmp);
X		    ModBits |= AC;
X		}
X		else {
X		    err1("%s: already in alias", (char *)ac->ac_name);
X		    continue;
X		}
X	    }
X	    if (!instrlist(&al->al_addresses, (char *)addressv[indx])) {
X		strlistadd(&al->al_addresses, (char *)addressv[indx]);
X		added++;
X	    }
X	    else if (!ac)
X		err1("%s: already in alias", (char *)addressv[indx]);
X	    else {
X		err1("%s: unique membership noted", (char *)ac->ac_name);
X		notes++;
X	    }
X	}
X	if (added) {
X		sort_list(&al->al_addresses, pstrcmp);
X		ModBits |= AL;
X		(void) printf("%d added\n", added);
X	}
X	else if (!notes)
X		err("no change");
X	non_critical();
X
X	return;
X}
X#endif
X
Xaddtoclass(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct account *ac;
X	struct class *cs;
X	addr *userv;
X	int cc, added = 0;
X	register int indx;
X#ifdef SENDMAIL
X	struct alias *al;
X	register int j;
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 <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	for (indx=0; indx < cc; indx++) {
X		ac = getacnam((char *)userv[indx]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[indx]);
X			continue;
X		}
X		if (instrlist(&ac->ac_classes, (char *)v[1])) {
X			err1("%s: already is in class\n",
X				(char *)userv[indx]);
X			continue;
X		}
X		strlistadd(&ac->ac_classes, (char *)v[1]);
X		sort_list(&ac->ac_classes, pstrcmp);
X#ifdef SENDMAIL
X		for (j=0; j < cs->cs_aliases.l_count; j++) {
X		    al = getalnam((char *)cs->cs_aliases.l_list[j]);
X		    if (!al) continue;	/* trouble */
X		    if (!instrlist(&al->al_addresses, (char *)ac->ac_name)) {
X			strlistadd(&al->al_addresses, (char *)ac->ac_name);
X			sort_list(&al->al_addresses, pstrcmp);
X			ModBits |= AL;
X		    }
X		}
X#endif
X		added++;
X	}
X	if (added) {
X	    ModBits |= AC;
X	    (void) printf("%d added\n", added);
X	}
X	else
X	    err("no change");
X	non_critical();
X
X	return;
X}
X
Xaddtogroup(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct account *ac;
X	struct groupmap *gm;
X	addr *userv;
X	int cc, added = 0;
X	register int indx;
X#ifdef SENDMAIL
X	struct alias *al;
X	register int j;
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 <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, &Users);
X	if (cc == 0) {
X		err("no change");
X		return;
X	}
X
X	critical();
X	for (indx=0; indx < cc; indx++) {
X		if (instrlist(&gm->gm_mem, (char *)userv[indx])) {
X			err1("%s: is in group", (char *)userv[indx]);
X			continue;
X		}
X		ac = getacnam((char *)userv[indx]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[indx]);
X			continue;
X		}
X		strlistadd(&ac->ac_groups, (char *)v[1]);
X		strlistadd(&gm->gm_mem, (char *)userv[indx]);
X		sort_list(&ac->ac_groups, pstrcmp);
X#ifdef SENDMAIL
X		for (j=0; j < gm->gm_aliases.l_count; j++) {
X		    al = getalnam((char *)gm->gm_aliases.l_list[j]);
X		    if (!al) continue;	/* trouble */
X		    if (!instrlist(&al->al_addresses, (char *)ac->ac_name)) {
X			strlistadd(&al->al_addresses, (char *)ac->ac_name);
X			sort_list(&al->al_addresses, pstrcmp);
X			ModBits |= AL;
X		    }
X		}
X#endif
X		added++;
X	}
X	if (added) {
X		ModBits |= AC|GR;
X		sort_list(&gm->gm_mem, pstrcmp);
X		(void) printf("%d added\n", added);
X	}
X	else
X		err("no change");
X	non_critical();
X
X	return;
X}
X
Xaddtosig(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct account *ac;
X	struct sig *sg;
X	addr *userv;
X	int cc, added = 0;
X	register int indx;
X#ifdef SENDMAIL
X	struct alias *al;
X	register int j;
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 <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
X	for (indx=0; indx < cc; indx++) {
X		ac = getacnam((char *)userv[indx]);
X		if (!ac) {
X			err1("%s: no such user", (char *)userv[indx]);
X			continue;
X		}
X		if (instrlist(&ac->ac_sigs, (char *)v[1])) {
X			err1("%s: already is in sig", (char *)userv[indx]);
X			continue;
X		}
X		strlistadd(&ac->ac_sigs, (char *)v[1]);
X		sort_list(&ac->ac_sigs, pstrcmp);
X#ifdef SENDMAIL
X		for (j=0; j < sg->sg_aliases.l_count; j++) {
X		    al = getalnam((char *)sg->sg_aliases.l_list[j]);
X		    if (!al) continue;	/* trouble */
X		    if (!instrlist(&al->al_addresses, (char *)ac->ac_name)) {
X			strlistadd(&al->al_addresses, (char *)ac->ac_name);
X			sort_list(&al->al_addresses, pstrcmp);
X			ModBits |= AL;
X		    }
X		}
X#endif
X		added++;
X	}
X	if (added) {
X	    ModBits |= AC;
X	    (void) printf("%d added\n", added);
X	}
X	else
X	    err("no change");
X	non_critical();
X
X	return;
X}
X
Xadduser(c, v)
Xint c;
Xaddr *v;
X
X{
X	struct account *aa;
X	struct groupmap *gm;
X	addr *realnamev, *idv, *passwdv, *groupv, *uidv, *shellv;
X	addr username, def_dir, *dirv;
X	addr shell, dir;
X	addr password[SHORT_BUF];
X	char prompt[MEDIUM_BUF], prompt2[MEDIUM_BUF], *salt;
X	int cc, uid, n;
X	addr_t cap[SHORT_BUF];
X
X	if ( c > 2 ) {
X		err1("%s: too many arguments", (char *)v[0]);
X		return;
X	}
X	if (c > 1 && userexists((char *)v[1])) {
X		err1("%s: user exists", (char *) v[1]);
X		return;
X	}
X	if (c > 1) {
X		(void) strcpy((char *)cap, (char *)v[1]);
X		capitalize((char *)cap);
X		rnlist.l_count = 1;
X		rnlist.l_list[0] = cap;
X	}
X	else
X		rnlist.l_count = 0;
X	
X	realnamev = get_gpa(17);
X	do {
X		GetLine("Real Name: ", 16, &cc, realnamev, &rnlist);
X	} while (cc == 0 && clear_gpa(realnamev, 17));
X
X	/*
X	 * If we were handed a username, take it.  If not, we must manufacture
X	 * one from the Real Name.
X	 */
X	if (c > 1)
X		username = v[1];
X	else {
X		username = makeusername(cc, realnamev);
X		(void) printf("login name is \"%s\"\n", username);
X	}
X
X	/*
X	 * Unique identification, like SSN
X	 */
X	idv = get_gpa(2);
X	do {
X		GetLine("Id: ", 1, &cc, idv, &idlist);
X	} while (cc == 0 && clear_gpa(idv, 2));
X	if (!eq(*idv, "exception") && (aa = getacid((char *)*idv))) {
X		(void) sprintf(prompt, "%s shares that id.  continue? [no] ",
X			(char *)aa->ac_name);
X		if (no(prompt))
X			return;
X	}
X
X	/*
X	 * Give the user a password
X	 */
X	(void) sprintf(prompt, "Password [%s]: ", *idv);
X	passwdv = get_gpa(2);
X	GetLine(prompt, 1, &cc, passwdv, &pwlist);
X	if (cc)
X		if (eq(*passwdv, "none"))
X			(void) strcpy((char *)password, "");
X		else if (eq(*passwdv, "unused"))
X			(void) strcpy((char *)password, "*");
X		else if (eq(*passwdv, "generate")) {
X			(void) strcpy((char *)password, makepass());
X			(void) printf("password is \"%s\"\n", password);
X		}
X		else {
X			salt = CRYPT_SALT;
X			(void) strcpy((char *)password,
X					crypt((char *)*passwdv, salt));
X		}
X	else {
X		salt = CRYPT_SALT;
X		(void) strcpy((char *)password, crypt((char *)*idv, salt));
X	}
X
X	(void) sprintf(prompt, "Group [%s]: ", DEF_GROUP);
X	groupv = get_gpa(2);
X	do {
X		GetLine(prompt, 1, &cc, groupv, &Groups);
X		if (cc) {
X			gm = getgmnam((char *)*groupv);
X			if (!gm)
X				err1("%s: no such group", (char *)*groupv);
X			else
X				break;
X		}
X		else {
X			gm = getgmnam(DEF_GROUP);
X			if (!gm) {
X				err1("%s: no such group", DEF_GROUP);
X				continue;
X			}
X			break;
X		}
X	} while (clear_gpa(groupv, 2));
X
X	uid = findnextuid(gm->gm_name);
X	if (uid == NOMORE) {
X		err1("no more free uids for group %s!",
X			gm->gm_name);
X		return;
X	}
X	(void) sprintf(prompt, "Uid [%d]: ", uid);
X	uidv = get_gpa(2);
X	do {
X	    GetLine(prompt, 1, &cc, uidv, &Null_List);
X	    if (cc) {
X		if (!validint((char *)*uidv)) {
X		    err1("%s makes no sense to me", (char *)*uidv);
X		    continue;
X		}
X		n = atoi((char *)*uidv);
X		aa = getacuid(n);
X		if (aa) {
X		    (void) sprintf(prompt2,
X					"%s shares that uid, use anyway? ",
X					aa->ac_name);
X		    if (yesno(prompt2)) {
X			uid = n;
X			break;
X		    }
X		}
X		else {
X		    uid = n;
X		    break;
X		}
X	    }
X	    else
X			break;
X	} while (clear_gpa(uidv, 2));
X
X	/*
X	 * Shell
X	 */
X	(void) sprintf(prompt, "Shell [%s]: ", DEF_SHELL);
X	shellv = get_gpa(2);
X	GetLine(prompt, 1, &cc, shellv, &Shells);
X	shell = (cc == 0) ? DEF_SHELL : *shellv;
X
X	/*
X	 * Home directory.
X	 */
X	def_dir = gethomedir((char *)username, gm->gm_name);
X	(void) sprintf(prompt, "Home [%s]: ", def_dir);
X	dirv = get_gpa(2);
X	GetFilenames(prompt, 1, &cc, dirv);
X	dir = (cc == 0) ? def_dir : *dirv;
X
X	addu(uid, gm->gm_gid, username, glob(realnamev),
X		(addr)password, *idv, dir, shell);
X
X#ifndef DOFILES
X	err("Don't forget to create this user's directory!");
X#endif
X	puts("added");
X	return;
X}
X
Xaddvig(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 <name>", (char *)v[0]);
X		return;
X	}
X	if (!groupexists((char *)v[1])) {
X		err1("%s: no such group", (char *)v[1]);
X		return;
X	}
X
X	critical();
X	strlistadd(&Vigs, (char *)v[1]);
X	sort_list(&Vigs, pstrcmp);
X	ModBits |= VG;
X	puts("added");
X	non_critical();
X
X	return;
X}
X
X
Xaddu(uid, gid, username, realname, password, id, dir, shell)
Xint uid, gid;
Xaddr username, realname, password, id, dir, shell;
X
X{
X	struct account ac;
X#ifdef SENDMAIL
X	struct groupmap *gm;
X	struct alias *al;
X	register int j;
X#endif
X#ifdef DOFILES
X	int zero = 0;
X#endif
X
X	critical();
X#ifdef SENDMAIL
X	zerolist(&ac.ac_aliases);
X#endif
X	zerolist(&ac.ac_groups);
X	zerolist(&ac.ac_sigs);		zerolist(&ac.ac_classes);
X	ac.ac_uid = uid;
X	ac.ac_gid = gid;
X	savestr((char **)&ac.ac_name, (char *)username);
X	savestr((char **)&ac.ac_realname, (char *)realname);
X	savestr((char **)&ac.ac_gecos, (char *)realname);
X	savestr((char **)&ac.ac_passwd, (char *)password);
X	savestr((char **)&ac.ac_id, (char *)id);
X	savestr((char **)&ac.ac_dir, (char *)dir);
X	savestr((char **)&ac.ac_shell, (char *)shell);
X	ac.ac_ll.ll_time = (time_t) 0;
X	(void) strncpy(ac.ac_ll.ll_line, "", sizeof ac.ac_ll.ll_line);
X	(void) strncpy(ac.ac_ll.ll_host, "", sizeof ac.ac_ll.ll_host);
X	genlistadd(&AccountList, (addr) &ac, sizeof (struct account));
X	sort_list(&AccountList, acctcmp);
X	strlistadd(&Users, (char *)ac.ac_name);
X	sort_list(&Users, pstrcmp);
X#ifdef DOFILES
X	add_job(JB_MKDIR, ac.ac_dir, (addr)&ac.ac_uid,
X		(addr)&zero);
X#endif
X	add_job(JB_LASTLOG, (addr) &ac.ac_uid,
X		(addr)&ac.ac_ll, NIL);
X	ModBits |= (AC|PW);
X#ifdef SENDMAIL
X	gm = getgmgid(ac.ac_gid);
X	for (j=0; j < gm->gm_aliases.l_count; j++) {
X	    al = getalnam((char *)gm->gm_aliases.l_list[j]);
X	    if (!al) continue;	/* trouble */
X	    if (!instrlist(&al->al_addresses, (char *)ac.ac_name)) {
X		strlistadd(&al->al_addresses, (char *)ac.ac_name);
X		sort_list(&al->al_addresses, pstrcmp);
X		ModBits |= AL;
X	    }
X	}
X#endif
X	non_critical();
X
X	return;
X}
@//E*O*F src/add.c//
if test 21617 -ne "`wc -c <'src/add.c'`"; then
    echo shar: error transmitting "'src/add.c'" '(should have been 21617 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/alias.c'" '(3382 characters)'
if test -f 'src/alias.c' ; then 
  echo shar: will not over-write existing file "'src/alias.c'"
else
sed 's/^X//' >src/alias.c <<'@//E*O*F src/alias.c//'
X#include <stdio.h>
X#include <ctype.h>
X#include "sysdep.h"
X
X#ifdef SENDMAIL
X#include "mem.h"
X#include "macros.h"
X#include "lists.h"
X#include "alias.h"
X#include "sort.h"
X
Xextern	addr acskip();
X
X#define	alskip acskip
X
Xextern	struct list AliasList;
X
Xstatic struct alias aka;
Xstatic FILE *alf = NULL;
Xstatic FILE *bindf = NULL;
Xstatic char line[BUFSIZ];
X
Xsetalent()
X
X{
X	if (alf == NULL) {
X		alf = fopen(ALIASFILE, "r");
X		if (alf == NULL) {
X			perr(ALIASFILE);
X			goodbye(1);
X		}
X	}
X	rewind(alf);
X	if (bindf == NULL) {
X		bindf = fopen(ALBIND, "r");
X		if (bindf == NULL) {
X			perr(ALBIND);
X			goodbye(1);
X		}
X	}
X	rewind(bindf);
X	return;
X}
X
Xendalent()
X
X{
X	if (alf != NULL) {
X		(void) fclose(alf);
X		alf = NULL;
X	}
X	if (bindf != NULL) {
X		(void) fclose(bindf);
X		bindf = NULL;
X	}
X	return;
X}
X
Xstatic
Xint getch()
X
X{
X	int c;
X
X	for (;;) {
X		c = getc(alf);
X		if (c == '#') {
X			while ((c = getc(alf)) != '\n' && c != EOF)
X				;
X			return c;
X		}
X		break;
X	}
X	return c;
X}
X
Xstruct alias *
Xgetalent()
X
X{
X	int c;
X	register int i = 0;
X	register struct list *q;
X	static char name[MEDIUM_BUF], address[LONG_BUF];
X	flexaddr p, oldp;
X	int quoteopen = 0;
X
X	zerolist(&aka.al_addresses);
X	zerolist(&aka.al_groups);
X	zerolist(&aka.al_classes);
X	zerolist(&aka.al_sigs);
X	aka.al_name = (char *)0;
X	while ((c = getch()) != EOF) {
X		if (c == '\n')
X			if (aka.al_name) {
X				c = getch();
X				if (!isspace(c) || c == '\n') {
X					(void) ungetc(c, alf);
X					break;
X				}
X				else
X					continue;
X			}
X			else
X				continue;
X		if (isspace(c) && !quoteopen)
X			continue;
X		if (c == '"')
X			quoteopen = !quoteopen;
X		if (!aka.al_name) {
X			if (c == ':') {
X				name[i] = '\0';
X				aka.al_name = name;
X				i = 0;
X			}
X			else
X				name[i++] = (char) c;
X			continue;
X		}
X		if (c == ',' && i != 0) {
X			address[i] = '\0';
X			strlistadd(&aka.al_addresses, address);
X			i = 0;
X		}
X		else if (c == ',' && i == 0)
X			continue;
X		else
X			address[i++] = (char) c;
X	}
X	if (!aka.al_name)
X		return (struct alias *) 0;
X	address[i] = '\0';
X	if (i > 0)
X		strlistadd(&aka.al_addresses, address);
X	sort_list(&aka.al_addresses, pstrcmp);
X	/*
X	 * Now get the group, class, and sig bindings
X	 */
X	p.p_cp = fgets(line, BUFSIZ, bindf);
X	if (!p.p_cp) {
X	   err1("getalent(): %s: unexpected EOF", ALBIND);
X	   err1("getalent(): %s corrupted, gagging... returning 0", ALBIND);
X	   return (struct alias *) 0;
X	}
X	p.p_ap = alskip(p.p_ap, ':');
X	if (!eq(line, aka.al_name)) {
X	   err("getalent(): alias name mismatch");
X	   err1("getalent(): %s corrupted, gagging... returning 0", ALBIND);
X	   return (struct alias *) 0;
X	}
X	(void) alskip(p.p_ap, '\n');
X	oldp.p_ap = p.p_ap;
X	q = &aka.al_groups;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = alskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X	p.p_cp++;
X	q = &aka.al_classes;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = alskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X	p.p_cp++;
X	q = &aka.al_sigs;
X	while( *p.p_cp && *p.p_cp != ':' ) {
X		oldp.p_ap = p.p_ap;
X		p.p_ap = alskip(p.p_ap,',');
X		strlistadd(q, oldp.p_cp);
X	}
X	sort_list(q, pstrcmp);
X	return &aka;
X}
X
Xstruct alias *
Xgetalnam(name)
Xchar *name;
X
X{
X	int found;
X	register int indx;
X
X	indx = search_list(&AliasList, name, saliascmp, &found);
X	if (found)
X		return (struct alias *) AliasList.l_list[indx];
X	return (struct alias *) 0;
X}
X
X#endif
@//E*O*F src/alias.c//
if test 3382 -ne "`wc -c <'src/alias.c'`"; then
    echo shar: error transmitting "'src/alias.c'" '(should have been 3382 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/backup.c'" '(2195 characters)'
if test -f 'src/backup.c' ; then 
  echo shar: will not over-write existing file "'src/backup.c'"
else
sed 's/^X//' >src/backup.c <<'@//E*O*F src/backup.c//'
X/**************************************************************************\
X* 									   *
X* 	backup.c							   *
X* 									   *
X* Before the account files are modified mcp back them up.  THe files are   *
X* backed up only once per mcp session; if you save-changes more than once  *
X* the backups will still contain the files as they were when the mcp	   *
X* session started, NOT the result of the last save-changes.		   *
X* 									   *
X\**************************************************************************/
X
X#include <sys/file.h>
X#include <stdio.h>
X#include "sysdep.h"
X#include "mem.h"
X#include "save.h"
X
Xstatic	int BackedUp = 0;
Xextern	char *sprintf();
X
X/*
X * Will only backup one file per call!  Don't pass all of ModBits to this
X * routine at once.
X */
Xbackup(flag)
Xint flag;
X
X{
X	char *old, *new;
X
X	if (BackedUp & flag)
X	    return 1;
X	switch (flag) {
X	case AC:
X	    old = ACFILE;
X	    new = ACBAK;
X	    break;
X#ifdef SENDMAIL
X	case AL:
X	    if (copyfile(ALBIND, ALBINDBAK) == 0)
X		return 0;
X	    old = ALIASFILE;
X	    new = ALIASBAK;
X	    break;
X#endif
X	case CS:
X	    old = CSFILE;
X	    new = CSBAK;
X	    break;
X	case GR:
X	    old = GRPFILE;
X	    new = GRPBAK;
X	    break;
X	case PW:
X	    old = PWDFILE;
X	    new = PWDBAK;
X	    break;
X	case RG:
X	    old = RANGEFILE;
X	    new = RANGEBAK;
X	    break;
X	case SG:
X	    old = SIGFILE;
X	    new = SIGBAK;
X	    break;
X	case VG:
X	    old = VIGFILE;
X	    new = VIGBAK;
X	    break;
X	default:
X	    break;
X	}
X	if (copyfile(old, new) != 0) {
X		BackedUp |= flag;
X		return 1;
X	}
X	return 0;
X}
X
Xcopyfile(from, to)
Xchar *from, *to;
X
X{
X	char buf[BUFSIZ+1];
X	int n, fromfd, tofd;
X	char errmsg[LONG_BUF];
X
X	if ((fromfd = open(from, O_RDONLY)) < 0) {
X	    perr(from);
X	    err2("copy %s -> %s failed", from, to);
X	    return 0;
X	}
X	if ((tofd = open(to, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
X	    perr(from);
X	    err2("copy %s -> %s failed", from, to);
X	    return 0;
X	}
X	while ((n = read(fromfd, buf, BUFSIZ)) > 0)
X	    if (write(tofd, buf, n) != n) {
X		(void) sprintf(errmsg, "write of %d bytes to %s failed", n,
X				to);
X		perr(errmsg);
X		err2("copy %s -> %s failed", from, to);
X	    }
X	(void) close(fromfd);
X	(void) close(tofd);
X	return 1;
X}
@//E*O*F src/backup.c//
if test 2195 -ne "`wc -c <'src/backup.c'`"; then
    echo shar: error transmitting "'src/backup.c'" '(should have been 2195 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/class.c'" '(1809 characters)'
if test -f 'src/class.c' ; then 
  echo shar: will not over-write existing file "'src/class.c'"
else
sed 's/^X//' >src/class.c <<'@//E*O*F src/class.c//'
X#include <sys/types.h>
X#include <sys/file.h>
X#include <stdio.h>
X#include "sysdep.h"
X#include "mem.h"
X#include "lists.h"
X#include "class.h"
X
Xextern	struct list ClassList;
Xextern	int sclasscmp();
Xlong	lseek();
X
Xstatic char cdesc[DESCSIZE+1], cname[SHORT_BUF], csize[SHORT_BUF];
Xstatic char cexp[SHORT_BUF];
Xstruct class cs = { cname, 0, (time_t)0, cdesc };
X
Xint CS_FileDes = UNDEFINED;
X
Xsetcsent()
X
X{
X	if (CS_FileDes == UNDEFINED) {
X		CS_FileDes = open(CSFILE, O_RDONLY);
X		if (CS_FileDes < 0) {
X			perr(CSFILE);
X			goodbye(1);
X		}
X	}
X	lseek(CS_FileDes, (long) 0, L_SET)<0 &&
X		perr("setcsent: lseek failed?!");
X	return;
X}
X
Xendcsent()
X
X{
X	if (CS_FileDes == UNDEFINED)
X		return;
X	(void) close(CS_FileDes);
X	CS_FileDes = UNDEFINED;
X	return;
X}
X
Xstruct class *
Xgetcsent()
X
X{
X	register int i;
X	char c;
X
X	if (CS_FileDes == UNDEFINED)
X		setcsent();
X#ifdef SENDMAIL
X	zerolist(&cs.cs_aliases);
X#endif
X	i = 0;
X	while (read(CS_FileDes, &c, 1) != 0) {
X		c &= 0177;
X		if (c == ' ')
X			break;
X		cname[i++] = c;
X	}
X	if (i == 0)
X		return(0);
X	cname[i] = '\0';
X	i = 0;
X	while (read(CS_FileDes, &c, 1) != 0) {
X		c &= 0177;
X		if (c == ' ')
X			break;
X		csize[i++] = c;
X	}
X	csize[i] = '\0';
X	i = 0;
X	while (read(CS_FileDes, &c, 1) != 0) {
X		c &= 0177;
X		if (c == '\n')
X			break;
X		cexp[i++] = c;
X	}
X	if (i == 0)
X		return(0);
X	cexp[i] = '\0';
X	/* result of intermediate assignment used in read() to stifle lint */
X	cs.cs_dsize = i = atoi(csize);
X	cs.cs_exptime = atoi(cexp);
X	if (read(CS_FileDes, cs.cs_desc, i) != cs.cs_dsize)
X		fatal1("%s: bad file format", CSFILE);
X	cs.cs_desc[cs.cs_dsize] = '\0';
X	return(&cs);
X}
X
Xstruct class *
Xgetcsnam(name)
Xchar *name;
X
X{
X	int indx, found;
X
X	indx = search_list(&ClassList, name, sclasscmp, &found);
X	if (found)
X		return (struct class *) ClassList.l_list[indx];
X	return (struct class *) 0;
X}
@//E*O*F src/class.c//
if test 1809 -ne "`wc -c <'src/class.c'`"; then
    echo shar: error transmitting "'src/class.c'" '(should have been 1809 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/class.h'" '(303 characters)'
if test -f 'src/class.h' ; then 
  echo shar: will not over-write existing file "'src/class.h'"
else
sed 's/^X//' >src/class.h <<'@//E*O*F src/class.h//'
Xstruct class {
X	char		*cs_name;
X	off_t		cs_dsize;	/* description size (bytes) */
X	time_t		cs_exptime;	/* expiration date (0=never) */
X	char		*cs_desc;	/* pointer to description */
X#ifdef SENDMAIL
X	struct list	cs_aliases;	/* aliases class is bound to */
X#endif
X};
X
Xstruct class *getcsent(), *getcsnam();
@//E*O*F src/class.h//
if test 303 -ne "`wc -c <'src/class.h'`"; then
    echo shar: error transmitting "'src/class.h'" '(should have been 303 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/command.h'" '(167 characters)'
if test -f 'src/command.h' ; then 
  echo shar: will not over-write existing file "'src/command.h'"
else
sed 's/^X//' >src/command.h <<'@//E*O*F src/command.h//'
Xstruct command {
X	char	*c_name;	/* name of command */
X	int	(*c_func)();	/* function to call to do command */
X	short	c_su;		/* boolean; is command for root only? */
X};
@//E*O*F src/command.h//
if test 167 -ne "`wc -c <'src/command.h'`"; then
    echo shar: error transmitting "'src/command.h'" '(should have been 167 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'src/gpa.h'" '(42 characters)'
if test -f 'src/gpa.h' ; then 
  echo shar: will not over-write existing file "'src/gpa.h'"
else
sed 's/^X//' >src/gpa.h <<'@//E*O*F src/gpa.h//'
X#define	G_P_A__SIZE	512
X
Xaddr *get_gpa();
@//E*O*F src/gpa.h//
if test 42 -ne "`wc -c <'src/gpa.h'`"; then
    echo shar: error transmitting "'src/gpa.h'" '(should have been 42 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 3 (of 8)."
cp /dev/null ark3isdone
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