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