AUSAM/source/S/pwedit.c

Compare this file to the similar file:
Show the results in this format:

#

/*
 *	This program maintains and updates the passwd file
 *	under the AUSAM system. The command has the following format.
 *
 *		pwedit [-m] [-u] [-k] [-n] [-x] [-c] [-pstring] [-tstring] [filename]
 *
 *	where	-k	allows keyword specifications in the input
 *		-n	causes encryption of passwords to be suspended
 *		-x	causes extraction of all files onto standard output
 *		-m	causes initial directory creation on adds
 *		-u	allows uids not in the default range to be specified
 *		-c	causes comments to appear in password entry listings
 *			from -x option and editor temporarys...
 *		-pstring the string is to be used as the alternate password
 *			file name
 *		-tstring specifies a string to be used as a template filename
 *			that is "/usr/lib/pwetplts/string"
 *		filename specifies a file from which entries are to be taken
 *			for operation in non-interactive mode
 *
 *		Commands which may be given are; add, delete, update,
 *			change, look and default.
 *
 *
 *		Graham fix 29/11/78
 *			octal numbers in updates are recognised by a leading
 *			'0' and are also printed by pwedit thus.
 *
 */

#include	<local-system>
#include	<passwd.h>
#include	<class.h>


/*	some nice little defines to make life easier	*/ 
#define	PWETMPS		"/tmp/"			/* where tmp files are kept */
#define	PWETPLTS	"/usr/lib/pwe/tplts/"	/* where the templates are */
#define	PWEDFLTS	"/usr/lib/pwe/dflts/"	/* where the defaults are */
#define	PWETDFLT	"default"		/* the default name */

#define	SSIZE		100	/* name string lengths */

/*	some handles on difficult to hold things	*/ 
struct
{
	unsigned hiword;
	unsigned loword;
};
struct
{
	char lobyte;
	char hibyte;
};

/*	now the global data	*/ 

/*	flags	*/ 
int tflag, nflag, xflag, cflag, fflag, mflag, uflag;
int sigstop;
int status;	/* status used for waits */ 
int owuid;	/* the caller's uid */

/*	filename arrays	*/ 
char tname[SSIZE], dname[SSIZE], ename[SSIZE], fname[SSIZE];

/*	temp file templates for editor	*/ 
char *edtemp "pweaXXXXX";

/*	the global last character	*/ 
char nextc;
char c;

/*	global passwd entry	*/ 
struct pwent pe;

/*	global default entry	*/ 
struct pwent de;

/*	putc and getc buffers	*/ 
struct iobuf
{
	int fildes;
	int count;
	char *cnext;
	char buff[512];
} sibuf;
struct iobuf sobuf {
	1,
	0,
	0,
	512*0
};
struct iobuf *ibuf, *obuf;

/*	some definitions	*/ 
#define	ITEMKEY	1	/* a keyword item */
#define	ITEMNUM	2	/* a number item, may be byte,int or long */
#define	ITEMSTR	3	/* string item */
#define	ITEMBIT	4	/* a bit string */
#define	ITEMNL	5	/* an empty line */
#define	ITEMTERM 6	/* a terminal group spec in {}'s */

/*	definition of ITEMKEY command codes for internal use	*/ 
#define	ADDCOM	0	/* add command */
#define	DELCOM	1	/* delete command */
#define	CHNGCOM	2	/* change command */
#define	UPDTCOM	3	/* update command */
#define	LOOKCOM	4	/* lookat command */

/*	string to code matching	*/ 
char *commands[]
{
	"add",		/* ADDCOM */ 
	"delete",	/* DELCOM */ 
	"change",	/* CHNGCOM */ 
	"update",	/* UPDTCOM */ 
	"look",		/* LOOKCOM */
	0
};

/*	some handles to hang on to things by	*/ 
long	pnum;		/* the global read number	*/ 
int	pcom;		/* type of command, +ve if known, -ve if not */ 
int	scom;		/* a place to keep it safe */ 
int pclass[CMASKSIZE];	/* the present read class mask bits string */ 
char	*pstr;		/* the global read string */ 


main(argc, argv)
int argc;
char *argv[];
{
	extern catsig();
	register int i;

	/*	initialise io	*/ 


	ibuf = &sibuf;
	obuf = &sobuf;

#ifdef	DEBUG
	printf("main\n");
	fflush(obuf);
#endif	DEBUG
	owuid = getuid();

	/*	get args and stuff	*/ 
	getargs(argc, argv);

	/*	initialise defaults etc	*/ 
	initialise();

	/*
	 *	now have serveral possibilities.
	 *	extraction mode, file input mode, or interaction.
	 */ 
	if(xflag)
		xtract();
	else
	{
		/*	initialise nasty signals	*/ 
		for(i = 1; i < 4; i++)
			signal(i, 1);
		for(i = 14; i <= 16; i++)
			signal(i, catsig);
		if(fflag)
			readfile();
		else
			interact();
	}

}


getargs(ac, av)
int ac;
char **av;
{
	/*	things with a '-' are flags, without is a filename	*/ 

#ifdef	DEBUG
	printf("getargs\n");
	fflush(obuf);
#endif	DEBUG
	while(--ac)
	{
		if(**++av == '-')
		{
			switch(av[0][1])
			{
		    case 't':
				settname(*av+2);
				tflag++;
				break;
		    case 'p':
				setpname(*av+2);
				break;
		    case 'm':
				mflag++;
				break;
		    case 'u':
				uflag++;
				break;
		    case 'n':
				nflag++;
				break;
		    case 'x':
				xflag++;
				break;
		    case 'c':
				cflag++;
				break;
		    default:
				error(1, *av);
				break;
			}
		}
		else
		{
			setfname(*av);
			fflag++;
		}
	}
#ifdef	DEBUG
	printf("tflag=%d,nflag=%d,xflag=%d\n", tflag, nflag, xflag);
	fflush(obuf);
	printf("tname->%s<-,dname->%s<-,fname->%s<-\n", tname, dname, fname);
	fflush(obuf);
#endif	DEBUG
}


initialise()
{
	/*
	 *	set default file names if necessary, open template and default files
	 *	and initialise default pwent.
	 */ 

#ifdef	DEBUG
	printf("initialise\n");
	fflush(obuf);
#endif	DEBUG
	if(!tflag)
	{
		strcpy(tname, PWETPLTS);
		strcat(tname, PWETDFLT);
		strcpy(dname, PWEDFLTS);
		strcat(dname, PWETDFLT);
	}
	getdefault();
}


settname(s)
char *s;
{
	/*	make up the filenames for templates and defaults	*/ 

#ifdef	DEBUG
	printf("settname\n");
	fflush(obuf);
#endif	DEBUG
	strcpy(tname, PWETPLTS);
	strcat(tname, s);
	strcpy(dname, PWEDFLTS);
	strcat(dname, s);
}


setpname(s)
char *s;
{
	/*	set the default password file name	*/ 
#ifdef	DEBUG
	printf("setpname\n");
	fflush(obuf);
#endif	DEBUG
	pwfile(s);
}


setfname(s)
char *s;
{
	/*	set input file name	*/ 

#ifdef	DEBUG
	printf("setfname\n");
	fflush(obuf);
#endif	DEBUG
	strcpy(fname, s);
}


xtract()
{
	/*	explode whole passwd file onto SO with adds for each entry	*/ 
	register struct iobuf *rsbuf;
	register int i;

#ifdef	DEBUG


	printf("xtract\n");
	fflush(obuf);
#endif	DEBUG
	/*	save old output	*/ 
	rsbuf = obuf;
	fflush(obuf);
	obuf = &sobuf;

	/*	output	*/ 
	for(i = 0; i < PWTABSIZE; i++)
	{
		pe.pw_uid = i;
		if(getpwlog(&pe, 0, 0) < 0)
			continue;
		/*	real entry, output it	*/ 
		if(getpw(0, &pe) < 0)
			continue;
		putpe("add", &pe, 1);
	}

	/*	restore old SO	*/ 
	fflush(obuf);
	obuf = rsbuf;
}


interact()
{
	/*
	 *	it interacts with the cretins
	 */ 
	register int ri, rf;
	struct iobuf *ribuf, *robuf;
	char cc;

#ifdef	DEBUG
	printf("interact\n");
	fflush(obuf);
#endif	DEBUG
	while(1)
	{
		/* major loop */ 
		if(sigstop)
			break;
		rf = 0;
		if( owuid == 0)
		{
			do
			{
				putchar('>');
				fflush(obuf);
			}
			while(((ri = getitem()) != ITEMKEY) && (ri != 0));
			if(ri == 0)
				break;
			scom = pcom;
		}
		else
			scom = LOOKCOM;

		if(scom != ADDCOM)
		{
			/* only need uid and lname if not an add command */ 
			printf("lname: ");
			fflush(obuf);
			if((ri = getitem()) == 0)
				break;
			if(ri == ITEMSTR)
			{
				pe.pw_strings[LNAME] = pstr;
				rf =| 02;
			}
			if( rf == 0 || scom == DELCOM)
			{
				printf("uid: ");
				fflush(obuf);
				if((ri = getitem()) == 0)
					break;
				if(ri == ITEMNUM)
				{
					/* got a number, not just nothing */ 
					if(!bcheck(2))
					{
						error(15, 0);
						continue;
					}
					pe.pw_uid = pnum.loword;
					rf =| 01;
				}
			}
		}

		/* now have command and other data, just use it */ 
		if(scom == DELCOM)
		{
			/* delete command, must have both uid and lname */ 
			if((rf&03) != 03)
			{
				error(17, 0);
			}
			else
			{
				if(delpwent(&pe) < 1)
					error(9, 0);
			}
		}
		else
		{
			/* for add command or flags 01|02 must go on */ 
			if((scom == ADDCOM) || (rf&03))
			{
				fflush(obuf);
				robuf = obuf;
				strcpy(ename, PWETMPS);
				strcat(ename, edtemp);
				mktemp(ename);
				obuf = copen(ename, 0600);

				if(scom == ADDCOM)
				{
					/* for an add must copy over template */ 
					ribuf = ibuf;
					ibuf = copen(tname, 0);
					while((cc = getc(ibuf)) != -1)
						putc(cc, obuf);
					cclose(ibuf);
					ibuf = ribuf;
				}
				else
				{
					/* must be change or update */ 
					if(rf&01)
					{
						if(getpw(0, &pe) < 0)
							rf =| 04;
					}
					else
					{
						if(getpw(1, &pe) < 0)
							rf =| 04;
					}

					/* free up the interactive login name */ 

					if(!(rf&04))
						putpe(commands[scom], &pe, 1);
				}

				/* finished with obuf */ 
				fflush(obuf);
				cclose(obuf);
				obuf = robuf;

				if(!(rf&04))
				{
					/* return input absorbed into buffer */
					seek(ibuf->fildes, -(ibuf->count), 1);
					ibuf->count = 0;
					/* now spawn an elfic ed */ 
					if(fork())
					{
						/* parent */ 
						wait(&status);
					}
					else
					{
						/* child */ 
						if(execl("/bin/em", "pwede", "-e", ename, 0) < 0)
						{
							error(16, 0);
						}
					}

					/* now have returned so validate results */ 
					if(scom != LOOKCOM)
					{
						ribuf = ibuf;
						ibuf = copen(ename, 0);
						if(getpe(&pe) < 0)
						{
							error(5, 1);
							rf =| 04;
						}
						else
							if(putpw(&pe) < 0)
								error(6, 1);
						cclose(ibuf);
						ibuf = ribuf;
					}
				}
				unlink(ename);
			}
		}
	}
}


putpe(rs, rpe, ff)
register char *rs;
register struct pwent *rpe;
int ff;
{
	/*
	 *	Output the pwent struct at *rpe with the string at *rs as the
	 *	first line of output. Uses printf calling putchar calling putc
	 *	an ff of 1 causes freeing of string area after output
	 */ 
	register int i;

#ifdef	DEBUG
	printf("putpe\n");
	fflush(obuf);
#endif	DEBUG
	/*	command out	*/ 
	printf("%s\n", rs);

	/*	now all other entries	*/ 
	if(cflag)
	{
		printf("%d	/* uid */\n", rpe->pw_uid);
	}
	else
	{
		printf("%d\n", rpe->pw_uid);
	}
	if(cflag)
	{
		printf("%d	/* shares */\n", rpe->pw_shares);
	}
	else
	{
		printf("%d\n", rpe->pw_shares);
	}
	if(cflag)
	{
		printf("%ld	/* usage */\n", rpe->pw_usage);
	}
	else
	{
		printf("%ld\n", rpe->pw_usage);
	}

	printclass(rpe);

	printterms(rpe);

	if(cflag)
	{
		printf("0%o	/* flags */\n", rpe->pw_flags);	/* Graham fix	*/
	}
	else
	{
		printf("0%o\n", rpe->pw_flags);		/* Graham fix */
	}
	if(cflag)
	{
		printf("%d	/* dlimit */\n", rpe->pw_dlimit);
	}
	else
	{
		printf("%d\n", rpe->pw_dlimit);
	}
	if(cflag)
	{
		printf("%d	/* doverflw */\n", rpe->pw_doverflw);
	}
	else
	{
		printf("%d\n", rpe->pw_doverflw);
	}
	if(cflag)
	{
		printf("%d	/* plimit */\n", rpe->pw_plimit);
	}
	else
	{
		printf("%d\n", rpe->pw_plimit);
	}
	if(cflag)
	{
		printf("%d	/* climit */\n", rpe->pw_climit);
	}
	else
	{
		printf("%d\n", rpe->pw_climit);
	}
	if(rpe->pw_pword[0] == 0)
		printf("\"\"\n");
	else
	{
		printf("\"%c%c%c%c%c%c%c%c\"\n", rpe->pw_pword[0], rpe->pw_pword[1], rpe->pw_pword[2], rpe->pw_pword[3],
			 rpe->pw_pword[4], rpe->pw_pword[5], rpe->pw_pword[6], rpe->pw_pword[7]);
	}
	if(cflag)
	{
		printf("%ld	/* contime */\n", rpe->pw_contime);
	}
	else
	{
		printf("%ld\n", rpe->pw_contime);
	}
	if(cflag)
	{
		printf("%ld	/* cputime */\n", rpe->pw_cputime);
	}
	else
	{
		printf("%ld\n", rpe->pw_cputime);
	}
	if(cflag)
	{
		printf("%ld	/* extime */\n", rpe->pw_extime);
	}
	else
	{
		printf("%ld\n", rpe->pw_extime);
	}
	if(cflag)
	{
		printf("%d	/* warn */\n", rpe->pw_warn);
	}
	else
	{
		printf("%d\n", rpe->pw_warn);
	}
	if(cflag)
	{
		printf("%d	/* pages */\n", rpe->pw_pages);
	}
	else
	{
		printf("%d\n", rpe->pw_pages);
	}
#ifdef	TERMBOOK
	if(cflag)
	{
		printf("%d	/* tblim */\n", rpe->pw_tblim & 0377);
	}
	else
	{
		printf("%d\n", rpe->pw_tblim & 0377);
	}
	if(cflag)
	{
		printf("%d	/* tbrate */\n", rpe->pw_tbrate);
	}
	else
	{
		printf("%d\n", rpe->pw_tbrate);
	}
#endif	TERMBOOK

	for(i = 0; i < PWSLENCNT; i++)
		if(rpe->pw_strings[i] != 0)
		{
			printf("\"%s\"\n", rpe->pw_strings[i]);
		}
		else
		{
			error(2, i);
		}
	if(ff)
	{
		free(rpe->pw_strings[0]);
		for(i = 0; i < PWSLENCNT; i++)
			rpe->pw_strings[i] = 0;
	}
}


getpw(ct, rpe)
int ct;
register struct pwent *rpe;
{
	/*
	 *	using call type, ct, gets an entry into *rpe. cts are:
	 *		0	by uid
	 *		1	by login name
	 */ 
	register int rsum, ri;
	char *as, *ss;

#ifdef	DEBUG
	printf("getpw\n");
	fflush(obuf);
#endif	DEBUG
	/*	first determine the string sizes	*/ 
	ss = rpe->pw_strings[0];

	switch(ct)
	{
    case 0:	/* by uid */ 
		if(getpwlog(rpe, 0, 0) < 0)
		{
			error(12, 0);
			return(-1);
		}
		break;
    case 1:	/* by login name */ 
		if(getpwuid(rpe, 0, 0) < 0)
		{
			error(13, 0);
			return(-1);
		}
		break;
	}

	for(ri = 0, rsum = 0; ri < PWSLENCNT; ri++)
	{
		rsum =+ rpe->pw_strings[ri];
	}

	if((as = alloc(rsum)) < 0)
	{
		error(14, 0);
		return(-1);
	}

	switch(ct)
	{
    case 0:	/* by uid we get it */ 
		if(getpwlog(rpe, as, rsum) != rsum)
		{
			error(12, 0);
			return(-1);
		}
		break;
    case 1:	/* by login name */ 
		rpe->pw_strings[0] = ss;
		if(getpwuid(rpe, as, rsum) != rsum)
		{
			error(13, 0);
			return(-1);
		}
		break;
	}

}


putpw(rpe)
register struct pwent *rep;
{
	/*
	 *	add change or update a passwd file entry using the stuff in *rep
	 */ 
	register int ri;

#ifdef	DEBUG
	printf("putpw\n");
	fflush(obuf);
#endif	DEBUG
	switch(scom)
	{
    case 0:	/* add */ 
		/* enforce the bounds limits for this site */ 
		if(!uflag)
			rpe->pw_uid = UIDLB;
		if(addpwent(rpe) < 0)
			error(8, rpe->pw_strings[LNAME]);
		else
		/* make directories etc if needed */ 
		if(mflag)
			mkit();
		break;
    case 2:	/* change */ 
		if(chngpwent(rpe) < 0)
			error(10, 0);
		break;
    case 3:	/* update */ 
		if(updtpwent(rpe) < 0)
			error(11, 0);
		break;
	}

	for(ri = 0; ri < PWSLENCNT; ri++)
	{
		free(rpe->pw_strings[ri]);
		rpe->pw_strings[ri] = 0;
	}

}


struct iobuf *copen(s, m)
char *s;
int m;
{
	/*
	 *	open (or if m>0 creat) a file with name "*s" and make
	 *	associated buffer area for getc and putc.
	 */ 
	register int rfd;
	register struct iobuf *rsbuf;

#ifdef	DEBUG
	printf("copen of %s\n", s);
	fflush(obuf);
#endif	DEBUG
	if(m > 0)
	{
		/*	creat the file	*/ 
		if((rfd = creat(s, m)) < 0)
		{
			error(3, s);
		}
	}
	else
	{
		/*	open only	*/ 
		if((rfd = open(s, 0)) < 0)
		{
			error(0, s);
		}
	}
	if((rsbuf = alloc(sizeof sobuf)) < 0)
		error(4, s);
	rsbuf->fildes = rfd;
	rsbuf->count = 0;
	rsbuf->cnext = 0;
	return(rsbuf);
}


readfile()
{
	/*
	 *	opens file called "*fname" and decodes input to form
	 *	new and modified passwd entries. Sets up input buffers also.
	 */ 
	register struct iobuf *rsbuf;
	register int ri, rn;

	/*	save old input buffer	*/ 
#ifdef	DEBUG
	printf("readfile\n");
	fflush(obuf);
#endif	DEBUG
	rsbuf = ibuf;
	/*	open and use the new stuff	*/ 
	ibuf = copen(fname, 0);
	rn = 0;
	while(++rn)
	{
		if(sigstop)
			break;
		if((ri = getpe(&pe)) < 0)
		{
			error(5, rn);
			break;
		}
		if(putpw(&pe) < 0)
			error(6, rn);
		if(ri == 0)
			break;
	}

	/*	flush and restore to exit	*/ 
	fflush(obuf);
	cclose(ibuf);
	ibuf = rsbuf;
}


getdefault()
{
	/*
	 *	open files etc and read defaults into "&de".
	 *	Note that defaults of zero force entries to be requested for them
	 */ 
	register struct iobuf *rsbuf;

#ifdef	DEBUG
	printf("getdefault\n");
	fflush(obuf);
#endif	DEBUG
	rsbuf = ibuf;
	ibuf = copen(dname, 0);
	if(getpe(&de) < 0)
		error(5, 0);
	cclose(ibuf);
	ibuf = rsbuf;
}


getpe(rpe)
register struct pwent *rpe;
{
	/*
	 *	reads and validates the entry from "ibuf" into "*rpe".
	 */ 
	register char *rpw;
	register int rn;

#ifdef	DEBUG
	printf("getpe\n");
	fflush(obuf);
#endif	DEBUG
	/*	get command	*/ 
	if(getitem() != ITEMKEY)
		return(-1);
	if((scom = pcom) < 0)
		return(-1);

	/*	get uid	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(2))
		return(-1);
	rpe->pw_uid = pnum.loword;

	/*	get shares	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(2))
		return(-1);
	rpe->pw_shares = pnum.loword;

	/*	get usage	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(4))
		return(-1);
	rpe->pw_usage = pnum;

	/*	read class mask bit string	*/ 
	if(getitem() != ITEMBIT)
		return(-1);
	for(rn = 0; rn < CMASKSIZE; rn++)
		rpe->pw_cmask[rn] = pclass[rn];

	/*	read terminal groups string	*/ 
	if(getitem() != ITEMTERM)
		return(-1);
	rpe->pw_tmask = pnum.loword;

	/*	get flags	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(2))
		return(-1);
	rpe->pw_flags = pnum.loword;

	/*	get dlimit	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(2))
		return(-1);
	rpe->pw_dlimit = pnum.loword;


	/*	get doverflw	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(2))
		return(-1);
	rpe->pw_doverflw = pnum.loword;
	/*	get plimit	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_plimit = pnum.loword.lobyte;

	/*	get climit	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_climit = pnum.loword.lobyte;

	/*	get passwd	*/ 
	if(getitem() != ITEMSTR)
		return(-1);
	if(*pstr == 0)
	{
		/* null passwd */ 
		for(rn = 0; rn < 8; rn++)
			rpe->pw_pword[rn] = 0;
	}
	else if((scom != ADDCOM) || (nflag))
	{
		/* no encryption */ 
		for(rn = 0; rn < 8; rn++)
			rpe->pw_pword[rn] = pstr[rn];
	}
	else
	{
		/* encrypt */ 
		rpw = crypt(pstr);
		for(rn = 0; rn < 8; rn++)
			rpe->pw_pword[rn] = rpw[rn];
	}

	/*	get contime	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(4))
		return(-1);
	rpe->pw_contime = pnum;

	/*	get cputime	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(4))
		return(-1);
	rpe->pw_cputime = pnum;

	/*	get extime	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(4))
		return(-1);
	rpe->pw_extime = pnum;

	/*	get warn	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_warn = pnum.loword.lobyte;

	/*	get pages	*/ 
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_pages = pnum.loword.lobyte;

#ifdef TERMBOOK
	/*	get tblim	*/
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_tblim = pnum.loword.lobyte;

	/*	get tbrate	*/
	if(getitem() != ITEMNUM)
		return(-1);
	if(!bcheck(1))
		return(-1);
	rpe->pw_tbrate = pnum.loword.lobyte;

#endif	TERMBOOK

	/*	finally get strings	*/ 
	for(rn = 0; rn < PWSLENCNT; rn++)
	{
		if(getitem() != ITEMSTR)
			return(-1);
		if(rpe->pw_strings[rn] != 0)
		{
			free(rpe->pw_strings[rn]);
		}
		rpe->pw_strings[rn] = pstr;
		pstr = 0;
	}

}


getitem()
{
	/*
	 *	returns a number corresponding to the type of item read.
	 *	return values are define previously. Returns the negative of the
	 *	normal return for an error item. Returns 0 for eof.
	 */ 
	register int finished;
	register int rv;
	register int ri;

#ifdef	DEBUG
	printf("getitem\n");
	fflush(obuf);
#endif	DEBUG
	finished = 0;

	c = getc(ibuf);

	while(!finished)
	{
		if(c == -1)
			return(0);
		if((c <= 'z') && (c >= 'a'))
		{
			/*	a keyword	*/ 
			rv = ITEMKEY;
			nextc = c;
			pstr = getstring(pstr, 0);
			for(ri = 0; (strcmp(commands[ri], pstr) != 0); ri++)
			{
				if(commands[ri] == '\0')
				{
					ri = -1;
					break;
				}
			}
			pcom = ri;
			finished = 1;
		}
		else if((c <= '9') && (c >= '0'))
		{
			/*	a number of some form	*/ 
			rv = ITEMNUM;
			if(c == '0')	/* Graham fix,we're not interested in null's!	*/
			{
				if(getnum(8) < 0)
					rv =* -1;
			}
			else
			{
				if(getnum(10) < 0)
					rv =* -1;
			}
			finished = 1;

		}
		else
			switch(c)
			{
		    case '"':	/*	a string	*/ 
				rv = ITEMSTR;
				pstr = getstring(pstr, 1);
				finished = 1;
				break;
		    case '/':	/*	a comment	*/ 
				flushline();
				break;
		    case '`':	/*	a bit string	*/ 
				rv = ITEMBIT;
				if(getclass() < 0)
					rv =* -1;
				finished = 1;
				break;
		    case '{':	/* a terminal group spec */ 
				rv = ITEMTERM;
				if(getterms() < 0)
					rv = -rv;
				finished = 1;
				break;
		    case '\n':	/* a null line */ 
				rv = ITEMNL;
				finished = 1;
				break;
		    default:	/*	read another char and do again	*/ 
				c = getc(ibuf);
				break;
			}
	}

	flushline();
	return(rv);
}


getnum(rbase)
register int rbase;
{
	/*
	 *	get a number terminated by a blank in base rbase
	 */ 
	char cc;

#ifdef	DEBUG
	printf("getnum\n");
	fflush(obuf);
#endif	DEBUG
	pnum = 0;

	while(((cc = c-'0') >= 0) && (cc < rbase))
	{
		pnum = (pnum*rbase)+cc;
		c = getc(ibuf);
	}

	return(0);
}


printclass(rpe)
register struct pwent *rpe;
{
	/*
	 *	prints the bitwise representation of the pw_cmask
	 */ 
	register int rn, ri;

#ifdef	DEBUG
	printf("printclass\n");
	fflush(obuf);
#endif	DEBUG
	putc('`', obuf);
	for(rn = 0; rn < CMASKSIZE; rn++)
	{
		/* int by int */ 
		for(ri = 0; ri < 16; ri++)
		{
			/* bit by bit */ 
			if(((rpe->pw_cmask[rn]<<ri)&0100000) == 0)
				putc('0', obuf);
			else
				putc('1', obuf);
		}
	}
	putc('`', obuf);
	putc('\n', obuf);
}

printterms(rpe)
register struct pwent *rpe;
{
	/*
	 *	prints the groupwise representation of pw_tmask
	 */ 
	register rn, ri;

#ifdef	DEBUG
	printf("printterms\n");
	fflush(obuf);
#endif	DEBUG

	rn = rpe->pw_tmask;
	putc('{', obuf);
	for(ri = 0; ri < 16; ri++)
	{
		if(rn&01)
		{
			putc('a'+ri, obuf);
		}
		rn =>> 1;
	}
	putc('}', obuf);
	putc('\n', obuf);
}


getclass()
{
	/*	read class mask into pclass	*/ 
	register int ri, rn;

#ifdef	DEBUG
	printf("getclass\n");
	fflush(obuf);
#endif	DEBUG
	for(rn = 0; rn < CMASKSIZE; rn++)
		pclass[rn] = 0;

	for(rn = 0; rn < CMASKSIZE; rn++)
	{
		for(ri = 16; --ri >= 0; )
		{
			c = getc(ibuf);
			if((c == '0') || (c == '1'))
			{
				if(c == '0')
					pclass[rn] =& ~(1<<ri);
				else
					pclass[rn] =| (1<<ri);
			}
			else
				return(-1);
		}
	}

	return(0);
}

getterms()
{
	/*
	 *	return terminal mask in pnum.loword
	 */ 
	register rc, ri;

#ifdef	DEBUG
	printf("getterms\n");
	fflush(obuf);
#endif	DEBUG

	ri = 0;
	while((rc = getc(ibuf)) != -1 && rc != '\n')
	{
		if(rc == '}')
		{
			pnum.loword = ri;
			return 0;
		}
		if(rc >= 'a' && rc <= 'p')	/* only valid groups so far */ 
		{
			ri = ri^(1<<(rc-'a'));
		}
		else if(rc == '!')
			ri = ~ri;
		else
			return -1;
	}
	return -1;
}


flushline()
{
	/* flushes ibuf until a '\n' or eof are reached */ 

#ifdef	DEBUG
	printf("flushline\n");
	fflush(obuf);
#endif	DEBUG
	while((c != '\n') && (c != -1))
	{
		c = getc(ibuf);
	}

}


bcheck(ri)
register int ri;
{
	/*
	 *	checks to see if the global long pnum has a number small enough
	 *	to fit in "ri" bytes.
	 */ 
#ifdef	DEBUG
	printf("bcheck\n");
	fflush(obuf);
#endif	DEBUG
	return(1);
}


cclose(rsbuf)
register struct iobuf *rsbuf;
{
	/*
	 *	close the file
	 *	and free the buffer area
	 */ 
#ifdef	DEBUG
	printf("cclose\n");
	fflush(obuf);
#endif	DEBUG
	close(rsbuf->fildes);
	free(rsbuf);
}


char readc(tm)
int tm;
{
	/*
	 *	reads characters from the ibuf file one by one.
	 *	returns characters, '\0' for EOF or end of string
	 *	specified by value of tm.
	 */ 

#ifdef	DEBUG
	printf("readc\n");
	fflush(obuf);
#endif	DEBUG
	if(nextc)
	{
		c = nextc;
		nextc = 0;
	}
	else
		c = getc(ibuf);

	if(c == '\\')
	{
		c = getc(ibuf);
		return(c);
	}

	if(c == -1)
		return('\0');
	if(tm)
	{
		/* terminate with '"' */ 
		if(c == '"')
			return('\0');
	}
	else
	{
		/* terminate with ' ' or '\n' */ 
		if((c == ' ') || (c == '\n'))
			return('\0');
	}

	return(c);
}


char *getstring(ptr, tm)
char *ptr;
int tm;
{
	/*
	 *	read a string from the input source specified by present ibuf.
	 *	free the area pointed to by ptr (if non-zero). return a pointer
	 *	to a newly alloced string.
	 *	tm specifies the termination method, as in 1 for a """ terminator
	 *	and 0 for normal ones like " ", "\n" etc
	 */ 
	register char *string;
	register s, slen, finished;

#ifdef	DEBUG
	printf("getstring\n");
	fflush(obuf);
#endif	DEBUG
	s = 0;
	finished = 0;

	if(ptr)
	{
		free(ptr);
		ptr = 0;
	}

	string = alloc(slen = SSIZE);

	while(!finished)
	{
		while(s < slen)
		{
			if((string[s++] = readc(tm)) <= 0)
			{
				finished = 1;
				break;
			}
		}
		if(finished)
			string = expand(string, s, slen);
		else
			string = expand(string, slen, slen =+ SSIZE);
	}

	return(string);
}


char *expand(old, initial, final)
register char *old;
{
	/*
	 *	modifies size of area pointed to by "old" from "initial" to "final"
	 *	and returns "new" pointer
	 */ 
	register char *new;
	register int i;

#ifdef	DEBUG
	printf("expand\n");
	fflush(obuf);
#endif	DEBUG
	new = alloc(final);

	for(i = 0; i < initial; i++)
	{
		new[i] = old[i];
	}

	free(old);

	return(new);
}


error(ri, rp)
register int ri;
register unsigned *rp;
{
	/*	error output and actions	*/ 
	register struct iobuf *rsbuf;

	rsbuf = obuf;
	obuf = &sobuf;

	printf("pwedit: ");

	switch(ri)
	{
    case 0:
		printf("cannot open file %s\n", rp);
		fflush(obuf);
		exit(0);
		break;
    case 1:
		printf("unknown argument %s\n", rp);
		break;
    case 2:
		printf("not used at present\n");
		fflush(obuf);
		exit(0);
		break;
    case 3:
		printf("cannot creat file %s\n", rp);
		fflush(obuf);
		exit(0);
		break;
    case 4:
		printf("cannot alloc buffer area for file %s\n", rp);
		fflush(obuf);
		exit(0);
		break;
    case 5:
		printf("error in input file at item %d\n", rp);
		break;
    case 6:
		printf("error writing passwd file at item %d\n", rp);
		fflush(obuf);
		exit(0);
		break;
    case 7:
		printf("invalid character is %c\n", *rp);
		fflush(obuf);
		exit(0);
		break;
    case 8:
		printf("passwd add error login name %s\n", rp);
		break;
    case 9:
		printf("passwd delete error\n");
		break;
    case 10:
		printf("passwd change error\n");
		break;
    case 11:
		printf("passwd update error\n");
		break;
    case 12:
		printf("passwd getpwlog error\n");
		break;
    case 13:
		printf("passwd getpwuid error\n");
		break;
    case 14:
		printf("cannot alloc string area\n");
		fflush(obuf);
		exit(0);
		break;
    case 15:
		printf("uid too large\n");
		break;
    case 16:
		printf("editor execl failed\n");
		fflush(obuf);
		exit(0);
		break;
    case 17:
		printf("not enough data for interactive action requested\n");
		break;
    case 18:
		printf("cannot fork mkdir\n");
		break;
    case 19:
		printf("cannot exec mkdir for %s\n", rp);
		fflush(obuf);
		exit(0);
    case 20:
		printf("mkdir failed for %s\n", rp);
		break;
    case 21:
		printf("chown failed for %s\n", rp);
		break;
    default:
		printf("spurious error call\n");
		fflush(obuf);
		exit(0);
		break;
	}

	fflush(obuf);
	obuf = rsbuf;
}


putchar(ac)
char ac;
{
	putc(ac, obuf);
}


catsig()
{
	register int i;

	for(i = 14; i <= 16; i++)
		signal(i, 1);

	sigstop++;
}


mkit()
{
	register int cpid;


	if(cpid = fork())
	{
		/* parent */ 
		if(cpid == -1)
		{
			error(18, 0);
		}
		else
		{
			wait(&status);
			if(status&0177400)
				error(20, pe.pw_strings[DIRPATH]);
			else
			{
				if(chown(pe.pw_strings[DIRPATH], pe.pw_uid) < 0)
					error(21, pe.pw_strings[DIRPATH]);
			}
		}
	}
	else
	{
		/* child */ 
		execl("/bin/mkdir", "mkdir", pe.pw_strings[DIRPATH], 0);
		error(19, 1);
	}
}