[net.sources] REPOSTED-ACCESS 3 of 3

mahler@pur-ee (11/09/84)

This is the distribution for the access, info, and lock programs.
It is contained in three separate mailings; each mailing is in
so-called "shell archive" format.

This is file 3 of 3.

To extract the sources and compile the programs, do the following:

	1. Save this file and the others into three separate
	   files.  Edit the files and delete the mail headers
	   and this text (delete from line 1 up to and including
	   the line marked "--- CUT HERE ---").

	2. Create an empty directory and copy the files you
	   made in step 1 into it.  Now give each file to
	   the shell by typing

			sh filename1
			sh filename2
			sh filename3

	   This will extract the various files in the
	   distribution.

	3. Fill in the answers to the questions by editing the file
	   QUESTIONAIRE and mail it to

		{decvax, ihnp4, ucbvax}!pur-ee!mahler

	   This is so we'll know just who is running the
	   program, and so we can distribute any corrections
	   or enhancements.

	4. Follow the directions contained in the README file.

------------------------- CUT HERE -----------------------------
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#          info.c        lock.sh   mkaccessdb.c  mkaccesspw.sh
# 
#
echo 'x - info.c'
sed 's/^X//' <<'________This_Is_The_END________' >>info.c
Xstatic char *RCSid = "$Header: info.c,v 1.2 84/10/29 13:39:08 root Exp $";
X/*
X * info - print information about a file
X *
X * For each file, info will stat(2) the file and print out the information
X * in the structure.  It will also look at the file and try to figure out
X * what's in it, ala' file(1).
X *
X *	-f	- don't try to figure out what's in the file
X *	-s	- print security information about file (not implemented)
X *	-v	- print all the information, instead of just some of it
X *
X * David A. Curry
X * Purdue University Engineering Computer Network
X * April 1984
X *
X * This program is hereby placed in the public domain, and may
X * be used by anyone for any purpose provided that it is not
X * used or sold for profit and that this notice and the name
X * of the original author appears with all copies of the program.
X *
X * $Log:	info.c,v $
X * Revision 1.2  84/10/29  13:39:08  root
X * fix major/minor number to print properly
X * 
X */
X#include <sys/param.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <a.out.h>
X#include <ctype.h>
X#include <stdio.h>
X#include <grp.h>
X#include <pwd.h>
X
X#define STAT		lstat
X#define ROOTDIR		"/"
X#define kbytes(x)	((x + 1023) >> 10)
X#define isregular(x)	((x & S_IFMT) == S_IFREG)
X#define isspecial(x)	(((x & S_IFMT) == S_IFCHR) || ((x & S_IFMT) == S_IFBLK))
X#define isdirectory(x)	((x & S_IFMT) == S_IFDIR)
X
X/*
X * C language keywords to use in whatsin().
X */
Xchar *c_language[] = {
X	"int", "char", "float", "double", "struct", "extern", "static", 0
X};
X
X/*
X * FORTRAN keywords.
X */
Xchar *f_language[] = {
X	"function", "subroutine", "common", "dimension", "block", "data",
X	"integer", "real", "double", 0
X};
X
X/*
X * PASCAL keywords.
X */
Xchar *p_language[] = {
X	"program", "procedure", "record", "array", "const", "type", "var", 
X	"begin", "end", "then", "character", "integer", "real", 0
X};
X
X/*
X * Device-Independent Troff keywords.
X */
Xchar *t_language[] = {
X	"x", "T", "res", "init", "font", "202", "V0", "p1", 0
X};
X
X/*
X * Assembler keywords.
X */
Xchar *a_language[] = {
X	"chmk", "mov", "tst", "clr", "jmp", 0
X};
X
X/*
X * More assembler keywords.
X */
Xchar *a2_language[] = {
X	"globl", "byte", "align", "text", "data", "comm", 0
X};
X
Xshort fflag = 0;			/* 1 if -f given		*/
Xshort sflag = 0;			/* 1 if -s given		*/
Xshort vflag = 0;			/* 1 if -v given		*/
X
Xchar *pname;				/* Global argv[0]		*/
Xchar cur_dir[MAXPATHLEN];		/* Current directory for -s	*/
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	char *rindex();
X	extern char _sobuf[];
X	
X	if ((pname = rindex(*argv, '/')) == NULL)
X		pname = *argv;
X	else
X		pname++;
X	
X	if (argc < 2) {
X		fprintf(stderr, "Usage: %s [-f] [-s] [-v] files ...\n", pname);
X		exit(1);
X	}
X	
X	*cur_dir = NULL;
X	setbuf(stdout, _sobuf);
X	
X	while (--argc) {
X		if ((*++argv)[0] != '-') {
X			info(*argv);
X			continue;
X		}
X		
X		switch ((*argv)[1]) {
X		case 'f':
X			fflag++;
X			break;
X		case 's':
X			sflag++;
X			break;
X		case 'v':
X			vflag++;
X			break;
X		default:
X			fprintf(stderr, "%s: unknown flag '%s'\n", pname, *argv);
X			fprintf(stderr, "Usage: %s [-f] [-s] [-v] files ...\n", pname);
X			exit(1);
X			break;
X		}
X	}
X
X	exit(0);
X}
X
X/*
X * info - stat the file and print the information.
X */
Xinfo(file)
Xchar *file;
X{
X	struct stat sbuf;
X	char *uname, *gname;
X	struct group *g, *getgrgid();
X	struct passwd *p, *getpwuid();
X	char *itoa(), *ctime(), *whatis(), *whatsin(), *filemode();
X
X	/*
X	 * If the file isn't there, give up.
X	 */
X	if (STAT(file, &sbuf) < 0) {
X		fprintf(stderr, "%s: cannot locate file '%s'.\n", pname, file);
X		return;
X	}
X	
X	/*
X	 * Get the user and group names.  If they aren't
X	 * in the password (group) file, use the numeric id.
X	 */
X	p = getpwuid(sbuf.st_uid);
X	uname = (p ? p->pw_name : itoa(sbuf.st_uid));
X	g = getgrgid(sbuf.st_gid);
X	gname = (g ? g->gr_name : itoa(sbuf.st_gid));
X
X	/*
X	 * Print file's name, type, and size.
X	 */
X	printf("\n");
X	printf("File Name      - %s\n", file);
X	printf("File Type      - %s\n", whatis(file, sbuf.st_mode));
X	printf("File Size      - %d bytes, %d Kbytes\n", sbuf.st_size, kbytes(sbuf.st_size));
X
X	/*
X	 * Provided the -f flag wasn't given, and the file is a
X	 * regular file, and we can read the file, try to figure
X	 * out what's in it.
X	 */
X	if (!fflag) {
X		if (isregular(sbuf.st_mode) && (access(file, 4) == 0))
X			printf("File Contents  - %s\n", whatsin(file, sbuf));
X	}
X	
X	/*
X	 * Print the owner, group, and mode of the file.
X	 */
X	printf("Uid of Owner   - %s (%d)\n", uname, sbuf.st_uid);
X	printf("Gid of Owner   - %s (%d)\n", gname, sbuf.st_gid);
X	printf("File Mode      - %s (%o)\n", filemode(sbuf.st_mode), (sbuf.st_mode & 07777));
X	
X	/*
X	 * Interpret the file mode for them.
X	 */
X	interpret(uname, gname,  sbuf);
X		
X	/*
X	 * Print all this stuff if -v was given.
X	 */
X	if (vflag) {
X		/*
X		 * Print the number of links, and the
X		 * inode number.
X		 */
X		printf("Links to file  - %d\n", sbuf.st_nlink);
X		printf("Inode Number   - %d\n", sbuf.st_ino);
X		
X		/*
X		 * Handle major/minor devices.
X		 */
X		if (isspecial(sbuf.st_mode)) {
X		    	printf("Major Device   - %u\n", major(sbuf.st_dev));
X		    	printf("Minor Device   - %u\n", minor(sbuf.st_dev));
X		    	printf("Device Type    - %u\n", major(sbuf.st_rdev));
X		    	printf("Device Number  - %u\n", minor(sbuf.st_rdev));
X		}
X		else {
X		    	printf("Major Device   - %u\n", major(sbuf.st_dev));
X		    	printf("Minor Device   - %u\n", minor(sbuf.st_dev));
X		}
X	}
X	
X	/*
X	 * Print the times.
X	 */
X	printf("Creation Time  - %s", ctime(&sbuf.st_ctime));
X	printf("Last Modified  - %s", ctime(&sbuf.st_mtime));
X	printf("Last Accessed  - %s", ctime(&sbuf.st_atime));
X	
X	/*
X	 * If -s given, interpret the file's security.
X	 */
X	if (sflag)
X		dosecurity(file);
X	
X	printf("\n");
X	fflush(stdout);
X}
X
X/*
X * whatis - returns a character string telling what the file is.
X */
Xchar *whatis(file, mode)
Xchar *file;
Xunsigned short mode;
X{
X	char *linkname();
X	static char buf[BUFSIZ];
X	
X	switch (mode & S_IFMT) {
X	case S_IFREG:
X		sprintf(buf, "normal file");
X		break;
X	case S_IFDIR:
X		sprintf(buf, "directory");
X		break;
X	case S_IFBLK:
X		sprintf(buf, "block special file");
X		break;
X	case S_IFCHR:
X		sprintf(buf, "character special file");
X		break;
X	case S_IFLNK:
X		/*
X		 * If it's a symbolic link, find out what it
X		 * points to.
X		 */
X		sprintf(buf, "symbolic link to %s", linkname(file));
X		break;
X	case S_IFSOCK:
X		sprintf(buf, "socket (named pipe)");
X		break;
X	default:
X		sprintf(buf, "unknown (inode trashed)");
X		break;
X	}
X	
X	return(buf);
X}
X
X/*
X * linkname - returns character string with the name of the file a
X *	     symbolic link points to.
X */
Xchar *linkname(file)
Xchar *file;
X{
X	int len;
X	static char buf[BUFSIZ];
X	
X	if ((len = readlink(file, buf, BUFSIZ)) < 0)
X		return("space - the final frontier");
X	
X	buf[len] = NULL;
X	return(buf);
X}
X
Xint	m1[] = { 1, S_IREAD>>0, 'r', '-' };
Xint	m2[] = { 1, S_IWRITE>>0, 'w', '-' };
Xint	m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' };
Xint	m4[] = { 1, S_IREAD>>3, 'r', '-' };
Xint	m5[] = { 1, S_IWRITE>>3, 'w', '-' };
Xint	m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' };
Xint	m7[] = { 1, S_IREAD>>6, 'r', '-' };
Xint	m8[] = { 1, S_IWRITE>>6, 'w', '-' };
Xint	m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' };
X
Xint	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
X
X/*
X * filemode - returns a little "rwx" string ala' ls(1).
X */
Xchar *filemode(mode)
Xunsigned mode;
X{
X	int **mp;
X	register char *s;
X	static char buf[16];
X	
X	s = buf;
X	
X	for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])]; ) {
X		register int *pairp = *mp++;
X		register int n = *pairp++;
X		
X		while ((--n >= 0) && ((mode & *pairp++) == 0))
X			pairp++;
X		
X		*s++ = (char) *pairp;
X	}
X	
X	*s = NULL;
X	return(buf);
X}
X
X/*
X * interpret - explain what the little "rwx" garbage means.
X */
Xinterpret(uname, gname, sbuf)
Xchar *uname, *gname;
Xstruct stat sbuf;
X{
X	char *perm;
X	int i, yup, xable;
X	char suid, sgid, vtx;
X	char grp[32], user[32];
X	char *itoa(), *filemode();
X	
X	suid = 0;
X	sgid = 0;
X	vtx  = 0;
X	
X	/*
X	 * Get a copy of the rwx stuff.
X	 */
X	perm = filemode(sbuf.st_mode);
X	
X	for (i=0; i < 9; i++) {
X		switch (i) {
X		case 0:				/* user permissions */
X			yup = 0;
X			xable = 0;
X			sprintf(user, "User %s", uname);
X			printf("%20s: ", user);
X			break;
X		case 3:				/* group permissions */
X			yup = 0;
X			xable = 0;
X			sprintf(grp, "Group %s", gname);
X			printf("\n%20s: ", grp);
X			break;
X		case 6:				/* worl permissions */
X			yup = 0;
X			xable = 0;
X			printf("\n       Everyone else: ");
X			break;
X		}
X		
X		switch (perm[i]) {
X		case 'r':
X			printf("%sreadable", (yup ? ", " : ""));
X			yup++;
X			break;
X		case 's':
X			if (i < 3) {
X				suid++;
X				if (sbuf.st_mode & S_IEXEC)
X					xable++;
X			}
X			else {
X				sgid++;
X				if (sbuf.st_mode & (S_IEXEC>>3))
X					xable++;
X			}
X			
X			if (xable) {
X				if (isdirectory(sbuf.st_mode))
X					printf("%ssearchable", (yup ? ", " : ""));
X				else
X					printf("%sexecutable", (yup ? ", " : ""));
X				yup++;
X			}
X
X			break;
X		case 't':
X			if (sbuf.st_mode & (S_IEXEC>>6))
X				xable++;
X			vtx++;
X			
X			if (xable) {
X				if (isdirectory(sbuf.st_mode))
X					printf("%ssearchable", (yup ? ", " : ""));
X				else
X					printf("%sexecutable", (yup ? ", " : ""));
X				yup++;
X			}
X			
X			break;
X		case 'w':
X			printf("%swritable", (yup ? ", " : ""));
X			yup++;
X			break;
X		case 'x':
X			if (isdirectory(sbuf.st_mode))
X				printf("%ssearchable", (yup ? ", " : ""));
X			else
X				printf("%sexecutable", (yup ? ", " : ""));
X			
X			yup++;
X			break;
X		}
X	}
X	
X	printf("\n");
X	
X	if (suid)
X		printf("             All executions run as user id %s\n", uname);
X	
X	if (sgid)
X		printf("             All executions run as group id %s\n", gname);
X	
X	if (vtx)
X		printf("             Sticky bit set (save swap image)\n");
X}
X
X/*
X * whatsin - return a character string saying what's in the file, ala' 
X *	     file(1).
X */
Xchar *whatsin(file, sbuf)
Xchar *file;
Xstruct stat sbuf;
X{
X	char ch;
X	char buf[BUFSIZ];
X	int i, j, in, nl, fd;
X	static char contents[BUFSIZ];
X	
X	/*
X	 * This should never happen, since it's checked before
X	 * we are called.
X	 */
X	if ((fd = open(file, 0)) < 0) {
X		sprintf(contents, "cannot open %s", file);
X		return(contents);
X	}
X
X	*contents = NULL;
X	
X	/*
X	 * Read one buffer full of info.
X	 */
X	if ((in = read(fd, buf, BUFSIZ)) < 0)
X		return("empty");
X
X	/*
X	 * Look for 4-byte magic numbers.
X	 */
X	switch (*(int *)buf) {
X	case 0413:
X		sprintf(contents, "demand paged pure ");
X		goto exec;
X	case 0410:
X		sprintf(contents, "pure ");
X		goto exec;
X	case 0411:
X		return("jfr or PDP-11 UNIX 411 executable binary");
X	case 0407:
Xexec:
X		strcat(contents, "executable binary");
X		
X		if (((int *)buf)[4] != 0) {
X			strcat(contents, " (not strippped)");
X			
X			if (oldo(buf, sbuf))
X				strcat(contents, " (old format symbol table)");
X		}
X		if (((struct exec *)(buf))->a_entry & 0x80000000)
X			strcat(contents, " (game)");
X		
X		return(contents);
X	case 0177555:
X		return("very old archive");
X	case 0177545:
X		return("old archive");
X	case 070707:
X		return("cpio data");
X	case 017437:
X		return("packed file");
X	case 017777:
X		return("compacted file");
X	case 052525:
X		return("PDS picture file");
X	}
X	
X	/*
X	 * Look for two-byte magic numbers.  The real file(1) program
X	 * doesn't (didn't) have this, a bug.
X	 */
X	switch (*(short *)buf) {
X	case 0411:
X		return("jfr or PDP-11 UNIX 411 executable binary");
X	case 0177555:
X		return("very old archive");
X	case 0177545:
X		return("old archive");
X	case 070707:
X		return("cpio data");
X	case 017437:
X		return("packed file");
X	case 017777:
X		return("compacted file");
X	case 052525:
X		return("PDS picture file");
X	}
X
X	/*
X	 * Look for an archive identifier.
X	 */
X	if (!strncmp(buf, "!<arch>\n__.SYMDEF", 17))
X		return("archived random library");
X
X	if (!strncmp(buf, "!<arch>\n", 8))
X		return("archive file");
X	
X	/*
X	 * Now fiddle with guessing what language it's written
X	 * in.  This stuff is bizzare, you figure it out.
X	 */
X	i = 0;
X
X	if (!ccom(&i, in, buf))
X		goto notc;
X	
X	while (buf[i] == '#') {
X		j = i;
X		
X		while (buf[i++] != '\n') {
X			if ((i - j) > 255)
X				return("data");
X			if (i >= in)
X				goto notc;
X		}
X		
X		if (!ccom(&i, in, buf))
X			goto notc;
X	}
X
Xcheckc:
X	if (lookup(&i, in, buf, c_language)) {
X		while (((ch = buf[i++]) != ';') && (ch != '{'))
X			if (i >= in)
X				goto notc;
X		
X		strcat(contents, "'C' program text");
X		goto outa;
X	}
X
X	nl = 0;
X	
X	while (buf[i] != '(') {
X		if (buf[i] <= 0)
X			goto notas;
X		if (buf[i] == ';') {
X			i++;
X			goto checkc;
X		}
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notc;
X		if (i >= in)
X			goto notc;
X	}
X	
X	while (buf[i] != ')') {
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notc;
X		
X		if (i >= in)
X			goto notc;
X	}
X	
X	while (buf[i] != '{') {
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notc;
X		
X		if (i >= in)
X			goto notc;
X	}
X	
X	strcat(contents, "'C' program text");
X	goto outa;
X	
Xnotc:
X	i = 0;
X	
X	while ((buf[i] == 'c') || (buf[i] == '#') || (buf[i] == '*')) {
X		while (buf[i++] != '\n')
X			if (i >= in)
X				goto notfortran;
X	}
X	
X	if (lookup(&i, in, buf, f_language)) {
X		strcat(contents, "FORTRAN program text");
X		goto outa;
X	}
X
Xnotfortran:
X	i = 0;
X	
X	if (!pcom(&i, in, buf))
X		goto notpascal;
X
Xcheckp:
X	if (lookup(&i, in, buf, p_language)) {
X		while (buf[i++] != ';')
X			if (i >= in)
X				goto notpascal;
X		strcat(contents, "PASCAL program text");
X		goto outa;
X	}
X	
X	nl = 0;
X	
X	while (buf[i] != '(') {
X		if (buf[i] <= 0)
X			goto notas;
X		if (buf[i] == ';') {
X			i++;
X			goto checkp;
X		}
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notpascal;
X		if (i >= in)
X			goto notpascal;
X	}
X	
X	while (buf[i] != ')') {
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notpascal;
X		
X		if (i >= in)
X			goto notpascal;
X	}
X	
X	while (strncmp(buf, "then", 4)) {
X		if (buf[i++] == '\n')
X			if (nl++ > 6)
X				goto notpascal;
X		
X		if ((i+3) >= in)
X			goto notpascal;
X	}
X
X	strcat(contents, "PASCAL program text");
X	goto outa;
X
Xnotpascal:
X	i = 0;
X	
X	if (!ascom(&i, in, buf))
X		goto notas;
X	
X	j = i - 1;
X	
X	if (buf[i] == '.') {
X		i++;
X		
X		if (lookup(&i, in, buf, a2_language)) {
X			strcat(contents, "assembler program text");
X			goto outa;
X		}
X		else if ((buf[j] == '\n') && isalpha(buf[j+2])) {
X			strcat(contents, "nroff/troff/eqn/tbl input text");
X			goto outa;
X		}
X	}
X	
X	while (!lookup(&i, in, buf, a_language)) {
X		if (!ascom(&i, in, buf))
X			goto notas;
X		
X		while ((buf[i] != '\n') && (buf[i++] != ':'))
X			if (i >= in)
X				goto notas;
X		
X		while ((buf[i] == '\n') || (buf[i] == ' ') || (buf[i] == '\t'))
X			if (i++ >= in)
X				goto notas;
X		
X		j = i - 1;
X		
X		if (buf[i] == '.') {
X			i++;
X			
X			if (lookup(&i, in, buf, a2_language)) {
X				strcat(contents, "assembler program text");
X				goto outa;
X			}
X			else if ((buf[j] == '\n') && isalpha(buf[j+2])) {
X				strcat(contents, "nroff/troff/eqn/tbl input text");
X				goto outa;
X			}
X		}
X	}
X
X	strcat(contents, "assembler program text");
X	goto outa;
X
Xnotas:
X	if (sbuf.st_mode & ((S_IEXEC) | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
X		strcat(contents, "commands text");
X	else if (troffint(&i, in, buf))
X		strcat(contents, "troff intermediate output text");
X	else if (english(&i, in, buf))
X		strcat(contents, "English text");
X	else
X		strcat(contents, "ASCII text");
X
Xouta:
X	while (i < in) {
X		if ((buf[i++] & 0377) > 127) {
X			strcat(contents, " with garbage");
X			return(contents);
X		}
X	}
X	
X	return(contents);
X}
X
Xoldo(cp, sbuf)
Xchar *cp;
Xstruct stat sbuf;
X{
X	struct exec ex;
X
X	ex = *(struct exec *)cp;
X
X	if (N_STROFF(ex)+sizeof(off_t) > sbuf.st_size)
X		return (1);
X	return (0);
X}
X
Xtroffint(i, n, buf)
Xint *i, n;
Xchar *buf;
X{
X	int k;
X
X	*i = 0;
X	for (k = 0; k < 6; k++) {
X		if (lookup(i, n, buf, t_language) == 0)
X			return(0);
X		while (*i < n && buf[*i] != '\n')
X			(*i)++;
X		if ((*i)++ >= n)
X			return(0);
X	}
X	return(1);
X}
Xlookup(i, in, buf, tab)
Xint *i, in;
Xchar *buf;
Xchar *tab[];
X{
X	char r;
X	int k,j,l;
X
X	while ((buf[*i] == ' ') || (buf[*i] == '\t') || (buf[*i] == '\n'))
X		(*i)++;
X
X	for (j=0; tab[j] != 0; j++) {
X		l=0;
X		
X		for (k = *i; ((r=tab[j][l++]) == buf[k] && r != '\0'); k++);
X
X		if (r == '\0')
X			if ((buf[k] == ' ') || (buf[k] == '\n') || (buf[k] == '\t')
X			    || (buf[k] == '{') || (buf[k] == '/')) {
X				*i = k;
X				return(1);
X			}
X	}
X	return(0);
X}
Xccom(i, in, buf)
Xint *i, in;
Xchar *buf;
X{
X	char cc;
X
X	while ((cc = buf[*i]) == ' ' || cc == '\t' || cc == '\n')
X		if ((*i)++ >= in)
X			return(0);
X
X	if (buf[*i] == '/' && buf[*i+1] == '*'){
X		*i += 2;
X		while (buf[*i] != '*' || buf[*i+1] != '/') {
X			if (buf[*i] == '\\')
X				*i += 2;
X			else 
X				*i++;
X			if (*i >= in)
X				return(0);
X		}
X		if ((*i += 2) >= in)
X			return(0);
X	}
X	if (buf[*i] == '\n')
X		if (ccom(i, in, buf) == 0)
X			return(0);
X	return(1);
X}
Xpcom(i, in, buf)
Xint *i, in;
Xchar *buf;
X{
X	char cc;
X
X	while ((cc = buf[*i]) == ' ' || cc == '\t' || cc == '\n')
X		if ((*i)++ >= in)
X			return(0);
X
X	if (buf[*i] == '(' && buf[*i+1] == '*'){
X		*i += 2;
X		while (buf[*i] != '*' || buf[*i+1] != ')') {
X			if (buf[*i] == '\\')
X				*i += 2;
X			else 
X				*i++;
X			if (*i >= in)
X				return(0);
X		}
X		if ((*i += 2) >= in)
X			return(0);
X	}
X	if (buf[*i] == '\n')
X		if (pcom(i, in, buf) == 0)
X			return(0);
X	return(1);
X}
Xascom(i, in, buf)
Xint *i, in;
Xchar *buf;
X{
X	while ((buf[*i] == '/') || (buf[*i] == '#') || (buf[*i] == ';')) {
X		(*i)++;
X
X		while (buf[(*i)++] != '\n')
X			if (*i >= in)
X				return(0);
X		while (buf[*i] == '\n')
X			if ((*i)++ >= in)
X				return(0);
X	}
X	return(1);
X}
X
Xenglish(i, n, bp)
Xint *i, n;
Xchar *bp;
X{
X#define NASC 128
X
X	int ct[NASC], j, vow, freq, rare;
X	int badpun = 0, punct = 0;
X
X	if (n < 50)
X		return(0); /* no point in statistics on squibs */
X
X	for (j=0; j < NASC; j++)
X		ct[j]=0;
X
X	for (j=0; j < n; j++) {
X		if (bp[j] < NASC)
X			ct[bp[j]|040]++;
X
X		switch (bp[j]) {
X		case '.': 
X		case ',': 
X		case ')': 
X		case '%':
X		case ';': 
X		case ':': 
X		case '?':
X			punct++;
X			if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n')
X				badpun++;
X		}
X	}
X
X	if (badpun*5 > punct)
X		return(0);
X
X	vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
X	freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
X	rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
X
X	if (2*ct[';'] > ct['e']) 
X		return(0);
X	if ((ct['>']+ct['<']+ct['/'])>ct['e']) 
X		return(0); /* shell file test */
X	return(vow*5 >= n-ct[' '] && freq >= 10*rare);
X}
X
X/*
X * itoa - return a character string containing the integer.
X */
Xchar *itoa(n)
Xint n;
X{
X	char *buf, *malloc();
X	
X	buf = malloc(32);
X	
X	sprintf(buf, "%d", n);
X	
X	return(buf);
X}
X
X/*
X * dosecurity - tell about file's security.
X */
Xdosecurity(file)
Xchar *file;
X{
X	printf("\n\tSorry, file security info not implemented yet.\n");
X}
________This_Is_The_END________
echo 'x - lock.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>lock.sh
X#! /bin/sh
X#
X# lock/unlock - lock and unlock files, or current directory by default.
X#
X# Purdue University Engineering Computer Network
X#
X# This program is hereby placed in the public domain, and may
X# be used by anyone for any purpose provided that it is not
X# used or sold for profit and that this notice and the name
X# of the original author appears with all copies of the program.
X#
X
Xmode=go-rwx
Xcase $0 in
X	unlock|*/unlock)	mode=go+rx
Xesac
XPATH=/bin
Xfor name in ${*-.}
Xdo
X	if test ! \( -f $name -o -d $name \)
X	then
X		echo Making directory $name
X		mkdir $name
X	fi
X	/bin/chmod $mode $name
Xdone
________This_Is_The_END________
echo 'x - mkaccessdb.c'
sed 's/^X//' <<'________This_Is_The_END________' >>mkaccessdb.c
Xstatic char *RCSid = "$Header: mkaccessdb.c,v 1.1 84/07/19 09:08:12 root Exp $";
X
X/*
X * mkaccessdb - makes databases for access program
X *
X * This program runs through the password and group files and slurps
X * out the information we need.  It then writes this information out
X * to the files USERFILE and GROUPFILE, where it may be read in by
X * the access program.
X *
X * The purpose for all this is to speed up access' initialization time
X * at the expense of a little bit of disk space.
X *
X * David A. Curry
X * Purdue University Engineering Computer Network
X * July 1984
X *
X * This program is hereby placed in the public domain, and may
X * be used by anyone for any purpose provided that it is not
X * used or sold for profit and that this notice and the name
X * of the original author appears with all copies of the program.
X *
X * $Log:	mkaccessdb.c,v $
X * Revision 1.1  84/07/19  09:08:12  root
X * Initial revision
X * 
X */
X#include "defs.h"
X
X/*
X * Redefine these, since we have slightly different
X * structures to use for building the linked list.
X */
X#undef USIZE
X#undef GSIZE
X#undef USNULL
X#undef GRNULL
X#define GSIZE	sizeof(struct Grp)
X#define USIZE	sizeof(struct User)
X#define GRNULL	(struct Grp *) NULL
X#define USNULL	(struct User *) NULL
X
Xlong nusers;
Xchar *malloc();
Xstruct Grp *ghead, *gtail;
Xstruct User *uhead, *utail;
X
Xmain()
X{
X	struct rlimit rlim;
X	
X	/*
X	 * Push up our limits.
X	 */
X	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
X	
X	setrlimit(RLIMIT_CPU, &rlim);
X	setrlimit(RLIMIT_RSS, &rlim);
X	setrlimit(RLIMIT_DATA, &rlim);
X	setrlimit(RLIMIT_STACK, &rlim);
X	
X	uhead = utail = USNULL;
X	ghead = gtail = GRNULL;
X	
X	/*
X	 * Load the files.
X	 */
X	loaduids();
X	loadgids();
X
X	/*
X	 * Write the files.
X	 */
X	writeuids();
X	writegids();
X}
X
X/*
X * loaduids - load in the password file
X */
Xloaduids()
X{
X	register int nu;
X	struct User *uinsert();
X	register struct User *q;
X	struct passwd *ngetpwent();
X	register struct passwd *p;
X	
X	nu = 0;
X	
X	/*
X	 * Rewind the password file.
X	 */
X	nsetpwent();
X	
X	/*
X	 * Grab entries until we hit EOF.
X	 */
X	while ((p = ngetpwent()) != PNULL) {
X		/*
X		 * Insert the uid into the linked
X		 * list.
X		 */
X		if ((q = uinsert(p->pw_uid)) == USNULL) {
X			fprintf(stderr, "mkaccessdb: out of memory\n");
X			exit(1);
X		}
X		
X		/*
X		 * Permissions and groups are nothing
X		 * for now.
X		 */
X		q->u.perm = 0;
X		q->u.operm = 0;
X		q->u.groups[0] = NOGROUP;
X		strcpy(q->u.uname, p->pw_name);
X
X		nu++;
X	}
X
X	/*
X	 * Don't need the password file anymore.
X	 */
X	nendpwent();
X
X	/*
X	 * Record number of users.
X	 */
X	nusers = nu;
X}
X
X/*
X * loadgids - reads in thr group file and records who's a member of
X *	      what group.
X */
Xloadgids()
X{
X	register int i;
X	register int members;
X	struct Grp *ginsert();
X	register struct Grp *gr;
X	struct group *getgrent();
X	register struct group *g;
X
X	/*
X	 * Rewind the group file.
X	 */
X	setgrent();
X	
X	while ((g = getgrent()) != GNULL) {
X		members = 0;
X		
X		/*
X		 * If there are no members of the group
X		 * listed, then everyone is a member of
X		 * the group.  This is a special case,
X		 * primarily for group "other".
X		 */
X		if (g->gr_mem[0] == NULL) {
X			mark(NULL, g->gr_gid);
X			members = nusers;
X		}
X		else {
X			/*
X			 * Mark each member listed as being in
X			 * the group.
X			 */
X			for (i=0; g->gr_mem[i] != NULL; i++)
X				members += mark(g->gr_mem[i], g->gr_gid);
X		}
X		
X		/*
X		 * Insert the group into the group list.
X		 */
X		if ((gr = ginsert(g->gr_gid)) == GRNULL) {
X			fprintf(stderr, "mkaccessdb: out of memory\n");
X			exit(1);
X		}
X		
X		gr->g.nmembers = members;
X		strcpy(gr->g.gname, g->gr_name);
X	}
X}
X
X/*
X * uinsert - insert a new record for user id u into the linked list.  We
X *	     avoid running through the whole list at all costs.
X */
Xstruct User *uinsert(u)
Xint u;
X{
X	register int uid;
X	register struct User *p, *q;
X	
X	uid = u;
X	
X	/*
X	 * If the head is NULL, we're just starting.
X	 */
X	if (uhead == USNULL) {
X		if ((p = (struct User *) malloc(USIZE)) == USNULL)
X			return(USNULL);
X		
X		uhead = p;
X		utail = p;
X		p->u.uid = uid;
X		p->next = USNULL;
X
X		return(p);
X	}
X	
X	/*
X	 * If uid < the uid in the head of the list, we
X	 * need to insert the new record in front of the
X	 * head.
X	 */
X	if (uid < uhead->u.uid) {
X		if ((p = (struct User *) malloc(USIZE)) == USNULL)
X			return(USNULL);
X		
X		p->u.uid = uid;
X		p->next = uhead;
X		uhead = p;
X		
X		return(p);
X	}
X	
X	/*
X	 * If uid > the uid at the end of the list,
X	 * we simply tack uid onto the end.
X	 */
X	if (uid > utail->u.uid) {
X		if ((p = (struct User *) malloc(USIZE)) ==  USNULL)
X			return(USNULL);
X		
X		p->u.uid = uid;
X		p->next = USNULL;
X		utail->next = p;
X		utail = p;
X		
X		return(p);
X	}
X	
X	/*
X	 * Otherwise, we have to run through the list
X	 * until we find the appropriate place to stick
X	 * the new record.
X	 */
X	p = q = uhead;
X	while (q->u.uid < uid) {
X		p = q;
X		q = q->next;
X	}
X	
X	if ((q = (struct User *) malloc(USIZE)) == USNULL)
X		return(USNULL);
X	
X	q->u.uid = uid;
X	q->next = p->next;
X	p->next = q;
X	
X	return(q);
X}
X
X/*
X * ginsert - insert a new record for group id g into the linked list.  We
X *	     avoid running through the whole list at all costs.
X */
Xstruct Grp *ginsert(g)
Xint g;
X{
X	register int gid;
X	register struct Grp *p, *q;
X	
X	gid = g;
X	
X	/*
X	 * If the head is NULL, we're just starting.
X	 */
X	if (ghead == GRNULL) {
X		if ((p = (struct Grp *) malloc(GSIZE)) == GRNULL)
X			return(GRNULL);
X		
X		ghead = p;
X		gtail = p;
X		p->g.gid = gid;
X		p->next = GRNULL;
X
X		return(p);
X	}
X	
X	/*
X	 * If gid < the gid in the head of the list, we
X	 * need to insert the new record in front of the
X	 * head.
X	 */
X	if (gid < ghead->g.gid) {
X		if ((p = (struct Grp *) malloc(GSIZE)) == GRNULL)
X			return(GRNULL);
X		
X		p->g.gid = gid;
X		p->next = ghead;
X		ghead = p;
X		
X		return(p);
X	}
X	
X	/*
X	 * If gid > the gid at the end of the list,
X	 * we simply tack gid onto the end.
X	 */
X	if (gid > gtail->g.gid) {
X		if ((p = (struct Grp *) malloc(GSIZE)) ==  GRNULL)
X			return(GRNULL);
X		
X		p->g.gid = gid;
X		p->next = GRNULL;
X		gtail->next = p;
X		gtail = p;
X		
X		return(p);
X	}
X	
X	/*
X	 * Otherwise, we have to run through the list
X	 * until we find the appropriate place to stick
X	 * the new record.
X	 */
X	p = q = ghead;
X	while (q->g.gid < gid) {
X		p = q;
X		q = q->next;
X	}
X	
X	if ((q = (struct Grp *) malloc(GSIZE)) == GRNULL)
X		return(GRNULL);
X	
X	q->g.gid = gid;
X	q->next = p->next;
X	p->next = q;
X	
X	return(q);
X}
X
X/*
X * mark - marks user u as being in group g.  If u is NULL, marks
X *	  all users.  Returns 1 or 0 if a given user was found or not.
X */
Xmark(u, g)
Xchar *u;
Xint g;
X{
X	register int i, gid;
X	register char *uname;
X	register struct User *p;
X	
X	uname = u;
X	gid = g;
X	
X	/*
X	 * If uname is NULL, mark every user.
X	 */
X	if (uname == NULL) {
X		p = uhead;
X		while (p != USNULL) {
X			/*
X			 * Skip to first unused entry.
X			 */
X			for (i=0; (i < NGROUPS) && (p->u.groups[i] != NOGROUP); i++);
X			
X			/*
X			 * Mark the group.
X			 */
X			if (i < NGROUPS) {
X				p->u.groups[i] = gid;
X				
X				if (i < (NGROUPS - 1))
X					p->u.groups[i+1] = NOGROUP;
X			}
X
X			p = p->next;
X		}
X		return;
X	}
X	
X	/*
X	 * Find the specific uid we want.
X	 */
X	p = uhead;
X	while ((p != USNULL) && strcmp(p->u.uname, uname))
X		p = p->next;
X	
X	/*
X	 * If we didn't find it, return 0.
X	 */
X	if (p == USNULL)
X		return(0);
X	
X	/*
X	 * Find unused entry.
X	 */
X	for (i=0; (i < NGROUPS) && (p->u.groups[i] != NOGROUP); i++);
X	
X	/*
X	 * Mark it.
X	 */
X	if (i < NGROUPS) {
X		p->u.groups[i] = gid;
X		
X		if (i < (NGROUPS - 1))
X			p->u.groups[i+1] = NOGROUP;
X	}
X	
X	return(1);
X}
X
X/*
X * writeuids - writes out the user structures to USERFILE.
X */
Xwriteuids()
X{
X	register FILE *fp;
X	register struct User *p;
X	
X	if ((fp = fopen(USERFILE, "w")) == NULL)
X		exit(1);
X	
X	p = uhead;
X	
X	while (p != USNULL) {
X		fwrite((char *) &(p->u), sizeof(struct user), 1, fp);
X		p = p->next;
X	}
X	
X	fclose(fp);
X}
X
X/*
X * writegids - writes out the gids to GROUPFILE.
X */
Xwritegids()
X{
X	register FILE *fp;
X	register struct Grp *p;
X	
X	if ((fp = fopen(GROUPFILE, "w")) == NULL)
X		exit(1);
X	
X	p = ghead;
X	
X	while (p != GRNULL) {
X		fwrite((char *) &(p->g), sizeof(struct grp), 1, fp);
X		p = p->next;
X	}
X	
X	fclose(fp);
X}
X
X#ifdef PASSWDBYUID /*------------------------------------------------------*/
X/*
X * Modified getpwent() which tries to use a password file sorted by user
X * id.  If this fails, it uses the regular password file.  The password
X * file sorted by user id should be used if at all possible, it speeds
X * up the initialization process greatly.
X */
Xstatic char PASSWDUID[]		= "/usr/lib/access/passwd.by.uids";
Xstatic char PASSWDNAME[]	= "/etc/passwd";
X
Xstatic FILE *pwf = NULL;
Xstatic char line[BUFSIZ+1];
Xstatic struct passwd passwd;
X
Xnsetpwent()
X{
X	if (pwf == NULL) {
X		if ((pwf = fopen(PASSWDUID, "r")) == NULL)
X			pwf = fopen(PASSWDNAME, "r");
X	}
X	else {
X		rewind(pwf);
X	}
X}
X
Xnendpwent()
X{
X	if (pwf != NULL) {
X		fclose(pwf);
X		pwf = NULL;
X	}
X}
X
Xstatic char *pwskip(p)
Xregister char *p;
X{
X	while (*p && *p != ':')
X		++p;
X	if (*p)
X		*p++ = 0;
X	return(p);
X}
X
Xstruct passwd *ngetpwent()
X{
X	register n;
X	register char *p;
X
X	if (pwf == NULL) {
X		if ((pwf = fopen(PASSWDUID, "r")) == NULL)
X			if ((pwf = fopen(PASSWDNAME, "r")) == NULL)
X				return(NULL);
X	}
X	
X	p = fgets(line, BUFSIZ, pwf);
X
X	if (p == NULL || *p == '\0')
X		return(NULL);
X
X	passwd.pw_name = p;
X	p = pwskip(p);
X	passwd.pw_passwd = p;
X	p = pwskip(p);
X	passwd.pw_uid = atoi(p);
X	p = pwskip(p);
X	passwd.pw_gid = atoi(p);
X	p = pwskip(p);
X	passwd.pw_gecos = p;
X	passwd.pw_comment = p;
X	passwd.pw_quota = atoi(p);
X	p = pwskip(p);
X	passwd.pw_dir = p;
X	p = pwskip(p);
X	passwd.pw_shell = p;
X	while (*p && *p != '\n')
X		p++;
X	*p = '\0';
X
X	return(&passwd);
X}
X#endif PASSWDBYUID /*-------------------------------------------------------*/
________This_Is_The_END________
echo 'x - mkaccesspw.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>mkaccesspw.sh
X#! /bin/sh
X#
X# Shell file to make the user and group files used by the
X# access program.
X#
X# David A. Curry
X# Purdue University Engineering Computer Network
X# July 1984
X#
X# This program is hereby placed in the public domain, and may
X# be used by anyone for any purpose provided that it is not
X# used or sold for profit and that this notice and the name
X# of the original author appears with all copies of the program.
X#
X
XPATH=/bin:/usr/bin
Xexport PATH
X
XPASS=/etc/passwd
XFILE=/tmp/access$$
XDEST=/usr/lib/access/passwd.by.uids
X
Xlimit filesize u
Xsort -t: +2n $PASS -o $FILE
X
Xset `ls -ls $PASS`
Xmode1=$5
X
Xset `ls -ls $FILE`
Xmode2=$5
X
Xif test $mode1 = $mode2
Xthen
X	mv $FILE $DEST
X	chmod 644 $DEST
Xelse
X	echo "" > /dev/console
X	echo "mkaccesspw: sort or copy error, remake $DEST by hand" > /dev/console
X	echo "" > /dev/console
Xfi
X
X/usr/lib/access/mkaccessdb 2> /dev/console
________This_Is_The_END________
exit