[comp.sources.misc] submission to source.misc - setuid shell...

mjr@osiris.UUCP (Marcus J. Ranum) (12/09/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	sushfunc.c
#	sushhelp.c
#	sushlex.c
#	sushmain.c
#	sushpath.c
#	sushperm.c
#	sushtree.c
#	sushuser.c
#	sush.h
#	Makefile
#	sush.8l
#	sushperm.5l
# This archive created: Fri Dec  4 09:11:33 1987
echo shar: extracting README '(794 characters)'
sed 's/^XX//' << \SHAR_EOF > README
XX#static char *RCSid = "$Header: README,v 1.1 87/11/24 17:35:24 mjr Exp $"
XX#	$Author: mjr $
XX#	$Log:	README,v $
XX# Revision 1.1  87/11/24  17:35:24  mjr
XX# Initial revision
XX# 
XX
XX	This is the source code and existing documentation for a 
XXprivileged shell. Typically it's more useful on development systems
XXand in trusted environments. It allows a systems admin to 'grant'
XXthe power to run certain programs as root on a user/group basis.
XXThe problem of shell escapes in the granted programs renders sush
XXless than 100% secure :-)
XX
XX	Some stylistic flaws:
XXLots of global variables. All the globals are listed in sush.h
XXUnfortunately, this makes it hard to run recursive 'sources'.
XX
XX	Options:
XXif ROOTRC is defined, it will add code in sushmain.c that tries to
XXsource a root owned .sushrc file.
XX
XX--mjr();
SHAR_EOF
if test 794 -ne "`wc -c README`"
then
echo shar: error transmitting README '(should have been 794 characters)'
fi
echo shar: extracting sushfunc.c '(5541 characters)'
sed 's/^XX//' << \SHAR_EOF > sushfunc.c
XX
XX#ifndef lint
XXstatic char *RCSid = "2:$Header: sushfunc.c,v 1.3 87/11/24 17:35:45 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushfunc.c,v $
XX * Revision 1.3  87/11/24  17:35:45  mjr
XX * fixed the source() function as well as the cd() to home if no args
XX * 
XX * Revision 1.2  87/11/19  14:22:47  mjr
XX * improved functionality of the environment variables.
XX * 
XX * Revision 1.1  87/11/08  18:19:18  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX
XXset()
XX{
XX	int	ind =0;
XX	int	lng;
XX	unsigned	mal1;
XX	unsigned	mal2;
XX
XX	/* set an environment variable */
XX	/* we assume the args are parsed (they must be to get here) */
XX	/* and flip through the envir stack looking for a blank slot*/
XX	/* when we find one we malloc the memory and copy into it. */
XX
XX	if(sh.shrgn == 1)
XX		return(prenv());
XX
XX	/* is the thing verbose? - if so set it */
XX	/* and immediately return */
XX	if((!strcmp(sh.sharg[1],"verbose")) || !(strcmp(sh.sharg[1],"-x"))) {
XX		verbose++;
XX		return(0);
XX	}
XX
XX	
XX	/* see if args is right and all */
XX	if((sh.shrgn != 4) || (strcmp(sh.sharg[2],"="))) {
XX		fprintf(stderr,"syntax: set string = string\n");
XX		return(1);
XX	} 
XX
XX	lng = strlen(sh.sharg[1]);
XX
XX	/* otherwise OK */
XX	/* search for the victim and free its memory space */
XX	for(ind = 0; ind < SHENV; ind++) { 
XX		if(!strncmp(sh.shenv[ind],sh.sharg[1],lng)) {
XX			/* next thing must be an = sign */
XX			if(sh.shenv[ind][lng] == '=') {
XX				if(sh.shenv[ind])
XX					(void)free(sh.shenv[ind]);
XX				sh.shenv[ind] = '\0';
XX			}
XX		}
XX	}
XX
XX	/* skip occupied environment space */
XX	ind = 0;
XX	while((sh.shenv[ind]) && (ind < SHENV))
XX		ind++;
XX
XX	/* if there is room for another shell var */
XX	if(ind < SHENV) {
XX		mal1 = (unsigned)(strlen(sh.sharg[1]));
XX		mal2 = (unsigned)(strlen(sh.sharg[3]));
XX		/* allocate the memory and make the name copy */
XX		if((sh.shenv[ind] = malloc(mal1 + mal2 + 3)) == NULL) {
XX			perror("set");
XX			return(1);
XX		}
XX		(void)strcpy(sh.shenv[ind],sh.sharg[1]);
XX		(void)strcat(sh.shenv[ind],"=");
XX		(void)strcat(sh.shenv[ind],sh.sharg[3]);
XX
XX	} else {
XX		fprintf(stderr,"set: out of environment space\n");
XX		return(1);
XX	}
XX
XX	/* is the thing the prompt ? - if so reset it */
XX	if(!strcmp(sh.sharg[1],"prompt")) {
XX		prompt = &sh.shenv[ind][mal1+1];
XX		return(0);
XX	}
XX
XX	/* is the thing the PATH ? - if so reset it */
XX	if(!strcmp(sh.sharg[1],"PATH")) {
XX		path = &sh.shenv[ind][mal1+1];
XX		return(0);
XX	}
XX
XX	/* otherwise OK */
XX	if(verbose)
XX		fprintf(stderr,"%s set\n",sh.sharg[1]);
XX	return(0);
XX}
XX
XXunset()
XX{
XX	int	ind;
XX	int 	mal1;
XX	int	ind2;
XX
XX	/* unset an environment variable */
XX	/* we assume the args are parsed (they must be to get here) */
XX	/* and flip through the envir stack looking for the named slot*/
XX	/* when we find it we free the memory and zero it. */
XX	
XX	/* is the thing verbose? - if so set it */
XX	/* and immediately return */
XX	if((!strcmp(sh.sharg[1],"verbose")) || !(strcmp(sh.sharg[1],"-x"))) {
XX		verbose =0;
XX		return(0);
XX	}
XX
XX	/* see if args is right and all */
XX	if(sh.shrgn != 2 ) {
XX		fprintf(stderr,"syntax: unset string\n");
XX		return(1);
XX	} 
XX
XX	/* is the thing the PATH ? - if so complain */
XX	if(!strcmp(sh.sharg[1],"PATH")) {
XX		fprintf(stderr,"why unset PATH?\n");
XX		return(1);
XX	}
XX
XX	/* used for length of search */
XX	mal1 = strlen(sh.sharg[1]);
XX
XX	/* otherwise OK */
XX	/* search for the victim and free its memory space */
XX	for(ind = 0; ind < SHENV; ind++) { 
XX		if(!strncmp(sh.shenv[ind],sh.sharg[1],mal1)) {
XX			/* next thing must be an = sign */
XX			if(sh.shenv[ind][mal1] == '=') {
XX				(void)free(sh.shenv[ind]);
XX				sh.shenv[ind] = '\0';
XX			}
XX			for (ind2 = 0; sh.shenv[ind + ind2 + 1]; ind2++) {
XX				sh.shenv[ind + ind2] = sh.shenv[ind + ind2 + 1];
XX				sh.shenv[ind + ind2 + 1] = '\0';
XX			}
XX			if(verbose)
XX				fprintf(stderr,"%s unset\n",sh.sharg[1]);
XX			return(0);
XX		}
XX	}
XX	
XX	fprintf(stderr,"unset: no environment variable %s\n",sh.sharg[1]);
XX	return(1);
XX}
XX
XXprenv()
XX{
XX	int	i;
XX	int	mal1;
XX
XX	/* print an environment variable or all of them */
XX	
XX	/* if one arg print whole environment */
XX	if(sh.shrgn == 1 ) {
XX		/* print all occupied environment space */
XX		for(i =0; i < SHENV; i++) {
XX			if(sh.shenv[i])
XX				if(*sh.shenv[i])
XX					printf("%s\n",sh.shenv[i]);
XX		}
XX		return(0);
XX	} else {
XX		/* search for the named variable and print it */
XX
XX		/* get the length */
XX		mal1 = strlen(sh.sharg[1]);
XX		for(i = 0; i < SHENV; i++) { 
XX			if(!strncmp(sh.shenv[i],sh.sharg[1],mal1)) {
XX				if(sh.shenv[i][mal1 + 1] == '=') {
XX					printf("%s\n",sh.shenv[i]);
XX					return(0);
XX				}
XX			}
XX		}
XX	}
XX	fprintf(stderr,"printenv: no environment variable %s\n",sh.sharg[1]);
XX	return(1);
XX}
XX
XXbye()
XX{
XX	/* if exit number given */
XX	if(sh.shrgn >= 2 )
XX		exit(atoi(sh.sharg[1]));
XX
XX	/* exit with 0 */
XX	exit(0);
XX}
XX
XXcd()
XX{
XX	/* change current working directory */
XX	/* if no args use home */
XX	if(sh.shrgn == 1) {
XX		if(chdir(home)) {
XX			perror(home);
XX			return(1);
XX		}
XX		return(0);
XX	}
XX	
XX	/* see if args is right and all */
XX	if(sh.shrgn != 2 ) {
XX		fprintf(stderr,"syntax: cd [directory]\n");
XX		return(1);
XX	}
XX
XX	if(chdir(sh.sharg[1])) {
XX		perror(sh.sharg[1]);
XX		return(1);
XX	}
XX	return(0);
XX}
XX
XXpwd()
XX{
XX
XX	/* print current working directory */
XX	
XX	/* see if args is right and all */
XX	if(sh.shrgn > 1 ) {
XX		fprintf(stderr,"syntax: pwd\n");
XX		return(1);
XX	}
XX	printf("%s\n",getwd(".")); 
XX		
XX	return(0);
XX}
XX
XXsource()
XX{
XX	FILE	*sourcin;
XX	int	savttyin = isttyin;
XX	
XX	if(sh.shrgn != 2) {
XX		fprintf(stderr,"syntax: source file\n");
XX		return(1);
XX	}
XX	if((sourcin = fopen(sh.sharg[1], "r")) == NULL) {
XX		perror(sh.sharg[1]);
XX	} else {
XX		isttyin = 0;
XX		(void)doinput(sourcin);
XX		(void)fclose(sourcin);
XX		isttyin = savttyin;
XX	}
XX	return(0);
XX}
SHAR_EOF
if test 5541 -ne "`wc -c sushfunc.c`"
then
echo shar: error transmitting sushfunc.c '(should have been 5541 characters)'
fi
echo shar: extracting sushhelp.c '(631 characters)'
sed 's/^XX//' << \SHAR_EOF > sushhelp.c
XX
XX#ifndef lint
XXstatic char *RCSid = "3:$Header: sushhelp.c,v 1.2 87/11/19 14:23:13 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushhelp.c,v $
XX * Revision 1.2  87/11/19  14:23:13  mjr
XX * added clearer help messages
XX * 
XX * Revision 1.1  87/11/08  18:19:20  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX
XXhelp()
XX{
XX	struct	cmdtab	*dptr;
XX
XX	fprintf(stderr,"Internal Commands Are:\n");
XX	dptr = cm;
XX	while(dptr -> func) {
XX		fprintf(stderr,"%s\n",dptr->mnem);
XX		dptr++;
XX	}
XX	fprintf(stderr,"Note - I/O redirection is not supported, nor are ");
XX	fprintf(stderr,"filename expansion or history.\n");
XX	return(0);
XX}
SHAR_EOF
if test 631 -ne "`wc -c sushhelp.c`"
then
echo shar: error transmitting sushhelp.c '(should have been 631 characters)'
fi
echo shar: extracting sushlex.c '(3455 characters)'
sed 's/^XX//' << \SHAR_EOF > sushlex.c
XX
XX#ifndef lint
XXstatic char *RCSid = "4:$Header: sushlex.c,v 1.3 87/11/24 16:19:12 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushlex.c,v $
XX * Revision 1.3  87/11/24  16:19:12  mjr
XX * added inline macro expansion in command line
XX * 
XX * Revision 1.2  87/11/19  14:23:33  mjr
XX * cleaned up parser code a bit.
XX * 
XX * Revision 1.1  87/11/08  18:19:21  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX#include <ctype.h>
XX
XXstatic	char	*copymac();
XX
XXlex(str)
XXchar	*str;
XX{
XX	char	*bufptr;
XX
XX	/* analyze input string - break it into tokens */
XX	sh.shrgn =0;
XX	bufptr = str;
XX
XX	/* actually perform the parse */
XX	while(bufptr = wordparse(bufptr,sh.sharg[sh.shrgn],0)) {
XX
XX		/* set the token pointers to token - this sucks */
XX		sh.shtok[sh.shrgn] = sh.sharg[sh.shrgn];
XX
XX		/* increment token number */
XX		sh.shrgn++;
XX	}
XX	sh.shtok[sh.shrgn] = NULL;
XX	return(0);
XX}
XX
XXchar *
XXwordparse(line,word,delim)
XXchar	*line,	*word;
XXint	delim;
XX{
XX	int	quot =0;
XX
XX	/* skip whitespace or delims */
XX	while (*line && (isspace(*line) || *line == delim))
XX		line++;
XX
XX	if(*line == '\n')
XX		line++;
XX
XX	/* if end of string, return */
XX	if (!*line) {
XX		*word = '\0';
XX		return(0);
XX	}
XX
XX	while (*line)
XX	{
XX		/* if its a quote character and we are not in a quoted */
XX		/* string we then set the quote character to match this */
XX		/* one (or end of line) */
XX		if(!quot && (*line == '\"' || *line == '\''))
XX			quot = *line++;
XX
XX		/* spaces get skipped unless were in a quoted string */ 
XX		/* if the current character is a matching quote we unset */
XX		/* the quotation and keep parsing */
XX		if((isspace(*line) || *line == delim) && !quot) {
XX			break;
XX		} else {
XX			if(quot && *line == quot) {
XX				quot = 0;
XX				line++;
XX			} else {
XX				*word++ = *line++;
XX			}
XX		}
XX	}
XX	/* null the end of the word and return an ptr to where we are */
XX	*word = '\0';
XX	return(line);
XX}
XX
XXexpline(line,retline,vars)
XXchar	*line;
XXchar	*retline;
XXchar	**vars;
XX{
XX
XX	/* expline - expand macros in a string and place the expanded */
XX	/* string in retline. retline is assumed to be long enough. */
XX	/* vars is assumed to be an array of strings that are in the */
XX	/* form of: thing=thing  - note - recursion not supported yet */
XX	/* function returns nonzero in event of error */
XX	
XX	char	*pti = line;
XX	char	*pto = retline;
XX	char	vbuf[400];
XX	char	*vbpt;
XX
XX	if(!pti)
XX		return(0);
XX
XX	while(*pti) {
XX		/* $ indicates start of possible macro */
XX		if(*pti != '$') {
XX			*pto++ = *pti++;
XX		} else {
XX			if(*++pti != '\(') {
XX				/* not a macro */
XX				*pto++ = *pti++;
XX			} else {
XX				/* get macroname into vbuf */
XX				vbpt = vbuf;
XX				++pti;
XX				while(*pti != '\)') { 
XX					if(pti) {
XX						*vbpt++ = *pti++;
XX					} else {	
XX						return(-1);
XX					} 
XX				}
XX				*vbpt = '\0';
XX				/* increment past last paren */
XX				pti++;
XX				if((pto = copymac(vbuf,pto,vars)) == '\0')
XX					return(-1);
XX			}
XX		}
XX	}
XX	*pto = '\0';
XX	return(0);
XX}
XX
XXstatic	char	*
XXcopymac(mac,out,varlist)
XXchar	*mac;
XXchar	*out;
XXchar	**varlist;
XX{
XX	/* copy the identified macro into the string we are handed */
XX	/* return a pointer to where we leave off, or NULL if we fail */ 
XX	char	**vpt = varlist;
XX	char	*ptr;
XX	int	lng;
XX
XX
XX	/* return if no macros defined */
XX	if(!*vpt)
XX		return(out);
XX
XX	/* save time if empty macro */
XX	if((lng = strlen(mac)) ==0)
XX		return(out);
XX
XX	while(vpt) {
XX		if((strncmp(*vpt,mac,lng) ==0) && ((*vpt)[lng] == '=')) {
XX		/* copy contents of macro into string */
XX			ptr = *vpt + lng +1;
XX			while(*ptr)
XX				*out++ = *ptr++;
XX			break;
XX		}
XX	vpt++;
XX	}
XX	return(out);
XX}
SHAR_EOF
if test 3455 -ne "`wc -c sushlex.c`"
then
echo shar: error transmitting sushlex.c '(should have been 3455 characters)'
fi
echo shar: extracting sushmain.c '(3164 characters)'
sed 's/^XX//' << \SHAR_EOF > sushmain.c
XX#ifndef lint
XXstatic char RCSid[] = "5:$Header: sushmain.c,v 1.5 87/11/24 17:34:43 mjr Exp $";
XX#endif
XX
XX/*
XX *	$Author: mjr $
XX *	$Log:	sushmain.c,v $
XX * Revision 1.5  87/11/24  17:34:43  mjr
XX * added the source() feature and .sushrc
XX * 
XX * Revision 1.4  87/11/24  16:18:50  mjr
XX * added inline macro expansion in command line.
XX * 
XX * Revision 1.3  87/11/19  14:22:21  mjr
XX * dropped newline off the end of input buffer before logging it.
XX * 
XX * Revision 1.2  87/11/19  14:10:43  mjr
XX * fixed interrupt handling so shell wouldn't exit on ^C from tty
XX * 
XX * Revision 1.1  87/11/08  18:19:22  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#define	NOEXTERN
XX#include "sush.h"
XX#include <stdio.h>
XX#include <syslog.h>
XX#include <sys/signal.h>
XX
XXextern char **environ;
XX
XXmain()
XX{
XX	register char **ep;
XX
XX	(void)signal(SIGINT,SIG_IGN);
XX	if(getuser())
XX		exit(1);
XX
XX	if(loadperm())
XX		exit(1);
XX
XX	/* make a copy of our environment - actually just point to it */
XX	if (environ) {
XX		int ind = 0;
XX		for (ep = environ; *ep; ep++, ind++)
XX			sh.shenv[ind] = *ep;
XX		path = getenv("PATH");
XX	}
XX
XX	/* if not a tty, dont print prompt */
XX	if(!isatty(fileno(stdin)))
XX		isttyin = 0;
XX	
XX	/* set default prompt */
XX	prompt = "xsh> ";
XX
XX#ifdef ROOTRC
XX	/* 'source' a static .sushrc file if any */
XX	/* we pass a fmt string to userrc to allow this. */
XX	/* later sprintf() is used to build the path */
XX	/* by adding 'home' in. This is possibly gross */
XX	(void)userrc("/etc/.sushrc");
XX#endif
XX
XX	/* 'source' a user's .sushrc file if any */
XX	(void)userrc("%s/.sushrc");
XX
XX	/* 'source' the standard input */ 
XX	exit(doinput(stdin));
XX}
XX
XXdoinput(inp)
XXFILE *inp;
XX{
XX	int	(*ptr)();
XX	char	*bptr;
XX	struct	cmdtab	*dptr;
XX
XX	/* loop forever reading from input FILE */
XX	while(1) {
XX		if(isttyin)
XX			printf("%s",prompt);
XX		if((fgets(sh.shbuf,SHBUF,inp)) == NULL) 
XX			return(0);
XX
XX		/* perform macro expansion if needed */
XX		if(expline(sh.shbuf,sh.shexb,sh.shenv)) {
XX			fprintf(stderr,"INTERNAL error in macro expansion\n");
XX		}
XX
XX		/* parse it - use the expanded buffer */
XX		if(lex(sh.shexb)) { 
XX			fprintf(stderr,"INTERNAL error in lexical analysis\n");
XX			break;
XX		}
XX		
XX		/* if no tokens, skip to read */
XX		if(sh.shrgn == 0)
XX			continue;
XX
XX		/* in case of verbosity, be verbose */
XX		if(verbose)
XX			fprintf(stderr,"%s",sh.shexb);
XX
XX		/* drop the last newline from input buffer */
XX		if(bptr = rindex(sh.shexb,'\n'))
XX			*bptr = '\0';
XX
XX		/* log the input buffer */
XX		(void)syslog(LOG_NOTICE,"sush:<%s> %s",user,sh.shexb);
XX
XX		/* set dispatch function pointer */
XX		dptr = cm;
XX
XX		while(dptr -> func) {
XX			if(!strcmp(dptr->mnem,sh.sharg[0])) {
XX				ptr = dptr->func;
XX				break;
XX			}
XX			dptr++;
XX		}
XX		if(!dptr->mnem) {
XX			(void)dopath();
XX		} else {
XX			(void)((*ptr)());
XX		}
XX	}
XXreturn(0);
XX}
XX
XXuserrc(fmt)
XXchar	*fmt;
XX{
XX	char	pathbuf[900];
XX	int	savttyin = isttyin;
XX	FILE	*rcp;
XX
XX	/* source a file if user's home dir has a .sushrc file */
XX	/* note fmt is passed to us - this is grotty but can */
XX	/* be used to pass a default .sushrc also. */
XX	/* see comment where userrc is called. */
XX
XX	(void)sprintf(pathbuf,fmt,home);
XX	if((rcp = fopen(pathbuf, "r")) == NULL)
XX		return(1);
XX
XX	isttyin = 0;
XX	(void)doinput(rcp);
XX	(void)fclose(rcp);
XX	isttyin = savttyin;
XX
XXreturn(0);
XX}
SHAR_EOF
if test 3164 -ne "`wc -c sushmain.c`"
then
echo shar: error transmitting sushmain.c '(should have been 3164 characters)'
fi
echo shar: extracting sushpath.c '(2369 characters)'
sed 's/^XX//' << \SHAR_EOF > sushpath.c
XX
XX#ifndef lint
XXstatic char *RCSid = "6:$Header: sushpath.c,v 1.2 87/11/19 14:10:26 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushpath.c,v $
XX * Revision 1.2  87/11/19  14:10:26  mjr
XX * fixed interrupt handling so shell wouldn't exit on ^C from tty
XX * 
XX * Revision 1.1  87/11/08  18:19:23  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX#include <syslog.h>
XX#include <sys/types.h>
XX#include <sys/stat.h>
XX#include <sys/wait.h>
XX#include <sys/signal.h>
XX
XXdopath()
XX{
XX	char	*todo;
XX	char	**alist = sh.shtok;
XX	char	**envptr = sh.shenv;
XX	int	child, ret;
XX	union	wait	status;
XX
XX	todo = xpath(sh.sharg[0]);
XX	if(!todo) {
XX		fprintf(stderr,"\"%s\" not found\n",sh.sharg[0]);
XX		return(1);
XX	}
XX
XX	if(!search(top,todo)) {
XX		(void)syslog(LOG_NOTICE,"sush:%s FAILED permission %s",user,todo);
XX		fprintf(stderr,"\"%s\" permission denied\n",todo);
XX		return(1);
XX	}
XX
XX	/* do it */
XX	if ((child = vfork()) == 0) {
XX		(void)signal(SIGINT,SIG_DFL);
XX		execve(todo,alist,envptr);
XX		perror(todo);
XX		_exit(127);
XX	}
XX
XX	if(child < 0) {
XX		perror("vfork");
XX	}
XX
XX	while ((ret = wait(&status)) != child && ret != -1);
XX
XX	if(verbose && status.w_T.w_Retcode)
XX		fprintf(stderr,"\"%s\" returns %d\n",todo,status.w_T.w_Retcode);
XX
XX	/* done it */
XX	return(0);
XX}
XX
XXchar	*
XXxpath(exe)
XXchar	*exe;
XX{
XX	char	*ptr;
XX	char	*p;
XX	static	char	pbuf[SHENV];	/* thing to build path in */
XX	static	struct	stat	stbuf;	/* stat buffer */
XX
XX	/* read the path and search for the first thing that matches */
XX	/* the name of the program */
XX
XX	/* first check if absolut path */
XX	if(exe[0] == '/') {
XX		/* if stat(2) fails return NULL */
XX		if(stat(exe,&stbuf)) {
XX			return((char *)NULL);
XX		} else {
XX			return(exe);
XX		}
XX	}
XX
XX	/* check to see if pathname is a relative path or not */
XX	/* IE - it has a '/' in it 	*/
XX	if((p = index(exe,'/')) != 0) {
XX		(void)strcpy(pbuf,".");
XX		if((p = getwd(pbuf)) == 0) {
XX			perror(p);
XX			return((char *)NULL);
XX		}
XX		(void)strcat(pbuf,"/");
XX		(void)strcat(pbuf,exe);
XX		if(stat(pbuf,&stbuf)) {
XX			return((char *)NULL);
XX		} else {
XX			return(pbuf);
XX		}
XX	}
XX
XX	/* last but not least, search the PATH */
XX	ptr = path;
XX	p = pbuf;
XX
XX	/* somewhat gnarly */
XX	while(*ptr) {
XX		p = pbuf;
XX		while(*ptr && *ptr != ':') {
XX			*p++ = *ptr++;
XX		}
XX		*p++ = '\0';
XX		(void)strcat(pbuf,"/");
XX		(void)strcat(pbuf,exe);
XX		if(!stat(pbuf,&stbuf)) {
XX			return(pbuf);
XX		}
XX		if(*ptr = ':')
XX			ptr++;
XX	} 
XX	return((char *)NULL);
XX}
SHAR_EOF
if test 2369 -ne "`wc -c sushpath.c`"
then
echo shar: error transmitting sushpath.c '(should have been 2369 characters)'
fi
echo shar: extracting sushperm.c '(2594 characters)'
sed 's/^XX//' << \SHAR_EOF > sushperm.c
XX
XX#ifndef lint
XXstatic char *RCSid = "7:$Header: sushperm.c,v 1.2 87/11/19 14:21:41 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushperm.c,v $
XX * Revision 1.2  87/11/19  14:21:41  mjr
XX * cleaner logging format and more specific messages for error conditions.
XX * 
XX * Revision 1.1  87/11/08  18:19:24  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX#include <syslog.h>
XX#include <grp.h>
XX
XXloadperm()
XX{
XX	char	inbuf[BUFSIZ];
XX	FILE	*fp;
XX	int	linenum =0;
XX
XX	if((fp = fopen(PERMFILE,"r")) == NULL) {
XX		perror(PERMFILE);
XX		return(1);
XX	} 
XX	while(fgets(inbuf,BUFSIZ,fp) != NULL) {
XX		linenum++;
XX		/* skip comments */
XX		if(inbuf[0] != '#') {
XX			if(tokenperm(inbuf,linenum))
XX				return(1);
XX		}
XX	}
XX	return(0);
XX}
XX
XXtokenperm(str,linenum)
XXchar	*str;
XXint	linenum;
XX{
XX	static	char	cmbuf[SHTOK];
XX	char	*bptr;
XX
XX	bptr = str;
XX	/* tokenize - or is it tokenate ? */
XX	if(bptr = wordparse(bptr,cmbuf,',')) {
XX
XX		/* parse it as a group */
XX		if(!strcmp(cmbuf,"group")) {
XX			return(addgroup(bptr,linenum)); 
XX		}
XX
XX		/* parse it as a user */
XX		if(!strcmp(cmbuf,"user")) {
XX			return(adduser(bptr,linenum)); 
XX		}
XX
XX		/* puke */
XX		fprintf(stderr,"bad \"%s\" %s line %d\n",str,PERMFILE,linenum);
XX		(void)syslog(LOG_NOTICE,"sush:sushperm line %d bad",linenum);
XX		return(1);
XX	}
XXreturn(0);
XX}
XX
XXadduser(str,lineno)
XXchar	*str;
XXint	lineno;
XX{
XX	static	char	buf[SHTOK];
XX	char	*bptr;
XX
XX	bptr = str;
XX
XX	/* this should be the username */
XX	if((bptr = wordparse(bptr,buf,',')) == '\0') {
XX		fprintf(stderr,"bad user in %s line %d\n",PERMFILE,lineno);
XX		(void)syslog(LOG_NOTICE,"sush:sushperm line %d user bad",lineno);
XX		return(1);
XX	}
XX
XX	/* not us - dont add the files */
XX	if(strcmp(user,buf))
XX		return(0);
XX
XX	while((bptr = wordparse(bptr,buf,','))!= '\0') {
XX		/* link it in */
XX		if(insert(&top,buf)) 
XX			return(1);
XX	}
XXreturn(0);
XX}
XX
XXaddgroup(str,lineno)
XXchar	*str;
XXint	lineno;
XX{
XX	static	char	buf[SHTOK];
XX	char	*bptr;
XX	struct	group	*gpt;
XX	int	ok =0;
XX	char	**gpmem;
XX
XX	bptr = str;
XX
XX	/* this should be the group name */
XX	if((bptr = wordparse(bptr,buf,',')) == '\0') {
XX		fprintf(stderr,"bad group in %s line %d\n",PERMFILE,lineno);
XX		(void)syslog(LOG_NOTICE,"sush:sushperm line %d group bad",lineno);
XX		return(1);
XX	}
XX	
XX	if((gpt = getgrnam(buf)) == NULL) {
XX		fprintf(stderr,"vapor group in %s line %d\n",PERMFILE,lineno);
XX		(void)syslog(LOG_NOTICE,"sush:sushperm line %d group bad",lineno);
XX		return(0);
XX	}
XX	gpmem = gpt->gr_mem;
XX	while(*gpmem++) {
XX		if(!strcmp(user,*gpmem))
XX			ok++;
XX	}
XX
XX	/* auth failed - return */
XX	if(!ok)
XX		return(0);
XX
XX	while(bptr = wordparse(bptr,buf,',')) {
XX		if(insert(&top,buf)) 
XX			return(1);
XX	}
XXreturn(0);
XX}
SHAR_EOF
if test 2594 -ne "`wc -c sushperm.c`"
then
echo shar: error transmitting sushperm.c '(should have been 2594 characters)'
fi
echo shar: extracting sushtree.c '(1681 characters)'
sed 's/^XX//' << \SHAR_EOF > sushtree.c
XX
XX#ifndef lint
XXstatic char *RCSid = "8:$Header: sushtree.c,v 1.2 87/11/19 14:23:57 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushtree.c,v $
XX * Revision 1.2  87/11/19  14:23:57  mjr
XX * cleaned up parser code a bit.
XX * 
XX * Revision 1.1  87/11/08  18:19:25  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX
XXinsert(curr,newcom)
XXstruct	leaf	**curr;
XXchar	*newcom;
XX{
XX	int ret;
XX
XX	/* current leaf is empty */
XX	if(*curr == NULL) {
XX		/* add-a-leaf */
XX		*curr = (struct leaf *)malloc((unsigned)sizeof(struct leaf));
XX		if(*curr == NULL) {
XX			perror("malloc");
XX			return(1);
XX		}
XX		(*curr)->cmd = malloc((unsigned)(strlen(newcom)+1));
XX		if((*curr)->cmd == NULL) {
XX			perror("malloc");
XX			return(1);
XX		}
XX		(void)strcpy((*curr)->cmd,newcom);
XX		(*curr)->lptr = NULL;
XX		(*curr)->rptr = NULL;
XX		return(0);
XX	}
XX
XX	/* fall through if match - no need to save */
XX	ret = strcmp((*curr)->cmd,newcom);
XX	if(ret >0)
XX		return(insert(&(*curr)->rptr,newcom));
XX	if(ret <0)
XX		return(insert(&(*curr)->lptr,newcom));
XX
XXreturn(0);
XX}
XX
XXsearch(curr,newcom)
XXstruct	leaf	*curr;
XXchar	*newcom;
XX{
XX
XX	int ret;
XX
XX	/* current leaf is empty - not found */
XX	if(curr == NULL) {
XX		return(0);
XX	}
XX
XX	/* if ! match - search appropriate branch */
XX	ret = strcmp(curr->cmd,newcom);
XX	if(ret >0)
XX		return(search(curr->rptr,newcom));
XX	if(ret <0)
XX		return(search(curr->lptr,newcom));
XX
XX	return(1);
XX}
XX
XXshopriv()
XX{
XX	fprintf(stderr,"You are privileged to execute the following:\n");
XX	return(leafdump(top));
XX}
XX
XXleafdump(curr)
XXstruct	leaf	*curr;
XX{
XX	/* current leaf is empty - not found */
XX	if(curr == NULL) {
XX		return(0);
XX	}
XX	(void)leafdump(curr->rptr);
XX	(void)leafdump(curr->lptr);
XX	printf("%s\n",curr->cmd);
XX
XX	return(0);
XX}
SHAR_EOF
if test 1681 -ne "`wc -c sushtree.c`"
then
echo shar: error transmitting sushtree.c '(should have been 1681 characters)'
fi
echo shar: extracting sushuser.c '(1315 characters)'
sed 's/^XX//' << \SHAR_EOF > sushuser.c
XX
XX#ifndef lint
XXstatic char *RCSid = "9:$Header: sushuser.c,v 1.3 87/11/24 17:36:24 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sushuser.c,v $
XX * Revision 1.3  87/11/24  17:36:24  mjr
XX * added code to preserve home external envir variable
XX * 
XX * Revision 1.2  87/11/19  14:24:03  mjr
XX * improved calls to syslog - dropped newlines
XX * 
XX * Revision 1.1  87/11/08  18:19:27  mjr
XX * Initial revision
XX * 
XX*/
XX
XX#include "sush.h"
XX#include <stdio.h>
XX#include <pwd.h>
XX#include <syslog.h>
XX
XXchar	*crypt();
XXchar	*getpass();
XX
XXstruct	passwd	*getpwuid();
XX
XXgetuser()
XX{
XX	struct	passwd	*pwt;	/* passwd struct */
XX	char	*uspass;	/* user password */
XX	char	*crpass;	/* crypted password */
XX	int	cleared =3;	/* cleared to fly */
XX
XX	 if((pwt = getpwuid(getuid())) == NULL) {
XX		fprintf(stderr,"WHO ARE YOU! !!!\n");
XX		exit(1);
XX	}
XX
XX	/* we assume your version of getpwent preserves the */
XX	/* stuff it returns. Ours does. */
XX	user = pwt->pw_name;
XX	home = pwt->pw_dir;
XX
XX	/* validate login */
XX	while(1 == 1) {
XX		uspass = getpass("Your Login Password:");
XX		crpass = crypt(uspass,pwt->pw_passwd);
XX		if(strcmp(crpass,pwt->pw_passwd)) {
XX			fprintf(stderr,"incorrect.\n");
XX			if(!--cleared)
XX				(void)syslog(LOG_NOTICE,"sush:BADlog %s",user);
XX				exit(4);
XX		} else {
XX			break;
XX		}
XX	}
XX	(void)syslog(LOG_NOTICE,"sush:login %s",user);
XX
XXreturn(0);
XX}
SHAR_EOF
if test 1315 -ne "`wc -c sushuser.c`"
then
echo shar: error transmitting sushuser.c '(should have been 1315 characters)'
fi
echo shar: extracting sush.h '(2328 characters)'
sed 's/^XX//' << \SHAR_EOF > sush.h
XX
XX#ifndef lint
XXstatic char *RCSidG = "1:$Header: sush.h,v 1.3 87/11/24 17:36:45 mjr Exp $";
XX#endif
XX
XX/*
XX * 	$Author: mjr $
XX * 	$Log:	sush.h,v $
XX * Revision 1.3  87/11/24  17:36:45  mjr
XX * added code to preserve home external envir variable
XX * 
XX * Revision 1.2  87/11/24  16:19:04  mjr
XX * added inline macro expansion in command line.
XX * 
XX * Revision 1.1  87/11/08  18:19:17  mjr
XX * Initial revision
XX * 
XX*/
XX
XX
XX/* should be adequate for basic shell - not heavy-duty */
XX#define	SHBUF	2048
XX#define	SHTOK	64
XX#define	SHARG	40
XX#define	SHENV	1024
XX
XXstruct	shglob	{
XX	char	shbuf[SHBUF];		/* general scratch mem */
XX	char	shexb[SHBUF];		/* macro expansion buffer */
XX	char	*shprm[SHTOK];		/* pointers to permitted progs */
XX	char	*shtok[SHTOK];		/* pointers to tokens */
XX	char	*shenv[SHENV];		/* pointers to environment variables */
XX	char	sharg[SHTOK][SHARG];	/* strings of shell args */
XX	int	shrgn;			/* number of shell args */
XX};
XX
XXstruct	cmdtab	{
XX	char	*mnem;			/* command name */
XX	int	(*func)();		/* pointer to func */
XX};
XX
XXstruct	leaf	{
XX	char	*cmd;
XX	struct	leaf	*lptr;
XX	struct	leaf	*rptr;
XX};
XX
XX	
XX/* function definitions */
XXextern	int	set(), unset(), prenv(), bye();
XXextern	int	cd(), pwd(), help(), shopriv();
XXextern	int	source();
XXextern	char	*malloc();
XXextern	char	*wordparse();
XXextern	char	*strcpy();
XXextern	char	*strcat();
XXextern	char	*getenv();
XXextern	char	*xpath();
XXextern	char	*index();
XXextern	char	*rindex();
XXextern	char	*getwd();
XXextern	struct	group	*getgrnam();
XX
XX#ifdef	NOEXTERN
XX
XX/* this version actually allocates memory */
XX/* only the main() module should define NOEXTERN */
XXchar	*prompt;			/* pointer to user prompt */
XXchar	*path;				/* pointer to user path */
XXchar	*user;				/* pointer to user name */
XXchar	*home;				/* pointer to user home dir */
XXchar	verbose =0;			/* set -x */
XXchar	isttyin =1;			/* is input from a tty ? */
XXstruct	shglob	sh;			/* shell global struct */
XXstruct	leaf	*top = 0;		/* permissions list tree */
XXstruct	cmdtab	cm[] = {
XX	"set",		set,
XX	"cd",		cd,
XX	"pwd",		pwd,
XX	"unset",	unset,
XX	"exit",		bye,
XX	"printenv",	prenv,
XX	"?",		help,
XX	"help",		help,
XX	"source",	source,
XX	"showpriv",	shopriv,
XX	0,	0
XX	};
XX
XX#else
XX
XXextern	char	*path;
XXextern	char	*user;
XXextern	char	*home;
XXextern	struct	leaf	*top;
XXextern	struct	shglob	sh;
XXextern	struct	cmdtab	cm[];
XXextern	char	*prompt;
XXextern	char	verbose;
XXextern	char	isttyin;
XX
XX#endif
SHAR_EOF
if test 2328 -ne "`wc -c sush.h`"
then
echo shar: error transmitting sush.h '(should have been 2328 characters)'
fi
echo shar: extracting Makefile '(1744 characters)'
sed 's/^XX//' << \SHAR_EOF > Makefile
XX
XX#static char *RCSid = "$Header: Makefile,v 1.7 87/11/24 17:35:04 mjr Exp $";
XX#/*
XX#	$Author: mjr $
XX#	$Log:	Makefile,v $
XX# Revision 1.7  87/11/24  17:35:04  mjr
XX# added more detail on define options
XX# 
XX# Revision 1.6  87/11/19  14:46:02  mjr
XX# final tweeks(?) .
XX# 
XX# Revision 1.5  87/11/19  14:42:28  mjr
XX# more futzing around.
XX# 
XX# Revision 1.4  87/11/19  14:37:26  mjr
XX# added doc into make dependencies. 
XX# 
XX# Revision 1.3  87/11/19  14:33:00  mjr
XX# added make install.
XX# 
XX# Revision 1.2  87/11/19  14:27:33  mjr
XX# forgot to put Makefile in dependency list !!
XX# 
XX# Revision 1.1  87/11/08  18:19:15  mjr
XX# Initial revision
XX# 
XX#*/
XX
XX.SUFFIXES:
XX.SUFFIXES: .c .o
XX
XX.DEFAULT:
XX	co $@
XX
XXDEST = /etc/local
XXDOC = sushperm.l sush.l
XX
XX#must be defined as pathname to permissions file.
XX#DEFINES= -DPERMFILE=\"/etc/local/sushperm\" -DROOTRC
XX
XXDEFINES= -DPERMFILE=\"/u1/mjr/hacks/sh/myperm\"
XX
XXCFLAGS= -OG -s -n $(DEFINES)
XX#CFLAGS= -gx $(DEFINES)
XX
XXOBJ=	sushmain.o\
XX	sushlex.o\
XX	sushpath.o\
XX	sushperm.o\
XX	sushuser.o\
XX	sushtree.o\
XX	sushhelp.o\
XX	sushfunc.o
XX
XX
XXsush:	$(OBJ)
XX	cc $(CFLAGS) -o sush $(OBJ) 
XX
XX$(OBJ): sush.h Makefile
XX
XXclean:
XX	rm -f *.o sush
XX
XXlint:
XX	lint $(DEFINES) *.c
XX
XXshar:
XX	shar -a README *.c *.h Makefile sush.8l sushperm.5l > sush.shar
XX
XXinstall: $(DOC) sush
XX	cp sush $(DEST)/sush
XX	chown root $(DEST)/sush
XX	chmod 4511 $(DEST)/sush
XX	cp sush.l /usr/man/manl
XX	chmod 744 /usr/man/manl/sush.l
XX	cp sushperm.l /usr/man/manl
XX	chmod 744 /usr/man/manl/sushperm.l
XX
XX#documentation !!
XXsush.l:		sush.8l
XX	cp sush.8l sush.l
XXsushperm.l:	sushperm.5l
XX	cp sushperm.5l sushperm.l
XX
XX#for RCS
XXsushlex.o:	sushlex.c
XXsushmain.o:	sushmain.c
XXsushpath.o:	sushpath.c
XXsushperm.o:	sushperm.c
XXsushuser.o:	sushuser.c
XXsushtree.o:	sushtree.c
XXsushhelp.o:	sushhelp.c
XXsushfunc.o:	sushfunc.c
SHAR_EOF
if test 1744 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 1744 characters)'
fi
echo shar: extracting sush.8l '(5046 characters)'
sed 's/^XX//' << \SHAR_EOF > sush.8l
XX.TH sush 8-local
XX.SH NAME
XXsush \- SuperUser shell
XX.fi
XX.ad
XX.hy 0
XX.SH ORIGIN
XXmjr@osiris.UUCP 
XX.SH SYNOPSIS
XX.B sush
XX.SH DESCRIPTION
XX.B Sush
XXis a restricted shell that allows systems administrators to
XXgrant specific limited priviledges to users.   All commands that are
XXexecuted are logged to the system log,   as well as other pertinent
XXinformation.
XX.SH AUTHORIZATION
XX.B Sush
XXreads an authorization file at start-up time.   This file contains a
XXlist of group and user names,   each followed by a list of pathnames
XXto programs they are allowed to run.   The user's password is checked,
XXto ensure that someone has not broken into that account.   Thereafter,
XXusers are prompted,   just as in a "normal" shell,   commands are parsed,
XXand executed if the user has permission to execute them.
XX.SH "INTERNAL COMMANDS"
XX.PP
XX.B set 
XX.B [
XXvariable
XX.B ] = [
XXstring
XX.B ]
XX.PP
XXIf called without arguments,   the set command shows a list of currently
XXdefined environment variables.   If called with arguments in the form of
XXstring = string (spaces necessary) the specified environment variable 
XXis set,   or reset.
XX.PP
XX.B cd
XX.PP
XXThe cd command allows the user to reset the current working directory.
XX.PP
XX.B pwd
XX.PP
XXThe pwd command will print the current working directory.
XX.PP
XX.B unset variable
XX.PP
XXUnset,   when provided an environment variable name,   will unset that 
XXenvironment variable.
XX.PP
XX.B exit
XX.PP
XXExits from the shell.   An EOF will also exit the shell.
XX.PP
XX.B source filename
XX.PP
XXWill read the file into the shell as commands.
XX.PP
XX.B printenv
XX.PP
XXThe printenv command lists all current environment variables.
XX.PP
XX.B ? or help
XX.PP
XXThe "?" and help commands provide a list of shell internals.
XX.PP
XX.SH "THE .sushrc FILE"
XX.PP
XXAt startup
XX.I Sush
XXwill read a 
XX.I .sushrc
XXfile if there is one in the user's home directory. This functions
XXexactly like the 
XX.B source
XXinternal command. If the last line in the 
XX.I .sushrc
XXis exit, the shell will exit. This can be used to more exactly control a 
XXuser.
XX.SH "THE ENVIRONMENT"
XX.I Sush
XXmaintains a copy of the invocation environment,  including the PATH,
XXTERM and other useful variables.  These are passed whenever a command
XXis invoked,  so that programs such as Ingres and Sybase that rely on
XXenvironment variables will still work properly.
XX.SH "ENVIRONMENT VARIABLES"
XX.PP
XXEnvironment variables are substituted in the command line if they
XXare surrounded by $().  Thus something like:
XX.br
XX\fIecho  $(PATH)\fP
XX.br
XX.PP
XXwill echo the contents of PATH.  Recursion is not supported - IE:
XX.nf
XX.na
XX.br
XX\fIset FOO = "this is $(BAR)"\fP
XX\fIecho $(FOO)\fP
XX\fBthis is $(BAR)\fP
XX.fi
XX.ad
XX.SH "DIFFERENCES FROM A REAL SHELL"
XX.I Sush 
XXintentionally does not support many features found in a \fIREAL\fP
XXUNIX shell,   since they allow unauthorized access too easily.
XX.PP
XX.I "I/O Redirection:"
XX.I Bourne
XXor
XX.I Csh 
XXconstructs like \fB"ls | more"\fP are not supported,   since it entails
XXan additional level of parsing in the command line.  Constructs such
XXas \fB"ls > foo"\fP are also unsupported,   for obvious reasons.
XX.PP
XX.I "Globbing:"
XXGlobbing,   or wildcard expansion,   is not supported,   since it renders it
XXmore difficult to determine what command a user wants to execute.  A
XXcommand like \fB"/etc/vip*"\fP,   which could expand to \fB"/etc/vipw"\fP
XXso the shell would have to re-parse the command line multiple times.
XX.SH "COMMAND EXECUTION"
XXCommands are executed by searching the PATH environment variable for the
XXcommand that is requested.  If the command is found,  the complete pathname
XXis checked against the list of user's permissions.  If the filename is in
XXthe permission list,  it is executed,  and the execution is logged to the
XXsystem log file,  along with the arguments it was invoked with.  The way
XXin which the path is parsed makes calls like \fB"/bin/../bin/ls"\fP to
XXbe rejected.
XX.SH "A SAMPLE RUN"
XX.nf
XX\fB
XXxsh> \fIshowpriv\fP
XXYou are privileged to execute the following:
XX/bin/grep
XX/bin/kill
XX/bin/echo
XX/bin/csh
XX/bin/ls
XX/ingres/bin/accessdb
XX/usr/ucb/w
XX/bin/who
XX/bin/sh
XXxsh> \fI?\fP
XXInternal Commands Are:
XXset
XXcd
XXpwd
XXunset
XXexit
XXprintenv
XX?
XXhelp
XXshowpriv
XXNote - I/O redirection,   filename expansion and history,   not supported.
XXxsh> \fIls\fP
XXMakefile    sush.8l     sushhelp.c  sushmain.c  sushperm.c  sushuser.c
XXRCS         sush.h      sushhelp.o  sushmain.o  sushperm.o  sushuser.o
XXxsh> \fIvipw\fP
XX"/etc/vipw" permission denied
XXxsh> \fIexit\fP
XX.fi
XX\fR
XX.SH "SEE ALSO"
XXsyslog(8),   sh(1),   sushperm(5l)
XX.SH MESSAGES
XX.IP "vapor group in /u1/mjr/hacks/sh/myperm line 3" 10
XX.br
XX.I Sush
XXfound a group in the permissions file that does not exist in /etc/group.
XXThis is logged as a potential security hole.
XX.SH BUGS
XX.PP
XXSignal handling is not perfect.
XX.PP
XXAny commands that contain a shell escape (vi,   more,   ingres editor,   
XXetc,   etc) are
XXa potential loophole.   Additionally,   there is the problem of a user with the
XXability to do anything that would alter a security file.   IE - someone with
XXthe ability to chmod /etc/passwd.   There is no way around this.
XX.\"	@(#)sush.8l Tue Nov 10 20:52:17 EST 1987
SHAR_EOF
if test 5046 -ne "`wc -c sush.8l`"
then
echo shar: error transmitting sush.8l '(should have been 5046 characters)'
fi
echo shar: extracting sushperm.5l '(1729 characters)'
sed 's/^XX//' << \SHAR_EOF > sushperm.5l
XX.TH SUSHPERM 5-local
XX.SH NAME
XXsushperm \- suid shell permissions database
XX.SH SYNOPSIS
XX/etc/local/sushperm
XX.SH DESCRIPTION
XX.I Sushperm
XXis a data base describing users,  groups,  and pathnames of programs
XXthat they are allowed to execute as "root".
XX.PP
XXEntries in
XX.I sushperm
XXconsist of a number of fields.
XXThe first entry for each field consists of the word "user" or "group"
XXto indicate whether the next field is specifying the permissions for
XXa single user,  or a group.  The second field is the name of the user
XXor group in question.  User names are expected to be in \fB"/etc/passwd"\fP
XXand groups are expected to be in \fB"/etc/group"\fP.  
XXThe remainder of the line consists of comma or space separated entries
XXthat list the complete PATHnames of programs that the user or group
XXin question is privileged to run.  
XX.PP
XXUser's permissions are cumulative,  so that a user's total permissions 
XXwill be the sum of that user's entries,  plus the sum of all groups in
XXwhich that user is a member.  Badly formatted lines in the 
XX.I sushperm
XXfile are ignored,  as are lines beginning with a \fB'#'\fP.
XX.fi
XX.PP
XX.B A Sample Entry
XX.PP
XX.nf
XX
XX# sample sushperm file
XXgroup e+o /bin/sh, /bin/ls, /bin/csh
XXgroup sys /bin/echo,  /bin/kill
XXuser ken /bin/sh, /bin/ls, /bin/cat
XXuser mjr /bin/kill,  /bin/grep,  /bin/who,  /usr/ucb/w
XXuser mjr /etc/shutdown,  /etc/halt,  /etc/reboot
XX
XX.fi
XX.PP
XXEntries for a particular user may appear on several lines with a cumulative
XXeffect.
XX.SH DIAGNOSTICS
XX.I sush
XXwill complain of it finds nonexistent groups or user names in the
XX.I sushperm
XXfile.
XX.SH FILES
XX.DT
XX/etc/local/sushperm - permissions file.
XX.SH SEE ALSO
XXsush(8l)
XX.br
XX.SH BUGS
XXNone known at present.
XX.\"	@(#)sushperm.5l	Tue Nov 17 10:02:59 EST 1987
SHAR_EOF
if test 1729 -ne "`wc -c sushperm.5l`"
then
echo shar: error transmitting sushperm.5l '(should have been 1729 characters)'
fi
#	End of shell archive
exit 0