home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / super-2.0 / part01 next >
Encoding:
Text File  |  1993-07-06  |  71.7 KB  |  2,702 lines

  1. Newsgroups: comp.sources.unix
  2. From: will@surya.caltech.edu (Will Deich)
  3. Subject: v26i292: super-2.0 - allow certain users to use certain commands as root, Part01/01
  4. Sender: unix-sources-moderator@gw.home.vix.com
  5. Approved: vixie@gw.home.vix.com
  6.  
  7. Submitted-By: will@surya.caltech.edu (Will Deich)
  8. Posting-Number: Volume 26, Issue 292
  9. Archive-Name: super-2.0/part01
  10.  
  11. Super(1) is a small program that allows users to execute other programs
  12. (particularly scripts) as root, without unduly compromising security.
  13.  
  14. Sample uses:
  15.     -  to call a script that allows users to use mount(8) on
  16.     cdrom's or floppy disks, but not other devices.
  17.  
  18.     -  to call a script that allows users to send STOP/CONT
  19.     signals to certain jobs, but not others.
  20.  
  21.     -  to restrict which users, on which hosts, may execute a
  22.     setuid-root program.
  23.  
  24.     -------------------
  25.  
  26. What's new for version 2.0:
  27.     A.  A couple of bugfixes.  (These fixes were first introduced
  28.         in version 1.2.)
  29.  
  30.     B.  You can restrict commands to particular users on particular
  31.         hosts.  This allows one "super.tab" file to serve many hosts.
  32.  
  33.     C.  Entries in "super.tab" can now span multiple lines.  Helpful
  34.         when one file serves many users + hosts.
  35.  
  36.     D.  csh-style brace-expansion:  super's pattern-matching previously
  37.         was done with the BSD 4.x regex routines.  This is now extended
  38.         allow csh-style braces.  For instance, to allow users pam and
  39.         to execute a command from hosts alpha and beta, you can
  40.         use an entry like {pam,sammy}@{alpha,beta}
  41.  
  42.     -------------------
  43.  
  44. A "super.tab" file names each command that super is willing to execute, and
  45. says who can use it. It contains lines like:
  46.  
  47.     command   fullpathname    valid-user/group/host ed-type patterns
  48.  
  49. To execute a super command, type
  50.  
  51.     % super command [args...]
  52.  
  53. If <command> is "-h" or "-?", or missing, super prints its current
  54. list of allowed commands, but nothing is executed.
  55.  
  56. If a user is allowed to execute a given <command>, the <fullpathname>
  57. is exec'd, with <command> as argv[0].  The superuser is always
  58. allowed to execute any super command.
  59.  
  60. For security, the environment variables are discarded, save for TERM,
  61. LINES, and COLUMNS.  If TERM contains any characters other than
  62. [a-z][A-Z][0-9]_, it is discarded.  If LINES or COLUMNS contains any
  63. characters other than [0-9], they are discarded.  To these are added
  64. reasonable values for IFS, PATH, USER and HOME (USER and HOME are set
  65. to the username and login directory, respectively, of the person who
  66. who runs super).  LOGNAME is set to the same as USER.  SUPERCMD is set
  67. to the <command>.  All descriptors excepting 0,1,2 are closed.  Signals
  68. are all reset to have default handling.
  69.  
  70.     --------------------
  71.  
  72.     /* Will Deich
  73.      * Caltech  105-24, Pasadena, CA 91125
  74.      * Internet: will@surya.caltech.edu
  75.      */
  76.  
  77. #! /bin/sh
  78. # This is a shell archive.  Remove anything before this line, then unpack
  79. # it by saving it into a file and typing "sh file".  To overwrite existing
  80. # files, type "sh file -c".  You can also feed this as standard input via
  81. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  82. # will see the following message at the end:
  83. #        "End of archive 1 (of 1)."
  84. # Contents:  MANIFEST Makefile README approve.c braces.c getlogdir.c
  85. #   ingroup.c re_fail.c regex.c sample.cdmount sample.tab super.1
  86. #   super.c version.h word.c
  87. # Wrapped by vixie@gw.home.vix.com on Wed Jul  7 01:39:17 1993
  88. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  89. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  90.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  91. else
  92. echo shar: Extracting \"'MANIFEST'\" \(579 characters\)
  93. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  94. X   File Name        Archive #    Description
  95. X-----------------------------------------------------------
  96. X MANIFEST                   1    This shipping list
  97. X Makefile                   1    
  98. X README                     1    
  99. X approve.c                  1    
  100. X braces.c                   1    
  101. X getlogdir.c                1    
  102. X ingroup.c                  1    
  103. X re_fail.c                  1    
  104. X regex.c                    1    
  105. X sample.cdmount             1    
  106. X sample.tab                 1    
  107. X super.1                    1    
  108. X super.c                    1    
  109. X version.h                  1    
  110. X word.c                     1    
  111. END_OF_FILE
  112. if test 579 -ne `wc -c <'MANIFEST'`; then
  113.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  114. fi
  115. # end of 'MANIFEST'
  116. fi
  117. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  118.   echo shar: Will not clobber existing file \"'Makefile'\"
  119. else
  120. echo shar: Extracting \"'Makefile'\" \(1484 characters\)
  121. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  122. XBINDIR=/usr/local/bin
  123. XMANDIR=/usr/man/manl
  124. XMANEXT=l
  125. X
  126. X# Things to set or unset in CFLAGS:
  127. X
  128. X# 1.  USE_NETGROUP: if you want hostnames like `+xxx' to mean NIS netgroup xxx,
  129. X#    define USE_NETGROUP in CFLAGS; otherwise comment it out.
  130. X
  131. X# 2.  MAXFD: if you don't have the system call getdtablesize() to return the
  132. X#    number of file descriptors, define
  133. X#        MAXFD=<expression to give max value of a file descr>.
  134. X#    If MAXFD not defined, getdtablesize() is used.
  135. X#    Examples:     -DMAXFD=63    -- hardwired for 64 max descriptors;
  136. X#            -DMAXFD="sysconf(_SC_OPEN_MAX)-1" -- HP-UX 8.x, 9.x
  137. X
  138. X# 3.  SUPERFILE: if you want the superfile to be other than
  139. X#    /usr/local/lib/super.tab, add -DSUPERFILE=FullPathName
  140. XCFLAGS= -O -DUSE_NETGROUP    # -DMAXFD=63  -DSUPERFILE=/etc/super.tab
  141. X
  142. X# SunOS: Link statically to avoid possible security holes in dynamic linking.
  143. X# Most other OS's: comment out next line, or use equivalent.
  144. XLDFLAGS=-Bstatic
  145. X
  146. X####################################################################
  147. X
  148. XSRC= super.c approve.c ingroup.c word.c getlogdir.c regex.c re_fail.c braces.c version.h
  149. XOBJ= super.o approve.o ingroup.o word.o getlogdir.o regex.o re_fail.o braces.o
  150. XALL= README Makefile super.1 sample.tab sample.cdmount $(SRC)
  151. X
  152. Xall: super
  153. X
  154. Xsuper: $(OBJ)
  155. X    $(CC) $(LDFLAGS) -o super $(OBJ)
  156. X
  157. Xapprove.o: version.h
  158. X    $(CC) $(CFLAGS) -c approve.c
  159. X
  160. Xinstall:
  161. X    cp super $(BINDIR)
  162. X    chmod 04755 $(BINDIR)/super
  163. X    cp super.1 $(MANDIR)/super.$(MANEXT)
  164. X
  165. Xclean:
  166. X    rm -f super *.o
  167. Xshar: $(ALL)
  168. X    shar $(ALL) > super.shar
  169. END_OF_FILE
  170. if test 1484 -ne `wc -c <'Makefile'`; then
  171.     echo shar: \"'Makefile'\" unpacked with wrong size!
  172. fi
  173. # end of 'Makefile'
  174. fi
  175. if test -f 'README' -a "${1}" != "-c" ; then 
  176.   echo shar: Will not clobber existing file \"'README'\"
  177. else
  178. echo shar: Extracting \"'README'\" \(5308 characters\)
  179. sed "s/^X//" >'README' <<'END_OF_FILE'
  180. XSuper(1) is a small program that allows users to execute other programs
  181. X(particularly scripts) as root, without unduly compromising security.
  182. X
  183. XSample uses:
  184. X    -  to call a script that allows users to use mount(8) on
  185. X    cdrom's or floppy disks, but not other devices.
  186. X
  187. X    -  to call a script that allows users to send STOP/CONT
  188. X    signals to certain jobs, but not others.
  189. X
  190. X    -  to restrict which users, on which hosts, may execute a
  191. X    setuid-root program.
  192. X
  193. X-------------------
  194. XWhat's new for version 2.0:
  195. X    A.  A couple of bugfixes.  (These fixes were first introduced
  196. X        in version 1.2.)
  197. X
  198. X    B.  You can restrict commands to particular users on particular
  199. X        hosts.  This allows one "super.tab" file to serve many hosts.
  200. X
  201. X    C.  Entries in "super.tab" can now span multiple lines.  Helpful
  202. X        when one file serves many users + hosts.
  203. X
  204. X    D.  csh-style brace-expansion:  super's pattern-matching previously
  205. X        was done with the BSD 4.x regex routines.  This is now extended
  206. X        allow csh-style braces.  For instance, to allow users
  207. X        pam and sammy, executing from hosts alpha and beta, you can
  208. X        use an entry like {pam,sammy}@{alpha,beta}
  209. X
  210. X-------------------
  211. X
  212. XA "super.tab" file names each command that super is willing to execute, and
  213. Xsays who can use it. It contains lines like:
  214. X
  215. X    command   fullpathname    valid-user/group/host ed-type patterns
  216. X
  217. XTo execute a super command, type
  218. X
  219. X    % super command [args...]
  220. X
  221. XIf <command> is "-h" or "-?", or missing, super prints its current
  222. Xlist of allowed commands, but nothing is executed.
  223. X
  224. XIf a user is allowed to execute a given <command>, the <fullpathname>
  225. Xis exec'd, with <command> as argv[0].  The superuser is always
  226. Xallowed to execute any super command.
  227. X
  228. XFor security, the environment variables are discarded, save for TERM,
  229. XLINES, and COLUMNS.  If TERM contains any characters other than
  230. X[a-z][A-Z][0-9]_, it is discarded.  If LINES or COLUMNS contains any
  231. Xcharacters other than [0-9], they are discarded.  To these are added
  232. Xreasonable values for IFS, PATH, USER and HOME (USER and HOME are set
  233. Xto the username and login directory, respectively, of the person who
  234. Xwho runs super).  LOGNAME is set to the same as USER.  SUPERCMD is set
  235. Xto the <command>.  All descriptors excepting 0,1,2 are closed.  Signals
  236. Xare all reset to have default handling.
  237. X
  238. X--------------------
  239. X
  240. XAcknowledgements:
  241. X    For the regular-expression code: Ozan Yigit's regex routines,
  242. X    plus the BSD brace-expansion code.
  243. X
  244. X--------------------
  245. X
  246. XMaking and installation:
  247. X
  248. XThe Makefile is only about 40 lines long.  Modify it to suit yourself.
  249. XYou have to be root to install super, as it must run setuid root.
  250. X
  251. XMany SysV-derived Unix's don't have the getdtablesize() routine which
  252. Xreturns the maximum value allowed for a file descriptor.  In that case,
  253. Xuse -DMAXFD=nnn when compiling, and it will be used instead of getdtablesize().
  254. X
  255. XBy default, super expects to find its table of valid commands+users/groups/hosts
  256. Xin /usr/local/lib/super.tab.  If you change this, you must also change the
  257. Xdocumentation.
  258. X
  259. XA sample super.tab file is found in sample.tab.
  260. X
  261. XOne sample script is enclosed: sample.cdmount, to mount cd-rom's under SunOS.
  262. X
  263. X--------------------
  264. XTesting the entries in super.tab:
  265. X
  266. XYou can test if super is restricting users properly by putting a
  267. Xharmless entry like
  268. X
  269. X    ECHO        /bin/echo       <a user/group/host pattern to test>
  270. X
  271. Xin your super.tab file, then typing
  272. X
  273. X    % super ECHO arg1 arg2 arg3
  274. X    
  275. X--------------------
  276. XNotes on super scripts:
  277. X
  278. X1.  Scripts run via super(1) must start "#!/bin/sh" (or whatever interpreter
  279. X    is being used).
  280. X
  281. X2.  It's nice to be able to type something like
  282. X    % cdmount
  283. X    instead of
  284. X    % super cdmount
  285. X
  286. X    You can make your script automatically execute super on
  287. X    itself by starting a script in the following manner:
  288. X
  289. X    #!/bin/sh
  290. X    prog=`basename $0`
  291. X    test "$SUPERCMD" = "$prog" || exec /usr/local/bin/super $prog "$@"
  292. X
  293. X
  294. X3.  Some variants of csh will not run setuid scripts unless the -b flag
  295. X    (force a "break" from option processing) is set:
  296. X    #!/bin/csh -fb
  297. X
  298. X4.  Some programs need certain directories in the path.  Your
  299. X    super scripts may have to add directories like /etc or /usr/etc
  300. X    to make commands work.  One common problem for SunOS 4.x users is
  301. X    that /usr/etc has to be in the path in order to mount HSFS-format
  302. X    cd-rom's.
  303. X
  304. X
  305. X5.  Super only changes the effective uid.  Some programs (e.g. exportfs
  306. X    under SunOS 4.1.x) require the real uid to be root.  In that case,
  307. X    your super script will have to change the real uid to root before
  308. X    executing the command.
  309. X
  310. X6.  A brief security comment:
  311. X    You must be exceedingly careful when writing scripts for super.
  312. X    A surprising variety of seemingly-ordinary commands can, when
  313. X    run setuid-root, be exploited to nasty purpose.  Always make your
  314. X    scripts do as little as possible, and give the user as few options
  315. X    as possible.
  316. X
  317. X    Think twice about side-effects and alternative uses of these
  318. X    scripts.  For instance, you might write a script to allow users to
  319. X    mount cd-rom's by executing mount(8).  But if you don't write it
  320. X    carefully, a user could mount a floppy disk containing, say, a
  321. X    setuid-root shell.
  322. X
  323. X--------------------
  324. X
  325. X/* Will Deich
  326. X * Caltech  105-24, Pasadena, CA 91125
  327. X * Internet: will@surya.caltech.edu
  328. X */
  329. END_OF_FILE
  330. if test 5308 -ne `wc -c <'README'`; then
  331.     echo shar: \"'README'\" unpacked with wrong size!
  332. fi
  333. # end of 'README'
  334. fi
  335. if test -f 'approve.c' -a "${1}" != "-c" ; then 
  336.   echo shar: Will not clobber existing file \"'approve.c'\"
  337. else
  338. echo shar: Extracting \"'approve.c'\" \(12888 characters\)
  339. sed "s/^X//" >'approve.c' <<'END_OF_FILE'
  340. X#include <stdio.h>
  341. X#include <string.h>
  342. X#include <ctype.h>
  343. X#include <pwd.h>
  344. X
  345. X#include "version.h"
  346. X
  347. Xstatic char SccsId[] = "@(#)approve.c    1.9\t7/6/93" ;
  348. X
  349. X/*
  350. X *    Copyright (c) 1993 by California Institute of Technology.
  351. X *    Written by William Deich.  Not derived from licensed software.
  352. X
  353. X *    Permission is granted to anyone to use this software for any
  354. X *    purpose on any computer system, and to redistribute it freely,
  355. X *    subject to the following restrictions:
  356. X *
  357. X *    1. The author is not responsible for the consequences of use of this
  358. X *       software, no matter how awful, even if they arise from defects in it.
  359. X *
  360. X *    2. The origin of this software must not be misrepresented, either
  361. X *       by explicit claim or by omission.
  362. X *
  363. X *    3. Altered versions must be plainly marked as such, and must not
  364. X *       be misrepresented as being the original software.
  365. X */
  366. X
  367. X
  368. Xstatic FILE *fp;
  369. X
  370. Xextern errno;
  371. X
  372. X#define MIN(a,b) ((a) < (b) ? (a) : (b))
  373. X#define UNTIL(e) while(!(e))
  374. X
  375. X
  376. Xextern char *user;
  377. Xextern char *prog;
  378. X
  379. X/* approve() returns:
  380. X *    - NULL ptr if error:
  381. X *        a) username not found;
  382. X *        b) superfile can't be opened for reading;
  383. X *        c) no such command as usrcmd in superfile;
  384. X *        d) user not allowed to execute this command.
  385. X *    - ptr to empty string if all ok, but no program should be executed.
  386. X *    - ptr to path of file to exec, if user allowed to do so.
  387. X *    Any error also generates a message to stderr.
  388. X
  389. X * New calls to approve() overwrite the buffer containing the returned path.
  390. X */
  391. X
  392. Xstruct Ebuf {        /* an expandable buffer */
  393. X    char *buf;
  394. X    int l;
  395. X    int nalloc;
  396. X};
  397. Xstatic struct Ebuf ebuf = { NULL, 0, 0 };
  398. X
  399. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  400. X/* For printing the errors uncovered in matching user/group/host patterns */
  401. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  402. Xchar *
  403. Xpaterror(errmsg, origtext, line, nl, file)
  404. Xchar *errmsg;
  405. Xchar *origtext;    /* the original text with the problem pattern */
  406. Xint line, nl;    /* the first line + number of lines in the input block */
  407. Xchar *file;    /* the input file */
  408. X{
  409. X    if (nl <= 1)
  410. X    (void) fprintf(stderr, "%s: %s.  Line %d in file `%s'\n",
  411. X                prog, errmsg, line, file);
  412. X    else
  413. X    (void) fprintf(stderr, "%s: %s.  Lines %d..%d in file `%s'\n",
  414. X                prog, errmsg, line, line+nl-1, file);
  415. X    (void) fprintf(stderr, "\tOffending text: %s\n", origtext);
  416. X    return errmsg;
  417. X}
  418. X
  419. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  420. X/* Copies in to out, prefixing with "^" and suffixing with "$"
  421. X * if these are missing.
  422. X */
  423. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  424. Xvoid
  425. Xanchor(in, out)
  426. Xchar *in;
  427. Xchar *out;
  428. X{
  429. X    int i;
  430. X    i = (*in != '^');
  431. X    if (i)
  432. X    out[0] = '^';
  433. X    (void) strcpy(out+i, in);
  434. X    i = strlen(out);
  435. X    if (out[i-1] != '$')
  436. X    out[i++] = '$';
  437. X    out[i] = '\0';
  438. X}
  439. X
  440. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  441. X/* Grow an expandable buffer by 2K */
  442. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  443. Xchar *
  444. Xgrow(cb)
  445. Xstruct Ebuf *cb;
  446. X{
  447. X    char *realloc(), *malloc();
  448. X    if (cb->buf)
  449. X    cb->buf = realloc(cb->buf, cb->nalloc += 2048);
  450. X    else
  451. X    cb->buf = malloc(cb->nalloc += 2048);
  452. X
  453. X    return cb->buf;
  454. X}
  455. X
  456. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  457. X/* Grow buffer if less than 1K free */
  458. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  459. Xchar *
  460. Xchecksize(cb)
  461. Xstruct Ebuf *cb;
  462. X{
  463. X    if (cb->nalloc - cb->l  <  1024)
  464. X    return grow(cb);
  465. X    else
  466. X    return cb->buf;
  467. X}
  468. X
  469. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  470. X/* Check if string s1 ends with string s2 */
  471. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  472. Xchar *ends(s1, s2)
  473. Xchar *s1, *s2;
  474. X/* If s1 ends with string s2, a pointer to the ending of s1 is returned;
  475. X * else null
  476. X */
  477. X{
  478. X    int l1, l2;
  479. X    l1 = strlen(s1);
  480. X    l2 = strlen(s2);
  481. X    if (l1 < l2)
  482. X    return NULL;
  483. X    else if (strcmp(s1+l1-l2, s2) == 0)
  484. X    return s1+l1-l2;
  485. X    else
  486. X    return NULL;
  487. X}
  488. X
  489. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  490. X/* Do fgets to get one logical line: join lines that are terminated
  491. X * with backslash-newline.  Don't discard backslash or newline (so that
  492. X * we can print the exact text, if desired).
  493. X * The result is stored in "ebuf" and a pointer to the string
  494. X * is returned.
  495. X */
  496. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  497. Xchar *
  498. Xfillbuffer(fp, nl)
  499. XFILE *fp;
  500. Xint *nl;    /* If non-null, number of lines read in is returned */
  501. X{
  502. X    char *s;
  503. X    ebuf.l = 0;        /* clear the extensible buffer */
  504. X
  505. X    /* Collect lines until we have a non-zero buffer (which happens with
  506. X     * the first line, of course) and it isn't terminated "\\\n".
  507. X     */
  508. X    if (nl) *nl = 0;
  509. X    UNTIL(ebuf.l && !(s=ends(ebuf.buf, "\\\n"))) {
  510. X    if (!checksize(&ebuf)) {
  511. X        /* Needed to, but couldn't increase the allocated space */
  512. X        return NULL;
  513. X    }
  514. X    if (!fgets(ebuf.buf+ebuf.l, ebuf.nalloc - ebuf.l, fp))
  515. X        return NULL;
  516. X    if (ebuf.l != 0 && !isspace(*(ebuf.buf+ebuf.l))) {
  517. X        (void) fprintf(stderr,
  518. X        "%s: SUPER.TAB FORMAT ERROR -- Continued line not indented\n",
  519. X        prog);
  520. X        (void) fprintf(stderr,
  521. X        "\tProblem text:\n%s\n",
  522. X        ebuf.buf);
  523. X        (void) exit(1);
  524. X    }
  525. X    ebuf.l += strlen(ebuf.buf+ebuf.l);
  526. X    if (nl) (*nl)++;
  527. X    }
  528. X    return ebuf.buf;
  529. X}
  530. X
  531. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  532. X/* Look up command "usrcmd" in file "superfile".  Return path to execute
  533. X * if approved, empty string if no action should be taken, NULL ptr
  534. X * if error.
  535. X */
  536. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  537. Xchar *
  538. Xapprove(superfile, usrcmd)
  539. Xchar *superfile;    /* file of approved commands+users */
  540. Xchar *usrcmd;        /* command we're to check on.
  541. X             * If command is one of:
  542. X             *    "" | "-h" | "-?"
  543. X             *    then a list of super commands is printed
  544. X             *    instead of attempting to execute anything.
  545. X             */
  546. X{
  547. X    int uid;
  548. X    struct passwd *usrpw;
  549. X    /* has to be static: holds the returned path used by the caller. */
  550. X    char *userlist, *command, *path, *tok;
  551. X    char *wd, **wdlist;
  552. X    int globbraces();
  553. X    char *word(), *re_comp(), *check_ugh();
  554. X    char *buf, *s;
  555. X    char *sep;
  556. X    int i, iwd, nl, line, givehelp, commandfound;
  557. X    int gid;
  558. X    int gethostname();
  559. X    char hostname[1024];
  560. X    void anchor();
  561. X
  562. X    uid = getuid();
  563. X    usrpw = getpwuid(uid);
  564. X    if (!usrpw) {
  565. X    (void) fprintf(stderr,
  566. X        "%s - approve(): Couldn't get your password entry: ", prog);
  567. X    perror("");
  568. X    return NULL;
  569. X    }
  570. X    user = usrpw->pw_name;
  571. X    gid = usrpw->pw_gid;
  572. X
  573. X    if (gethostname(hostname, sizeof(hostname)) == -1) {
  574. X    (void) fprintf(stderr, "%s: Couldn't get your hostname: ",
  575. X                prog);
  576. X    perror("");
  577. X    return NULL;
  578. X    }
  579. X
  580. X    if ((fp = fopen(superfile, "r")) == NULL) {
  581. X    (void) fprintf(stderr, "%s: Couldn't open valid-users text file `%s': ",
  582. X                prog, superfile);
  583. X    perror("");
  584. X    return NULL;
  585. X    }
  586. X
  587. X    sep = " \t\v\n";        /* How to split fields on input lines */
  588. X
  589. X    /* Do we just give help or really match a command with this user? */
  590. X    givehelp = (usrcmd == NULL) ||
  591. X            strcmp(usrcmd, "-h")==0 || strcmp(usrcmd, "-?")==0;
  592. X
  593. X    if (givehelp) {
  594. X    (void) fprintf(stderr, "%s version %s patchlevel %s\n",
  595. X                prog, Version, Patchlevel);
  596. X    (void) fprintf(stderr, "Use:\n\t%s command [args]\n\n", prog);
  597. X    (void) fprintf(stderr, "%-16s  %-24s  %s\n",
  598. X        "Command", "Full Path           ",
  599. X                    "Valid User:Group@Host Patterns");
  600. X    (void) fprintf(stderr, "%-16s  %-24s  %s\n",
  601. X        "-------", "--------------------",
  602. X                    "------------------------------");
  603. X    }
  604. X
  605. X    commandfound = 0;
  606. X    for (line=1; buf=fillbuffer(fp, &nl); line += nl) {
  607. X    if (!*buf || *buf == '#' )        /* Strip comments */
  608. X        continue;
  609. X    buf = strtok(buf, "#");            /* Strip more comments */
  610. X    if (re_comp("^[ \t\v\n]*$") != NULL) {    /* Skip whitespace */
  611. X        paterror("bad whitespace pattern!", buf, line, nl, superfile);
  612. X        return NULL;
  613. X    }
  614. X    if (re_exec(buf) == 1)
  615. X        continue;
  616. X
  617. X    if (isspace(*(ebuf.buf))) {
  618. X        (void) fprintf(stderr,
  619. X    "%s: SUPER.TAB FORMAT ERROR -- Commandnames must begin in column 1\n",
  620. X        prog);
  621. X        (void) fprintf(stderr, "\tline %d, file %s\n", line, superfile);
  622. X        (void) exit(1);
  623. X    }
  624. X                        
  625. X    userlist = word(buf, " \t\v\n", 3);    /* Find the okusernames before
  626. X                         * carving up the line.
  627. X                         */
  628. X    command = strtok(buf, sep);        /* get the command... */
  629. X    path = strtok(NULL, sep);        /* ...and its full path */
  630. X    if (!command || !path)
  631. X        continue;                /* Skip improper lines */
  632. X
  633. X    if (givehelp) {
  634. X        (void) fprintf(stderr,
  635. X        "%-16s  %-24s  %s",
  636. X        command, path, userlist);
  637. X        continue;
  638. X    }
  639. X
  640. X    if (strcmp(command, usrcmd) != 0)
  641. X        continue;                /* Skip non-matching commands */
  642. X
  643. X    commandfound++;
  644. X
  645. X    /* Check our user against all valid user patterns */
  646. X    if (uid == 0)
  647. X        return path;            /* root is always legit */
  648. X
  649. X    for (wd = strtok(NULL, sep); wd; wd = strtok(NULL, sep)) {
  650. X        if ((i=globbraces(wd, &wdlist)) != 0) {
  651. X        char errmsg[20];
  652. X        sprintf(errmsg, "Missing `%c'", i);
  653. X        paterror(errmsg, buf, line, nl, superfile);
  654. X        } else {
  655. X        for (iwd=0; tok=wdlist[iwd]; iwd++) {
  656. X            s = check_ugh(superfile, wd, tok, line, nl,
  657. X                user, gid, hostname);
  658. X#ifdef DEBUG
  659. X            if (s == NULL) {
  660. X            (void) fprintf(stderr,
  661. X                "MATCH:\n\tpath = %s\n\tpat=%s\n", path, wd);
  662. X                return "";
  663. X            } else {
  664. X            (void) fprintf(stderr,
  665. X                "user=%s gid=%d hostname=%s; pat=%s; reason: %s\n",
  666. X                user, gid,hostname,tok, s);
  667. X            }
  668. X#else
  669. X            if (s == NULL)
  670. X            return path;
  671. X#endif
  672. X        }
  673. X        }
  674. X    }
  675. X    }
  676. X    if (givehelp)
  677. X    return "";
  678. X    else if (!commandfound)
  679. X    (void) fprintf(stderr, "%s: No such super command as `%s'.\n",
  680. X        prog, usrcmd);
  681. X    else
  682. X    (void) fprintf(stderr, "%s %s: Permission denied to user %s\n",
  683. X        prog, usrcmd, user);
  684. X    return NULL;
  685. X}
  686. X
  687. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  688. X/* Check a single user/group/host string */
  689. X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  690. Xchar *
  691. Xcheck_ugh(superfile, origtext, token, line, nl, user, gid, hostname)
  692. Xchar *superfile;    /* used just for reporting errors about this file */
  693. Xchar *origtext;        /* original text containing token -- for err messages */
  694. Xchar *token;        /* user/group/host to check */
  695. Xint line;        /* line number in superfile, for reporting errors */
  696. Xint nl;            /* number of lines (ie lines n..n+nl-1 are the present
  697. X             *     block)
  698. X             */
  699. Xchar *user;        /* username to check */
  700. Xint gid;        /* gid for user */
  701. Xchar *hostname;        /* host to check */
  702. X{
  703. X    char tok[1024];
  704. X    char chkbuf[1024];
  705. X    int re_exec(), ingroup();
  706. X    char *userpat, *grouppat, *hostpat;
  707. X    int i;
  708. X
  709. X    /* Strip trailing backslash that may have preceded a newline -- it was
  710. X     * until now so that we can print, if necessary, the identical text
  711. X     * to that in the super.tab file.
  712. X     */
  713. X    (void) strcpy(tok, token);
  714. X    if ((i = strlen(tok)) && tok[i-1] == '\\') tok[i-1] = '\0';
  715. X
  716. X    /* Split into user:group@host */
  717. X    hostpat = strchr(tok, '@');
  718. X    if (hostpat && !*(hostpat+1))
  719. X    return paterror("Missing hostname", origtext, line, nl, superfile);
  720. X    else if (hostpat)
  721. X    *hostpat++ = '\0';
  722. X
  723. X#ifdef USE_NETGROUP
  724. X    if (hostpat && *hostpat == '+') {    /* Interpret as +netgroupname */
  725. X    if (*(hostpat+1) == '\0')
  726. X        return paterror("Missing netgroupname",
  727. X                    origtext, line, nl, superfile);
  728. X    if (!innetgr(hostpat+1, hostname, (char *) NULL, (char *) NULL))
  729. X        return "Not in netgroup";    /* Not in this netgroup */
  730. X    }
  731. X#else
  732. X    (void) fprintf(stderr,
  733. X    "%s: hostnames may not begin with `+' since this super()\n", prog);
  734. X    (void) fputs("was compiled without ``#define USE_NETGROUP''\n", stderr);
  735. X    return 0;
  736. X#endif
  737. X
  738. X    if (hostpat && *hostpat != '+') {    /* Interpret as a hostname pattern */
  739. X    anchor(hostpat, chkbuf);    /* Force all matches to be anchored */
  740. X    if (re_comp(chkbuf) != NULL)
  741. X        return paterror("bad host pattern", origtext, line, nl, superfile);
  742. X    if (re_exec(hostname) != 1)
  743. X        return "Doesn't match hostname";    /* Didn't match hostname */
  744. X    }
  745. X
  746. X    grouppat = strchr(tok, ':');
  747. X    userpat = tok;
  748. X    if (grouppat && *(grouppat+1)) {    /* pat is "uuu:ggg or ":ggg" */
  749. X    if (tok == grouppat)
  750. X        userpat = "^.*$";        /* pat is ":ggg" */
  751. X    grouppat++;
  752. X    } else {                /* pat is "uuu" or "uuu:" */
  753. X    if (grouppat)
  754. X        *grouppat = '\0';        /* pat was "uuu:" */
  755. X    grouppat = "^.*$";
  756. X    }
  757. X    anchor(userpat, chkbuf);        /* Force all matches to be anchored */
  758. X    if (re_comp(chkbuf) != NULL)
  759. X    return paterror("bad user pattern", origtext, line, nl, superfile);
  760. X    if (re_exec(user) != 1)
  761. X    return "Doesn't match user";    /* Didn't match user */
  762. X
  763. X    anchor(grouppat, chkbuf);
  764. X    i = ingroup(user, gid, chkbuf);
  765. X    if (i == -1)
  766. X    return paterror("bad group pattern", origtext, line, nl, superfile);
  767. X    else if (i != 1)
  768. X    return "Doesn't match group";
  769. X    
  770. X    return NULL;            /* Success! */
  771. X}
  772. END_OF_FILE
  773. if test 12888 -ne `wc -c <'approve.c'`; then
  774.     echo shar: \"'approve.c'\" unpacked with wrong size!
  775. fi
  776. # end of 'approve.c'
  777. fi
  778. if test -f 'braces.c' -a "${1}" != "-c" ; then 
  779.   echo shar: Will not clobber existing file \"'braces.c'\"
  780. else
  781. echo shar: Extracting \"'braces.c'\" \(6387 characters\)
  782. sed "s/^X//" >'braces.c' <<'END_OF_FILE'
  783. X/*
  784. X * brace.c: csh brace expansion -- includes pieces of
  785. X * [t]csh's sh.misc.c and sh.glob.c.
  786. X *
  787. X * Modified for use as a standalone brace-globbing subroutine.
  788. X *    - Will Deich, Mar 93.
  789. X */
  790. X
  791. X#include "version.h"
  792. Xstatic char SccsId[] = "@(#)braces.c    1.3\t4/13/93" ;
  793. X
  794. X/*-
  795. X * Copyright (c) 1980, 1991 The Regents of the University of California.
  796. X * All rights reserved.
  797. X *
  798. X * Redistribution and use in source and binary forms, with or without
  799. X * modification, are permitted provided that the following conditions
  800. X * are met:
  801. X * 1. Redistributions of source code must retain the above copyright
  802. X *    notice, this list of conditions and the following disclaimer.
  803. X * 2. Redistributions in binary form must reproduce the above copyright
  804. X *    notice, this list of conditions and the following disclaimer in the
  805. X *    documentation and/or other materials provided with the distribution.
  806. X * 3. All advertising materials mentioning features or use of this software
  807. X *    must display the following acknowledgement:
  808. X *    This product includes software developed by the University of
  809. X *    California, Berkeley and its contributors.
  810. X * 4. Neither the name of the University nor the names of its contributors
  811. X *    may be used to endorse or promote products derived from this software
  812. X *    without specific prior written permission.
  813. X *
  814. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  815. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  816. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  817. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  818. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  819. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  820. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  821. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  822. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  823. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  824. X * SUCH DAMAGE.
  825. X */
  826. X
  827. X#define _POSIX_SOURCE
  828. X
  829. X#include <sys/param.h>
  830. X#include <string.h>
  831. X
  832. Xtypedef void * ptr_t;
  833. X
  834. X#ifndef NULL
  835. X#define NULL 0
  836. X#endif
  837. X
  838. X#ifndef MAXPATHLEN
  839. X#define MAXPATHLEN 1024
  840. X#endif
  841. X
  842. Xextern void *malloc();
  843. Xextern void *realloc();
  844. Xextern void free();
  845. X
  846. X#define xmalloc        malloc
  847. X#define xrealloc    realloc
  848. X#define xfree        free
  849. X
  850. X#define    GLOBSPACE    100    /* Alloc increment */
  851. X
  852. X#define LBRC '{'
  853. X#define RBRC '}'
  854. X#define LBRK '['
  855. X#define RBRK ']'
  856. X#define EOS '\0'
  857. X
  858. Xstatic char *strsave();
  859. Xstatic void blkfree();
  860. Xstatic int blklen();
  861. X
  862. Xint
  863. Xglobbraces(v, blp)
  864. Xchar *v;
  865. Xchar ***blp;
  866. X{
  867. X    char   *s;
  868. X    char  **nv, **vl, **el;
  869. X    int     size = GLOBSPACE;
  870. X    int     glob1brace();
  871. X
  872. X
  873. X    nv = vl = (char **) xmalloc((size_t) sizeof(char *) * size);
  874. X    *vl++ = strsave(v);
  875. X    *vl = NULL;
  876. X
  877. X    el = vl;
  878. X    vl = nv;
  879. X    for (s = *vl; s; s = *++vl) {
  880. X    char   *b;
  881. X    char  **vp, **bp;
  882. X
  883. X    if ((b = strchr(s, LBRC)) && b[1] != '\0' && b[1] != RBRC) {
  884. X        char **bl;
  885. X        int len;
  886. X
  887. X        if ((len = glob1brace(s, &bl)) < 0) {
  888. X        blkfree(nv);
  889. X        return -len;
  890. X        }
  891. X        xfree((ptr_t) s);
  892. X        if (len == 1) {
  893. X        *vl-- = *bl;
  894. X        xfree((ptr_t) bl);
  895. X        continue;
  896. X        }
  897. X        len = blklen(bl);
  898. X        if (&el[len] >= &nv[size]) {
  899. X        int     l, e;
  900. X
  901. X        l = &el[len] - &nv[size];
  902. X        size += GLOBSPACE > l ? GLOBSPACE : l;
  903. X        l = vl - nv;
  904. X        e = el - nv;
  905. X        nv = (char **) xrealloc((ptr_t) nv, (size_t)
  906. X                    size * sizeof(char *));
  907. X        vl = nv + l;
  908. X        el = nv + e;
  909. X        }
  910. X        vp = vl--;
  911. X        *vp = *bl;
  912. X        len--;
  913. X        for (bp = el; bp != vp; bp--)
  914. X        bp[len] = *bp;
  915. X        el += len;
  916. X        vp++;
  917. X        for (bp = bl + 1; *bp; *vp++ = *bp++)
  918. X        continue;
  919. X        xfree((ptr_t) bl);
  920. X    }
  921. X    }
  922. X    *blp = nv;
  923. X    return 0;
  924. X}
  925. X
  926. Xint
  927. Xglob1brace(s, bl)
  928. X    char   *s, ***bl;
  929. X{
  930. X    char *p;
  931. X    int     i, len;
  932. X    char   *pm, *pe, *lm, *pl;
  933. X    char  **nv, **vl;
  934. X    char    gbuf[MAXPATHLEN];
  935. X    int     size = GLOBSPACE;
  936. X
  937. X    nv = vl = (char **) xmalloc((size_t) sizeof(char *) * size);
  938. X    *vl = NULL;
  939. X
  940. X    len = 0;
  941. X    /* copy part up to the brace */
  942. X    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
  943. X    continue;
  944. X
  945. X    /* check for balanced braces */
  946. X    for (i = 0, pe = ++p; *pe; pe++)
  947. X    if (*pe == LBRK) {
  948. X        /* Ignore everything between [] */
  949. X        for (++pe; *pe != RBRK && *pe != EOS; pe++)
  950. X        continue;
  951. X        if (*pe == EOS) {
  952. X        blkfree(nv);
  953. X        return (-RBRK);
  954. X        }
  955. X    }
  956. X    else if (*pe == LBRC)
  957. X        i++;
  958. X    else if (*pe == RBRC) {
  959. X        if (i == 0)
  960. X        break;
  961. X        i--;
  962. X    }
  963. X
  964. X    if (i != 0 || *pe == '\0') {
  965. X    blkfree(nv);
  966. X    return (-RBRC);
  967. X    }
  968. X
  969. X    for (i = 0, pl = pm = p; pm <= pe; pm++)
  970. X    switch (*pm) {
  971. X    case LBRK:
  972. X        for (++pm; *pm != RBRK && *pm != EOS; pm++)
  973. X        continue;
  974. X        if (*pm == EOS) {
  975. X        *vl = NULL;
  976. X        blkfree(nv);
  977. X        return (-RBRK);
  978. X        }
  979. X        break;
  980. X    case LBRC:
  981. X        i++;
  982. X        break;
  983. X    case RBRC:
  984. X        if (i) {
  985. X        i--;
  986. X        break;
  987. X        }
  988. X        /* FALLTHROUGH */
  989. X    case ',':
  990. X        if (i && *pm == ',')
  991. X        break;
  992. X        else {
  993. X        char    savec = *pm;
  994. X
  995. X        *pm = EOS;
  996. X        (void) strcpy(lm, pl);
  997. X        (void) strcat(gbuf, pe + 1);
  998. X        *pm = savec;
  999. X        *vl++ = strsave(gbuf);
  1000. X        len++;
  1001. X        pl = pm + 1;
  1002. X        if (vl == &nv[size]) {
  1003. X            size += GLOBSPACE;
  1004. X            nv = (char **) xrealloc((ptr_t) nv, (size_t)
  1005. X                        size * sizeof(char *));
  1006. X            vl = &nv[size - GLOBSPACE];
  1007. X        }
  1008. X        }
  1009. X        break;
  1010. X    default:
  1011. X        break;
  1012. X    }
  1013. X    *vl = NULL;
  1014. X    *bl = nv;
  1015. X    return (len);
  1016. X}
  1017. X
  1018. Xstatic char *
  1019. Xstrsave(s)
  1020. X    register char *s;
  1021. X{
  1022. X    char   *n;
  1023. X    register char *p;
  1024. X
  1025. X    if (s == NULL)
  1026. X    s = (char *) "";
  1027. X    for (p = (char *) s; *p++;);
  1028. X    n = p = (char *) xmalloc((size_t) ((p - s) * sizeof(char)));
  1029. X    while (*p++ = *s++);
  1030. X    return (n);
  1031. X}
  1032. X
  1033. Xstatic void
  1034. Xblkfree(av0)
  1035. X    char **av0;
  1036. X{
  1037. X    register char **av = av0;
  1038. X
  1039. X    if (!av0)
  1040. X    return;
  1041. X    for (; *av; av++)
  1042. X    xfree((ptr_t) * av);
  1043. X    xfree((ptr_t) av0);
  1044. X}
  1045. X
  1046. Xstatic int
  1047. Xblklen(av)
  1048. X    char **av;
  1049. X{
  1050. X    register int i = 0;
  1051. X
  1052. X    while (*av++)
  1053. X    i++;
  1054. X    return i;
  1055. X}
  1056. X
  1057. X#ifdef TEST
  1058. X#include <stdio.h>
  1059. X
  1060. Xmain(argc, argv)
  1061. X    int argc;
  1062. X    char **argv;
  1063. X{
  1064. X    int i, status;
  1065. X    char **p;
  1066. X
  1067. X    while (*(++argv)) {
  1068. X    status = globbraces(*argv, &p);
  1069. X    if (status == 0 - '}')
  1070. X        printf("} error\n");
  1071. X    else if (status == 0 - ']')
  1072. X        printf("] error\n");
  1073. X    else if (status < 0)
  1074. X        printf("globbraces returns %d\n", status);
  1075. X    else {
  1076. X        printf("%s expands to:\n", *argv);
  1077. X        while (*p)
  1078. X        printf("\t`%s'\t\n", *p++);
  1079. X    }
  1080. X    }
  1081. X}
  1082. X#endif
  1083. END_OF_FILE
  1084. if test 6387 -ne `wc -c <'braces.c'`; then
  1085.     echo shar: \"'braces.c'\" unpacked with wrong size!
  1086. fi
  1087. # end of 'braces.c'
  1088. fi
  1089. if test -f 'getlogdir.c' -a "${1}" != "-c" ; then 
  1090.   echo shar: Will not clobber existing file \"'getlogdir.c'\"
  1091. else
  1092. echo shar: Extracting \"'getlogdir.c'\" \(934 characters\)
  1093. sed "s/^X//" >'getlogdir.c' <<'END_OF_FILE'
  1094. X#include <string.h>
  1095. X#include <pwd.h>
  1096. X
  1097. Xstatic char SccsId[] = "@(#)getlogdir.c    1.3\t4/13/93";
  1098. X
  1099. X#ifndef NULL
  1100. X#define NULL (char *) 0
  1101. X#endif
  1102. X
  1103. Xint getlogdir(user, buf)
  1104. Xchar *user;
  1105. Xchar *buf;
  1106. X{
  1107. X    /* Gets the login directory of the named user, and puts it into buf.
  1108. X     * If user==NULL || *user == '\0', the current user is obtained.
  1109. X     * Best if buf is MAXPATHLEN long.
  1110. X     * 0 is returned on success; -1 on error.
  1111. X     */
  1112. X
  1113. X    struct passwd *pass;
  1114. X    char *p;
  1115. X    char *getlogin();
  1116. X
  1117. X    buf[0] = '\0';
  1118. X    if (user != NULL && *user != '\0') {
  1119. X    /* Name given; use getpwnam */
  1120. X    pass = getpwnam(user);
  1121. X    } else if ((p = getlogin()) != NULL) {
  1122. X    /* No name given; use current login name */
  1123. X    pass = getpwnam(p);
  1124. X    } else {
  1125. X    /* No user given && getlogin() returned NULL; use current uid */
  1126. X    pass = getpwuid(getuid());
  1127. X    }
  1128. X
  1129. X
  1130. X    if (pass == (struct passwd *) NULL)
  1131. X    return -1;
  1132. X
  1133. X    (void) strcpy(buf, pass->pw_dir);
  1134. X
  1135. X    return 0;
  1136. X}
  1137. END_OF_FILE
  1138. if test 934 -ne `wc -c <'getlogdir.c'`; then
  1139.     echo shar: \"'getlogdir.c'\" unpacked with wrong size!
  1140. fi
  1141. # end of 'getlogdir.c'
  1142. fi
  1143. if test -f 'ingroup.c' -a "${1}" != "-c" ; then 
  1144.   echo shar: Will not clobber existing file \"'ingroup.c'\"
  1145. else
  1146. echo shar: Extracting \"'ingroup.c'\" \(1448 characters\)
  1147. sed "s/^X//" >'ingroup.c' <<'END_OF_FILE'
  1148. X#include <grp.h>
  1149. X
  1150. Xstatic char SccsId[] = "@(#)ingroup.c    1.5\t7/6/93";
  1151. X
  1152. X/* Use:
  1153. X *    ingroup(user, gid, gp_pat)
  1154. X * Returns:
  1155. X *    1 if the user is in a group matching the regex pattern gp_pat.
  1156. X *    0 if the user isn't in a group matching the pattern.
  1157. X *    -1 if pattern failed to compile.
  1158. X
  1159. X * SIDE-EFFECT: uses re_comp! -- messes up caller's use of same!
  1160. X
  1161. X * Uses re_{comp,exec} routines to compare.
  1162. X
  1163. X * Examples:
  1164. X *    ingroup("joe", joes_gid, "xyz")
  1165. X * returns !0 if user joe is in group "xyz".
  1166. X *    ingroup("joe", joes_gid, "xy.*")
  1167. X * returns !0 if user joe is in any group matching "xy.*".
  1168. X
  1169. X */
  1170. X
  1171. Xingroup(user, gid, gp_pat)
  1172. Xchar *user;
  1173. Xint gid;
  1174. Xchar *gp_pat;    /* pattern to match */
  1175. X{
  1176. X    char *re_comp();
  1177. X    int re_exec();
  1178. X    struct group *gp;
  1179. X    char **mem;
  1180. X    void setgrent();
  1181. X
  1182. X    if (re_comp(gp_pat) != (char *)0 )
  1183. X    return -1;
  1184. X
  1185. X    /* Search group file for groups user's in.
  1186. X     * Test for group matches wherever user belongs.
  1187. X     */
  1188. X    setgrent();
  1189. X    for (gp = getgrent(); gp; gp = getgrent()) {
  1190. X    /* gr_mem only shows names added in the /etc/groups file, not
  1191. X     * the group assigned in passwd.  Check that group (gp->gr_gid)
  1192. X     * explicitly, then check gp->gr_mem list.
  1193. X     */
  1194. X    if (gid != gp->gr_gid) {
  1195. X        for (mem = gp->gr_mem; *mem ; mem++)
  1196. X        if (strcmp(*mem, user) == 0)
  1197. X            break;
  1198. X        if (!*mem)
  1199. X        continue;            /* not in group */
  1200. X    }
  1201. X    if (re_exec(gp->gr_name) == 1)    /* in group; compare gp name with pat */
  1202. X        return 1;
  1203. X    }
  1204. X    return 0;
  1205. X}
  1206. END_OF_FILE
  1207. if test 1448 -ne `wc -c <'ingroup.c'`; then
  1208.     echo shar: \"'ingroup.c'\" unpacked with wrong size!
  1209. fi
  1210. # end of 'ingroup.c'
  1211. fi
  1212. if test -f 're_fail.c' -a "${1}" != "-c" ; then 
  1213.   echo shar: Will not clobber existing file \"'re_fail.c'\"
  1214. else
  1215. echo shar: Extracting \"'re_fail.c'\" \(354 characters\)
  1216. sed "s/^X//" >'re_fail.c' <<'END_OF_FILE'
  1217. X
  1218. X#ifdef vms
  1219. X#include stdio
  1220. X#else
  1221. X#include <stdio.h>
  1222. X#endif
  1223. X
  1224. Xstatic char SccsId[] = "@(#)re_fail.c    1.3\t4/13/93" ;
  1225. X
  1226. X/* 
  1227. X * re_fail:
  1228. X *    internal error handler for re_exec.
  1229. X *
  1230. X *    should probably do something like a
  1231. X *    longjump to recover gracefully.
  1232. X */ 
  1233. Xvoid    
  1234. Xre_fail(s, c)
  1235. Xchar *s;
  1236. Xchar c;
  1237. X{
  1238. X    (void) fprintf(stderr, "%s [opcode %o]\n", s, c);
  1239. X    exit(1);
  1240. X}
  1241. END_OF_FILE
  1242. if test 354 -ne `wc -c <'re_fail.c'`; then
  1243.     echo shar: \"'re_fail.c'\" unpacked with wrong size!
  1244. fi
  1245. # end of 're_fail.c'
  1246. fi
  1247. if test -f 'regex.c' -a "${1}" != "-c" ; then 
  1248.   echo shar: Will not clobber existing file \"'regex.c'\"
  1249. else
  1250. echo shar: Extracting \"'regex.c'\" \(18831 characters\)
  1251. sed "s/^X//" >'regex.c' <<'END_OF_FILE'
  1252. X/*
  1253. X * regex - Regular expression pattern matching
  1254. X *         and replacement
  1255. X *
  1256. X *
  1257. X * By:  Ozan S. Yigit (oz)
  1258. X *      Dept. of Computer Science
  1259. X *      York University
  1260. X *
  1261. X *
  1262. X * These routines are the PUBLIC DOMAIN equivalents 
  1263. X * of regex routines as found in 4.nBSD UN*X, with minor
  1264. X * extensions.
  1265. X *
  1266. X * These routines are derived from various implementations
  1267. X * found in software tools books, and Conroy's grep. They
  1268. X * are NOT derived from licensed/restricted software.
  1269. X * For more interesting/academic/complicated implementations,
  1270. X * see Henry Spencer's regexp routines, or GNU Emacs pattern
  1271. X * matching module.
  1272. X *
  1273. X * Routines:
  1274. X *      re_comp:        compile a regular expression into
  1275. X *                      a DFA.
  1276. X *
  1277. X *            char *re_comp(s)
  1278. X *            char *s;
  1279. X *
  1280. X *      re_exec:        execute the DFA to match a pattern.
  1281. X *
  1282. X *            int re_exec(s)
  1283. X *            char *s;
  1284. X *
  1285. X *    re_modw        change re_exec's understanding of what
  1286. X *            a "word" looks like (for \< and \>)
  1287. X *            by adding into the hidden word-character 
  1288. X *            table.
  1289. X *
  1290. X *            void re_modw(s)
  1291. X *            char *s;
  1292. X *
  1293. X *      re_subs:    substitute the matched portions in
  1294. X *                  a new string.
  1295. X *
  1296. X *            int re_subs(src, dst)
  1297. X *            char *src;
  1298. X *            char *dst;
  1299. X *
  1300. X *    re_fail:    failure routine for re_exec.
  1301. X *
  1302. X *            void re_fail(msg, op)
  1303. X *            char *msg;
  1304. X *            char op;
  1305. X *  
  1306. X * Regular Expressions:
  1307. X *
  1308. X *      [1]     char    matches itself, unless it is a special
  1309. X *                      character (metachar): . \ [ ] * + ^ $
  1310. X *
  1311. X *      [2]     .       matches any character.
  1312. X *
  1313. X *      [3]     \       matches the character following it, except
  1314. X *            when followed by a left or right round bracket,
  1315. X *            a digit 1 to 9 or a left or right angle bracket. 
  1316. X *            (see [7], [8] and [9])
  1317. X *            It is used as an escape character for all 
  1318. X *            other meta-characters, and itself. When used
  1319. X *            in a set ([4]), it is treated as an ordinary
  1320. X *            character.
  1321. X *
  1322. X *      [4]     [set]   matches one of the characters in the set.
  1323. X *                      If the first character in the set is "^",
  1324. X *                      it matches a character NOT in the set. A
  1325. X *                      shorthand S-E is used to specify a set of
  1326. X *                      characters S upto E, inclusive. The special
  1327. X *                      characters "]" and "-" have no special
  1328. X *                      meaning if they appear as the first chars
  1329. X *                      in the set.
  1330. X *                      examples:        match:
  1331. X *
  1332. X *                              [a-z]    any lowercase alpha
  1333. X *
  1334. X *                              [^]-]    any char except ] and -
  1335. X *
  1336. X *                              [^A-Z]   any char except uppercase
  1337. X *                                       alpha
  1338. X *
  1339. X *                              [a-zA-Z] any alpha
  1340. X *
  1341. X *      [5]     *       any regular expression form [1] to [4], followed by
  1342. X *                      closure char (*) matches zero or more matches of
  1343. X *                      that form.
  1344. X *
  1345. X *      [6]     +       same as [5], except it matches one or more.
  1346. X *
  1347. X *      [7]             a regular expression in the form [1] to [10], enclosed
  1348. X *                      as \(form\) matches what form matches. The enclosure
  1349. X *                      creates a set of tags, used for [8] and for
  1350. X *                      pattern substution. The tagged forms are numbered
  1351. X *            starting from 1.
  1352. X *
  1353. X *      [8]             a \ followed by a digit 1 to 9 matches whatever a
  1354. X *                      previously tagged regular expression ([7]) matched.
  1355. X *
  1356. X *    [9]    \<    a regular expression starting with a \< construct
  1357. X *        \>    and/or ending with a \> construct, restricts the
  1358. X *            pattern matching to the beginning of a word, and/or
  1359. X *            the end of a word. A word is defined to be a character
  1360. X *            string beginning and/or ending with the characters
  1361. X *            A-Z a-z 0-9 and _. It must also be preceded and/or
  1362. X *            followed by any character outside those mentioned.
  1363. X *
  1364. X *      [10]            a composite regular expression xy where x and y
  1365. X *                      are in the form [1] to [10] matches the longest
  1366. X *                      match of x followed by a match for y.
  1367. X *
  1368. X *      [11]    ^    a regular expression starting with a ^ character
  1369. X *        $    and/or ending with a $ character, restricts the
  1370. X *                      pattern matching to the beginning of the line,
  1371. X *                      or the end of line. [anchors] Elsewhere in the
  1372. X *            pattern, ^ and $ are treated as ordinary characters.
  1373. X *
  1374. X *
  1375. X * Acknowledgements:
  1376. X *
  1377. X *    HCR's Hugh Redelmeier has been most helpful in various
  1378. X *    stages of development. He convinced me to include BOW
  1379. X *    and EOW constructs, originally invented by Rob Pike at
  1380. X *    the University of Toronto.
  1381. X *
  1382. X * References:
  1383. X *              Software tools            Kernighan & Plauger
  1384. X *              Software tools in Pascal        Kernighan & Plauger
  1385. X *              Grep [rsx-11 C dist]            David Conroy
  1386. X *        ed - text editor        Un*x Programmer's Manual
  1387. X *        Advanced editing on Un*x    B. W. Kernighan
  1388. X *        RegExp routines            Henry Spencer
  1389. X *
  1390. X * Notes:
  1391. X *
  1392. X *    This implementation uses a bit-set representation for character
  1393. X *    classes for speed and compactness. Each character is represented 
  1394. X *    by one bit in a 128-bit block. Thus, CCL or NCL always takes a 
  1395. X *    constant 16 bytes in the internal dfa, and re_exec does a single
  1396. X *    bit comparison to locate the character in the set.
  1397. X *
  1398. X * Examples:
  1399. X *
  1400. X *    pattern:    foo*.*
  1401. X *    compile:    CHR f CHR o CLO CHR o END CLO ANY END END
  1402. X *    matches:    fo foo fooo foobar fobar foxx ...
  1403. X *
  1404. X *    pattern:    fo[ob]a[rz]    
  1405. X *    compile:    CHR f CHR o CCL 2 o b CHR a CCL bitset END
  1406. X *    matches:    fobar fooar fobaz fooaz
  1407. X *
  1408. X *    pattern:    foo\\+
  1409. X *    compile:    CHR f CHR o CHR o CHR \ CLO CHR \ END END
  1410. X *    matches:    foo\ foo\\ foo\\\  ...
  1411. X *
  1412. X *    pattern:    \(foo\)[1-3]\1    (same as foo[1-3]foo)
  1413. X *    compile:    BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
  1414. X *    matches:    foo1foo foo2foo foo3foo
  1415. X *
  1416. X *    pattern:    \(fo.*\)-\1
  1417. X *    compile:    BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
  1418. X *    matches:    foo-foo fo-fo fob-fob foobar-foobar ...
  1419. X * 
  1420. X */
  1421. Xstatic char SccsId[] = "@(#)regex.c    1.3\t4/13/93" ;
  1422. X
  1423. X#define MAXDFA  1024
  1424. X#define MAXTAG  10
  1425. X
  1426. X#define OKP     1
  1427. X#define NOP     0
  1428. X
  1429. X#define CHR     1
  1430. X#define ANY     2
  1431. X#define CCL     3
  1432. X#define NCL     4
  1433. X#define BOL     5
  1434. X#define EOL     6
  1435. X#define BOT     7
  1436. X#define EOT     8
  1437. X#define BOW    9
  1438. X#define EOW    10
  1439. X#define REF     11
  1440. X#define CLO     12
  1441. X
  1442. X#define END     0
  1443. X
  1444. X/*
  1445. X * The following defines are not meant
  1446. X * to be changeable. They are for readibility
  1447. X * only.
  1448. X *
  1449. X */
  1450. X#define MAXCHR    128
  1451. X#define CHRBIT    8
  1452. X#define BITBLK    MAXCHR/CHRBIT
  1453. X#define BLKIND    0170
  1454. X#define BITIND    07
  1455. X
  1456. X#define ASCIIB    0177
  1457. X
  1458. Xtypedef /*unsigned*/ char CHAR;
  1459. X
  1460. Xstatic int  tagstk[MAXTAG];             /* subpat tag stack..*/
  1461. Xstatic CHAR dfa[MAXDFA];        /* automaton..       */
  1462. Xstatic int  sta = NOP;                   /* status of lastpat */
  1463. X
  1464. Xstatic CHAR bittab[BITBLK];        /* bit table for CCL */
  1465. X
  1466. Xstatic void
  1467. Xchset(c) register CHAR c; { bittab[((c)&BLKIND)>>3] |= 1<<((c)&BITIND); }
  1468. X
  1469. X#define badpat(x)    return(*dfa = END, x)
  1470. X#define store(x)    *mp++ = x
  1471. Xchar *     
  1472. Xre_comp(pat)
  1473. Xchar *pat;
  1474. X{
  1475. X    register char *p;               /* pattern pointer   */
  1476. X    register CHAR *mp=dfa;          /* dfa pointer       */
  1477. X    register CHAR *lp;              /* saved pointer..   */
  1478. X    register CHAR *sp=dfa;          /* another one..     */
  1479. X
  1480. X    register int tagi = 0;          /* tag stack index   */
  1481. X    register int tagc = 1;          /* actual tag count  */
  1482. X
  1483. X    register int n;
  1484. X    int c1, c2;
  1485. X        
  1486. X    if (!pat || !*pat)
  1487. X        if (sta)
  1488. X            return(0);
  1489. X        else
  1490. X            badpat("No previous regular expression");
  1491. X    sta = NOP;
  1492. X
  1493. X    for (p = pat; *p; p++) {
  1494. X        lp = mp;
  1495. X        switch(*p) {
  1496. X
  1497. X        case '.':               /* match any char..  */
  1498. X            store(ANY);
  1499. X            break;
  1500. X
  1501. X        case '^':               /* match beginning.. */
  1502. X            if (p == pat)
  1503. X                store(BOL);
  1504. X            else {
  1505. X                store(CHR);
  1506. X                store(*p);
  1507. X            }
  1508. X            break;
  1509. X
  1510. X        case '$':               /* match endofline.. */
  1511. X            if (!*(p+1))
  1512. X                store(EOL);
  1513. X            else {
  1514. X                store(CHR);
  1515. X                store(*p);
  1516. X            }
  1517. X            break;
  1518. X
  1519. X        case '[':               /* match char class..*/
  1520. X
  1521. X            if (*++p == '^') {
  1522. X                store(NCL);
  1523. X                p++;
  1524. X            }
  1525. X            else
  1526. X                store(CCL);
  1527. X
  1528. X            if (*p == '-')        /* real dash */
  1529. X                chset(*p++);
  1530. X            if (*p == ']')        /* real brac */
  1531. X                chset(*p++);
  1532. X            while (*p && *p != ']') {
  1533. X                if (*p == '-' && *(p+1) && *(p+1) != ']') {
  1534. X                    p++;
  1535. X                    c1 = *(p-2) + 1;
  1536. X                    c2 = *p++;
  1537. X                    while (c1 <= c2)
  1538. X                        chset(c1++);
  1539. X                }
  1540. X#ifdef EXTEND
  1541. X                else if (*p == '\\' && *(p+1)) {
  1542. X                    p++;
  1543. X                    chset(*p++);
  1544. X                }
  1545. X#endif
  1546. X                else
  1547. X                    chset(*p++);
  1548. X            }
  1549. X            if (!*p)
  1550. X                badpat("Missing ]");
  1551. X
  1552. X            for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
  1553. X                store(bittab[n]);
  1554. X    
  1555. X            break;
  1556. X
  1557. X        case '*':               /* match 0 or more.. */
  1558. X        case '+':               /* match 1 or more.. */
  1559. X            if (p == pat)
  1560. X                badpat("Empty closure");
  1561. X            lp = sp;                /* previous opcode */
  1562. X            if (*lp == CLO)         /* equivalence..   */
  1563. X                break;
  1564. X            switch(*lp) {
  1565. X
  1566. X            case BOL:
  1567. X            case BOT:
  1568. X            case EOT:
  1569. X            case BOW:
  1570. X            case EOW:
  1571. X            case REF:
  1572. X                badpat("Illegal closure");
  1573. X            default:
  1574. X                break;
  1575. X            }
  1576. X
  1577. X            if (*p == '+')
  1578. X                for (sp = mp; lp < sp; lp++)
  1579. X                    store(*lp);
  1580. X
  1581. X            store(END);
  1582. X            store(END);
  1583. X            sp = mp;
  1584. X            while (--mp > lp)
  1585. X                *mp = mp[-1];
  1586. X            store(CLO);
  1587. X            mp = sp;
  1588. X            break;
  1589. X
  1590. X        case '\\':              /* tags, backrefs .. */
  1591. X            switch(*++p) {
  1592. X
  1593. X            case '(':
  1594. X                if (tagc < MAXTAG) {
  1595. X                    tagstk[++tagi] = tagc;
  1596. X                    store(BOT);
  1597. X                    store(tagc++);
  1598. X                }
  1599. X                else
  1600. X                    badpat("Too many \\(\\) pairs");
  1601. X                break;
  1602. X            case ')':
  1603. X                if (*sp == BOT)
  1604. X                    badpat("Null pattern inside \\(\\)");
  1605. X                if (tagi > 0) {
  1606. X                    store(EOT);
  1607. X                    store(tagstk[tagi--]);
  1608. X                }
  1609. X                else
  1610. X                    badpat("Unmatched \\)");
  1611. X                break;
  1612. X            case '<':
  1613. X                store(BOW);
  1614. X                break;
  1615. X            case '>':
  1616. X                if (*sp == BOW)
  1617. X                    badpat("Null pattern inside \\<\\>");
  1618. X                store(EOW);
  1619. X                break;
  1620. X            case '1':
  1621. X            case '2':
  1622. X            case '3':
  1623. X            case '4':
  1624. X            case '5':
  1625. X            case '6':
  1626. X            case '7':
  1627. X            case '8':
  1628. X            case '9':
  1629. X                n = *p-'0';
  1630. X                if (tagi > 0 && tagstk[tagi] == n)
  1631. X                    badpat("Cyclical reference");
  1632. X                if (tagc > n) {
  1633. X                    store(REF);
  1634. X                    store(n);
  1635. X                }
  1636. X                else
  1637. X                    badpat("Undetermined reference");
  1638. X                break;
  1639. X#ifdef EXTEND
  1640. X            case 'b':
  1641. X                store(CHR);
  1642. X                store('\b');
  1643. X                break;
  1644. X            case 'n':
  1645. X                store(CHR);
  1646. X                store('\n');
  1647. X                break;
  1648. X            case 'f':
  1649. X                store(CHR);
  1650. X                store('\f');
  1651. X                break;
  1652. X            case 'r':
  1653. X                store(CHR);
  1654. X                store('\r');
  1655. X                break;
  1656. X            case 't':
  1657. X                store(CHR);
  1658. X                store('\t');
  1659. X                break;
  1660. X#endif
  1661. X            default:
  1662. X                store(CHR);
  1663. X                store(*p);
  1664. X            }
  1665. X            break;
  1666. X
  1667. X        default :               /* an ordinary char  */
  1668. X            store(CHR);
  1669. X            store(*p);
  1670. X            break;
  1671. X        }
  1672. X        sp = lp;
  1673. X    }
  1674. X    if (tagi > 0)
  1675. X        badpat("Unmatched \\(");
  1676. X    store(END);
  1677. X    sta = OKP;
  1678. X    return(0);
  1679. X}
  1680. X
  1681. X
  1682. Xstatic char *bol;
  1683. Xstatic char *bopat[MAXTAG];
  1684. Xstatic char *eopat[MAXTAG];
  1685. Xchar *pmatch();
  1686. X
  1687. X/*
  1688. X * re_exec:
  1689. X *     execute dfa to find a match.
  1690. X *
  1691. X *    special cases: (dfa[0])    
  1692. X *        BOL
  1693. X *            Match only once, starting from the
  1694. X *            beginning.
  1695. X *        CHR
  1696. X *            First locate the character without
  1697. X *            calling pmatch, and if found, call
  1698. X *            pmatch for the remaining string.
  1699. X *        END
  1700. X *            re_comp failed, poor luser did not
  1701. X *            check for it. Fail fast.
  1702. X *
  1703. X *    If a match is found, bopat[0] and eopat[0] are set
  1704. X *    to the beginning and the end of the matched fragment,
  1705. X *    respectively.
  1706. X *
  1707. X */
  1708. X
  1709. Xint
  1710. Xre_exec(lp)
  1711. Xregister char *lp;
  1712. X{
  1713. X    register char c;
  1714. X    register char *ep = 0;
  1715. X    register CHAR *ap = dfa;
  1716. X
  1717. X    bol = lp;
  1718. X
  1719. X    bopat[0] = 0;
  1720. X    bopat[1] = 0;
  1721. X    bopat[2] = 0;
  1722. X    bopat[3] = 0;
  1723. X    bopat[4] = 0;
  1724. X    bopat[5] = 0;
  1725. X    bopat[6] = 0;
  1726. X    bopat[7] = 0;
  1727. X    bopat[8] = 0;
  1728. X    bopat[9] = 0;
  1729. X
  1730. X    switch(*ap) {
  1731. X
  1732. X    case BOL:            /* anchored: match from BOL only */
  1733. X        ep = pmatch(lp,ap);
  1734. X        break;
  1735. X    case CHR:            /* ordinary char: locate it fast */
  1736. X        c = *(ap+1);
  1737. X        while (*lp && *lp != c)
  1738. X            lp++;
  1739. X        if (!*lp)        /* if EOS, fail, else fall thru. */
  1740. X            return(0);
  1741. X    default:            /* regular matching all the way. */
  1742. X        while (*lp) {
  1743. X            if ((ep = pmatch(lp,ap)))
  1744. X                break;
  1745. X            lp++;
  1746. X        }
  1747. X        break;
  1748. X    case END:            /* munged automaton. fail always */
  1749. X        return(0);
  1750. X    }
  1751. X    if (!ep)
  1752. X        return(0);
  1753. X
  1754. X    bopat[0] = lp;
  1755. X    eopat[0] = ep;
  1756. X    return(1);
  1757. X}
  1758. X
  1759. X/* 
  1760. X * pmatch: 
  1761. X *    internal routine for the hard part
  1762. X *
  1763. X *     This code is mostly snarfed from an early
  1764. X *     grep written by David Conroy. The backref and
  1765. X *     tag stuff, and various other mods are by oZ.
  1766. X *
  1767. X *    special cases: (dfa[n], dfa[n+1])
  1768. X *        CLO ANY
  1769. X *            We KNOW ".*" will match ANYTHING
  1770. X *            upto the end of line. Thus, go to
  1771. X *            the end of line straight, without
  1772. X *            calling pmatch recursively. As in
  1773. X *            the other closure cases, the remaining
  1774. X *            pattern must be matched by moving
  1775. X *            backwards on the string recursively,
  1776. X *            to find a match for xy (x is ".*" and 
  1777. X *            y is the remaining pattern) where
  1778. X *            the match satisfies the LONGEST match
  1779. X *            for x followed by a match for y.
  1780. X *        CLO CHR
  1781. X *            We can again scan the string forward
  1782. X *            for the single char without recursion, 
  1783. X *            and at the point of failure, we execute 
  1784. X *            the remaining dfa recursively, as
  1785. X *            described above.
  1786. X *
  1787. X *    At the end of a successful match, bopat[n] and eopat[n]
  1788. X *    are set to the beginning and end of subpatterns matched
  1789. X *    by tagged expressions (n = 1 to 9).    
  1790. X *
  1791. X */
  1792. X
  1793. Xextern void re_fail();
  1794. X
  1795. X/*
  1796. X * character classification table for word boundary
  1797. X * operators BOW and EOW. the reason for not using 
  1798. X * ctype macros is that we can let the user add into 
  1799. X * our own table. see re_modw. This table is not in
  1800. X * the bitset form, since we may wish to extend it
  1801. X * in the future for other character classifications. 
  1802. X *
  1803. X *    TRUE for 0-9 A-Z a-z _
  1804. X */
  1805. Xstatic char chrtyp[MAXCHR] = {
  1806. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1807. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1808. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1809. X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  1810. X    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
  1811. X    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
  1812. X    0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
  1813. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1814. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1815. X    1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
  1816. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1817. X    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  1818. X    1, 1, 1, 0, 0, 0, 0, 0
  1819. X    };
  1820. X
  1821. X#define inascii(x)    (0177&(x))
  1822. X#define iswordc(x)     chrtyp[inascii(x)]
  1823. X#define isinset(x,y)     ((x)[((y)&BLKIND)>>3] & (1<<((y)&BITIND)))
  1824. X
  1825. X/*
  1826. X * skip values for CLO XXX to skip past the closure
  1827. X *
  1828. X */
  1829. X
  1830. X#define ANYSKIP    2     /* CLO ANY END ...       */
  1831. X#define CHRSKIP    3    /* CLO CHR chr END ...       */
  1832. X#define CCLSKIP 18    /* CLO CCL 16bytes END ... */
  1833. X
  1834. Xstatic char *
  1835. Xpmatch(lp, ap)
  1836. Xregister char *lp;
  1837. Xregister CHAR *ap;
  1838. X{
  1839. X    register char *e;        /* extra pointer for CLO */
  1840. X    register char *bp;        /* beginning of subpat.. */
  1841. X    register char *ep;        /* ending of subpat..     */
  1842. X    register int op, c, n;
  1843. X    char *are;            /* to save the line ptr. */
  1844. X
  1845. X    while ((op = *ap++) != END)
  1846. X        switch(op) {
  1847. X
  1848. X        case CHR:
  1849. X            if (*lp++ != *ap++)
  1850. X                return(0);
  1851. X            break;
  1852. X        case ANY:
  1853. X            if (!*lp++)
  1854. X                return(0);
  1855. X            break;
  1856. X        case CCL:
  1857. X            c = *lp++;
  1858. X            if (!isinset(ap,c))
  1859. X                return(0);
  1860. X            ap += BITBLK;
  1861. X            break;
  1862. X        case NCL:
  1863. X            c = *lp++;
  1864. X            if (isinset(ap,c))
  1865. X                return(0);
  1866. X            ap += BITBLK;
  1867. X            break;
  1868. X        case BOL:
  1869. X            if (lp != bol)
  1870. X                return(0);
  1871. X            break;
  1872. X        case EOL:
  1873. X            if (*lp)
  1874. X                return(0);
  1875. X            break;
  1876. X        case BOT:
  1877. X            bopat[*ap++] = lp;
  1878. X            break;
  1879. X        case EOT:
  1880. X            eopat[*ap++] = lp;
  1881. X            break;
  1882. X         case BOW:
  1883. X            if (!(lp!=bol && iswordc(lp[-1])) && iswordc(*lp))
  1884. X                break;
  1885. X            return(0);
  1886. X        case EOW:
  1887. X            if ((lp!=bol && iswordc(lp[-1])) && !iswordc(*lp))
  1888. X                break;
  1889. X            return(0);
  1890. X        case REF:
  1891. X            n = *ap++;
  1892. X            bp = bopat[n];
  1893. X            ep = eopat[n];
  1894. X            while (bp < ep)
  1895. X                if (*bp++ != *lp++)
  1896. X                    return(0);
  1897. X            break;
  1898. X        case CLO:
  1899. X            are = lp;
  1900. X            switch(*ap) {
  1901. X
  1902. X            case ANY:
  1903. X                while (*lp)
  1904. X                    lp++;
  1905. X                n = ANYSKIP;
  1906. X                break;
  1907. X            case CHR:
  1908. X                c = *(ap+1);
  1909. X                while (*lp && c == *lp)
  1910. X                    lp++;
  1911. X                n = CHRSKIP;
  1912. X                break;
  1913. X            case CCL:
  1914. X            case NCL:
  1915. X                while (*lp && (e = pmatch(lp, ap)))
  1916. X                    lp = e;
  1917. X                n = CCLSKIP;
  1918. X                break;
  1919. X            default:
  1920. X                re_fail("closure: bad dfa.", *ap);
  1921. X                return(0);
  1922. X            }
  1923. X
  1924. X            ap += n;
  1925. X
  1926. X            while (lp >= are) {
  1927. X                if (e = pmatch(lp, ap))
  1928. X                    return(e);
  1929. X                --lp;
  1930. X            }
  1931. X            return(0);
  1932. X        default:
  1933. X            re_fail("re_exec: bad dfa.", op);
  1934. X            return(0);
  1935. X        }
  1936. X    return(lp);
  1937. X}
  1938. X
  1939. X/*
  1940. X * re_modw:
  1941. X *    add new characters into the word table to
  1942. X *    change the re_exec's understanding of what
  1943. X *    a word should look like. Note that we only
  1944. X *    accept additions into the word definition.
  1945. X *
  1946. X *    If the string parameter is 0 or null string,
  1947. X *    the table is reset back to the default, which
  1948. X *    contains A-Z a-z 0-9 _. [We use the compact
  1949. X *    bitset representation for the default table]
  1950. X *
  1951. X */
  1952. X
  1953. Xstatic char deftab[16] = {    
  1954. X    0, 0, 0, 0, 0, 0, 377, 003, 376, 377, 377, 207,  
  1955. X    376, 377, 377, 007 
  1956. X}; 
  1957. X
  1958. Xvoid
  1959. Xre_modw(s)
  1960. Xregister char *s;
  1961. X{
  1962. X    register int i;
  1963. X
  1964. X    if (!s || !*s) {
  1965. X        for (i = 0; i < MAXCHR; i++)
  1966. X            if (!isinset(deftab,i))
  1967. X                iswordc(i) = 0;
  1968. X    }
  1969. X    else
  1970. X        while(*s)
  1971. X            iswordc(*s++) = 1;
  1972. X}
  1973. X
  1974. X/*
  1975. X * re_subs:
  1976. X *    substitute the matched portions of the src in
  1977. X *    dst.
  1978. X *
  1979. X *    &    substitute the entire matched pattern.
  1980. X *
  1981. X *    \digit    substitute a subpattern, with the given
  1982. X *        tag number. Tags are numbered from 1 to
  1983. X *        9. If the particular tagged subpattern
  1984. X *        does not exist, null is substituted.
  1985. X *
  1986. X */
  1987. Xint
  1988. Xre_subs(src, dst)
  1989. Xregister char *src;
  1990. Xregister char *dst;
  1991. X{
  1992. X    register char c;
  1993. X    register int  pin;
  1994. X    register char *bp;
  1995. X    register char *ep;
  1996. X
  1997. X    if (!*src || !bopat[0])
  1998. X        return(0);
  1999. X
  2000. X    while (c = *src++) {
  2001. X        switch(c) {
  2002. X
  2003. X        case '&':
  2004. X            pin = 0;
  2005. X            break;
  2006. X
  2007. X        case '\\':
  2008. X            c = *src++;
  2009. X            if (c >= '0' && c <= '9') {
  2010. X                pin = c - '0';
  2011. X                break;
  2012. X            }
  2013. X            
  2014. X        default:
  2015. X            *dst++ = c;
  2016. X            continue;
  2017. X        }
  2018. X
  2019. X        if ((bp = bopat[pin]) && (ep = eopat[pin])) {
  2020. X            while (*bp && bp < ep)
  2021. X                *dst++ = *bp++;
  2022. X            if (bp < ep)
  2023. X                return(0);
  2024. X        }
  2025. X    }
  2026. X    *dst = (char) 0;
  2027. X    return(1);
  2028. X}
  2029. X            
  2030. X#ifdef DEBUG
  2031. X/*
  2032. X * symbolic - produce a symbolic dump of the
  2033. X *            dfa
  2034. X */
  2035. Xsymbolic(s) 
  2036. Xchar *s;
  2037. X{
  2038. X    printf("pattern: %s\n", s);
  2039. X    printf("dfacode:\n");
  2040. X    dfadump(dfa);
  2041. X}
  2042. X
  2043. Xstatic    
  2044. Xdfadump(ap)
  2045. XCHAR *ap;
  2046. X{
  2047. X    register int n;
  2048. X
  2049. X    while (*ap != END)
  2050. X        switch(*ap++) {
  2051. X        case CLO:
  2052. X            printf("CLOSURE");
  2053. X            dfadump(ap);
  2054. X            switch(*ap) {
  2055. X            case CHR:
  2056. X                n = CHRSKIP;
  2057. X                break;
  2058. X            case ANY:
  2059. X                n = ANYSKIP;
  2060. X                break;
  2061. X            case CCL:
  2062. X            case NCL:
  2063. X                n = CCLSKIP;
  2064. X                break;
  2065. X            }
  2066. X            ap += n;
  2067. X            break;
  2068. X        case CHR:
  2069. X            printf("\tCHR %c\n",*ap++);
  2070. X            break;
  2071. X        case ANY:
  2072. X            printf("\tANY .\n");
  2073. X            break;
  2074. X        case BOL:
  2075. X            printf("\tBOL -\n");
  2076. X            break;
  2077. X        case EOL:
  2078. X            printf("\tEOL -\n");
  2079. X            break;
  2080. X        case BOT:
  2081. X            printf("BOT: %d\n",*ap++);
  2082. X            break;
  2083. X        case EOT:
  2084. X            printf("EOT: %d\n",*ap++);
  2085. X            break;
  2086. X        case BOW:
  2087. X            printf("BOW\n");
  2088. X            break;
  2089. X        case EOW:
  2090. X            printf("EOW\n");
  2091. X            break;
  2092. X        case REF:
  2093. X            printf("REF: %d\n",*ap++);
  2094. X            break;
  2095. X        case CCL:
  2096. X            printf("\tCCL [");
  2097. X            for (n = 0; n < MAXCHR; n++)
  2098. X                if (isinset(ap,(CHAR)n))
  2099. X                    printf("%c",n);
  2100. X            printf("]\n");
  2101. X            ap += BITBLK;
  2102. X            break;
  2103. X        case NCL:
  2104. X            printf("\tNCL [");
  2105. X            for (n = 0; n < MAXCHR; n++)
  2106. X                if (isinset(ap,(CHAR)n))
  2107. X                    printf("%c",n);
  2108. X            printf("]\n");
  2109. X            ap += BITBLK;
  2110. X            break;
  2111. X        default:
  2112. X            printf("bad dfa. opcode %o\n", ap[-1]);
  2113. X            exit(1);
  2114. X            break;
  2115. X        }
  2116. X}
  2117. X#endif
  2118. END_OF_FILE
  2119. if test 18831 -ne `wc -c <'regex.c'`; then
  2120.     echo shar: \"'regex.c'\" unpacked with wrong size!
  2121. fi
  2122. # end of 'regex.c'
  2123. fi
  2124. if test -f 'sample.cdmount' -a "${1}" != "-c" ; then 
  2125.   echo shar: Will not clobber existing file \"'sample.cdmount'\"
  2126. else
  2127. echo shar: Extracting \"'sample.cdmount'\" \(780 characters\)
  2128. sed "s/^X//" >'sample.cdmount' <<'END_OF_FILE'
  2129. X#!/bin/sh
  2130. X
  2131. Xprog=`basename $0`
  2132. X# If script invoked w/o super, then exec super to run this script.
  2133. Xif [ X$SUPERCMD = X ] ; then exec /usr/local/bin/super $prog "$@" ; fi
  2134. X
  2135. Xusage() {
  2136. Xcat <<-END
  2137. X    Use:
  2138. X        $prog hsfs | 4.2
  2139. X
  2140. X    Purpose:
  2141. X        Mounts a cdrom on /cdrom.
  2142. X
  2143. X    Argument: the cdrom type; specify one of
  2144. X        hsfs    - cdrom is High Sierra File System
  2145. X        4.2        - usual Unix disk format
  2146. X
  2147. XEND
  2148. X}
  2149. X
  2150. Xcase $# in
  2151. X    1 ) ;;
  2152. X    * ) usage ; exit 1 ;;
  2153. Xesac
  2154. X
  2155. Xtype="$1"
  2156. Xcase "$type" in
  2157. X    4.2 | hsfs ) ;;
  2158. X    -h ) usage ; exit 0 ;;
  2159. X    * ) echo "$prog: unknown cd type $1" ; usage ; exit 1 ;;
  2160. Xesac
  2161. X
  2162. XPATH=$PATH:/usr/etc        # SunOS 4.x needs this to understand type hsfs
  2163. Xexport PATH
  2164. X
  2165. Xecho /etc/mount -v -r -t $type -o nosuid /dev/sr0 /cdrom
  2166. X     /etc/mount -v -r -t $type -o nosuid /dev/sr0 /cdrom
  2167. END_OF_FILE
  2168. if test 780 -ne `wc -c <'sample.cdmount'`; then
  2169.     echo shar: \"'sample.cdmount'\" unpacked with wrong size!
  2170. fi
  2171. # end of 'sample.cdmount'
  2172. fi
  2173. if test -f 'sample.tab' -a "${1}" != "-c" ; then 
  2174.   echo shar: Will not clobber existing file \"'sample.tab'\"
  2175. else
  2176. echo shar: Extracting \"'sample.tab'\" \(2104 characters\)
  2177. sed "s/^X//" >'sample.tab' <<'END_OF_FILE'
  2178. X# This file lists commands that super(1) will execute for you as root.
  2179. X
  2180. X# The format for data lines in this file is
  2181. X
  2182. X#    commandname   fullpathname      ed patterns of valid users/groups/hosts
  2183. X
  2184. X# -- The commandname must begin in column 1.  Lines may be continued with a
  2185. X#    backslash immediately preceding a newline; the continuation line must
  2186. X#    begin with whitespace.  (This requirement helps super() catch typos.)
  2187. X
  2188. X# The format for a users/groups/hosts entry is
  2189. X#    user[:][@host]   or  :group[@host]   or  user:group[@host]
  2190. X
  2191. X# -- Since you can specify a host in the entry, a single super.tab file can
  2192. X#    be used by many different machines.
  2193. X
  2194. X# -- All patterns are "anchored"; i.e. they are forced to match the entire
  2195. X#    username, groupname, or hostname.
  2196. X
  2197. X# -- Patterns can use csh-style "brace expansion".  For instance,
  2198. X#    a{x,y,z}b is replaced with axb ayb azb.
  2199. X
  2200. X# -- If a hostname is of the form "+xyz", then "xyz" is interpreted as
  2201. X#    a netgroup name and any host in netgroup xyz is matched.  In that
  2202. X#    case, "xyz" CANNOT CONTAIN WILDCARDS.  Note: netgroup lookup is only
  2203. X#    implemented if the function innetgr() is available and if super()
  2204. X#    was compiled with -DUSE_NETGROUP.
  2205. X
  2206. X# Example entry:
  2207. X
  2208. X#    doit    /usr/local/bin/doit    me \
  2209. X#                    you@{h1,h2}  \
  2210. X#                    ja.*:ok_j \
  2211. X#                    :goodguys
  2212. X
  2213. X# ...allows /usr/local/bin/doit to be run setuid root by:
  2214. X
  2215. X#        user "me" on any host,
  2216. X#        user "you" on hosts h1 and h2;
  2217. X#        any users named "ja.*" in group "ok_j";
  2218. X#        and anybody in group "goodguys".
  2219. X# ...by typing
  2220. X#    % super doit [ doit args ]
  2221. X
  2222. X# ---------------------------------------------------------------------------
  2223. X# Cmd    Full Path        Valid-User/Group/Host Patterns
  2224. X
  2225. Xtimeout    /usr/local/bin/timeout    :operator :wheel gv phillips srk
  2226. Xrestart    /usr/local/bin/restart    :operator :wheel gv phillips srk
  2227. X
  2228. X# Local restrictions on CD-ROM mounting:  tas is the only user who may mount
  2229. X#        cd's on elgar; anybody in group xyz may mount cd's on
  2230. X#        alpha or delta; and anybody on a host in the netgroup "india"
  2231. X#        may mount a CD on the "india" machines.
  2232. X
  2233. Xcdmount    /usr/local/bin/cdmount    tas@elgar        \
  2234. X                :xyz@{alpha,delta}    \
  2235. X                .*@+india
  2236. END_OF_FILE
  2237. if test 2104 -ne `wc -c <'sample.tab'`; then
  2238.     echo shar: \"'sample.tab'\" unpacked with wrong size!
  2239. fi
  2240. # end of 'sample.tab'
  2241. fi
  2242. if test -f 'super.1' -a "${1}" != "-c" ; then 
  2243.   echo shar: Will not clobber existing file \"'super.1'\"
  2244. else
  2245. echo shar: Extracting \"'super.1'\" \(3793 characters\)
  2246. sed "s/^X//" >'super.1' <<'END_OF_FILE'
  2247. X.TH SUPER 1 local
  2248. X.SH NAME
  2249. Xsuper \- execute commands setuid root.
  2250. X.SH SYNOPSIS
  2251. X.B super
  2252. X.I command
  2253. X[
  2254. X.I args
  2255. X]
  2256. X.SH DESCRIPTION
  2257. X.I Super
  2258. Xallows users to execute scripts (or other commands) as if they were root.
  2259. XIt
  2260. Xis intended to be a secure alternative to making scripts setuid root.
  2261. XIt also permits restricting certain commands to particular combinations
  2262. Xof user, group, and host.
  2263. X.PP
  2264. X.I Super
  2265. Xconsults a file to see if the user is allowed to execute the requested
  2266. X.IR command .
  2267. XIf so,
  2268. X.I super
  2269. Xwill exec
  2270. X.IR command\  [\  args\  ].
  2271. XRoot is always permitted to execute any command in the
  2272. Xsuper file.
  2273. X.PP
  2274. X.I Super
  2275. Xwithout any arguments will display its list of commands and their allowed users.
  2276. X.PP
  2277. XFor security, the following precautions are taken before exec'ing:
  2278. X.HP
  2279. X\fI(a)\fP    all descriptors save 0,1,2 are closed;
  2280. X.HP
  2281. X\fI(b)\fP    all of the user's environment variables are
  2282. Xdiscarded, save for TERM, LINES, and COLUMNS.
  2283. XIf TERM contains any characters other than
  2284. X[a-z][A-Z][0-9]_, it is discarded.
  2285. XIf LINES or COLUMNS contains any
  2286. Xcharacters other than [0-9], it are discarded.
  2287. XTo these
  2288. Xare added reasonable values for:
  2289. X.RS
  2290. X.HP
  2291. XUSER and LOGNAME: both are set to the username
  2292. Xof the real user running
  2293. X.IR super ;
  2294. X.HP
  2295. XHOME: set to the login directory
  2296. Xof the real user running
  2297. X.IR super ;
  2298. X.HP
  2299. XIFS: set to blank, tab, newline;
  2300. X.HP
  2301. XPATH: set to \fI/bin:/usr/bin:/usr/ucb\fP.
  2302. X.HP
  2303. XSUPERCMD: set to \fIcommand\fP.
  2304. X.RE
  2305. X.in -.5i
  2306. X.HP
  2307. X\fI(c)\fP    all signal handling is reset to the default.
  2308. X.SH OPTIONS
  2309. X.HP
  2310. X.BR \-h \ |\  \-?
  2311. XIf no arguments are given, or if the first argument is ``\-h'' or ``\-?'',
  2312. X.I super
  2313. Xprints a usage line and lists all the available commands.
  2314. X.SH FILES
  2315. X.HP
  2316. X.I /usr/local/lib/super.tab
  2317. X\(em contains the list of commands that
  2318. X.I super
  2319. Xmay execute, along with the names of the user/group combinations
  2320. Xwho may execute each command.  The valid-user line can restrict use to
  2321. Xparticular users or groups on different hosts, so a single super.tab
  2322. Xfile can be used across a network.
  2323. X.SH CREATING SUPER SCRIPTS
  2324. XYou must be exceedingly careful when writing scripts for
  2325. X.IR super .
  2326. XA surprising variety of ordinary commands can, when
  2327. Xrun setuid-root, be exploited for nasty purposes.  Always make your
  2328. Xscripts do as little as possible, and give the user as few options
  2329. Xas possible.
  2330. X.PP
  2331. XThink twice about side-effects and alternative uses
  2332. Xof these scripts.  For instance, you might write a script to allow
  2333. Xusers to mount cd-rom's by executing
  2334. X.IR mount(8) .
  2335. XBut if you don't write it carefully, a user could mount a floppy
  2336. Xdisk containing, say, a setuid-root shell.
  2337. X.PP
  2338. XSecurity issues aside, here are some hints on creating super scripts:
  2339. X.HP
  2340. X1.    Scripts must begin with 
  2341. X.BI #! interpreter-path . 
  2342. X.HP
  2343. X2.    Some variants of csh will not run setuid scripts unless the \-b flag
  2344. X(force a "break" from option processing) is set:
  2345. X.ti +.5i
  2346. X#!/bin/csh -fb
  2347. X.br
  2348. X.HP
  2349. X3.    It's nice to make the
  2350. X.I super
  2351. Xcall transparent to users, so that they can type
  2352. X.ti +.5i
  2353. X% cdmount \fIargs\fP
  2354. X.br
  2355. Xinstead of
  2356. X.ti +.5i
  2357. X% super cdmount \fIargs\fP
  2358. X.br
  2359. XYou can make a script
  2360. X.I super
  2361. Xitself by beginning the script in the following way:
  2362. X.in +.5i
  2363. X.nf
  2364. X#!/bin/sh
  2365. Xprog=`basename $0`
  2366. Xif [ X$SUPERCMD != X$prog ] ; then
  2367. X    exec /usr/local/bin/super $prog "$@"
  2368. Xfi
  2369. X.fi
  2370. X.in -1i
  2371. X.HP
  2372. X4.    Some programs need certain directories in the path.  Your
  2373. Xsuper scripts may have to add directories like
  2374. X.I /etc
  2375. Xor
  2376. X.I /usr/etc
  2377. Xto make commands work.
  2378. XFor instance, SunOS\ 4.1 needs
  2379. X.I /usr/etc
  2380. Xin the path before it can mount filesystems of type ``hsfs''.
  2381. X.HP
  2382. X5.    \fISuper\fP only changes the effective uid.
  2383. XSome programs (e.g. \fIexportfs\fP under SunOS\ 4.1.x)
  2384. Xrequire the real uid to be root.  In that case, your super
  2385. Xscript will have to change the real uid to root before executing the command.
  2386. X.SH AUTHOR
  2387. XWill Deich
  2388. X.br
  2389. Xwill@surya.caltech.edu
  2390. END_OF_FILE
  2391. if test 3793 -ne `wc -c <'super.1'`; then
  2392.     echo shar: \"'super.1'\" unpacked with wrong size!
  2393. fi
  2394. # end of 'super.1'
  2395. fi
  2396. if test -f 'super.c' -a "${1}" != "-c" ; then 
  2397.   echo shar: Will not clobber existing file \"'super.c'\"
  2398. else
  2399. echo shar: Extracting \"'super.c'\" \(5731 characters\)
  2400. sed "s/^X//" >'super.c' <<'END_OF_FILE'
  2401. X#include <stdio.h>
  2402. X#include <string.h>
  2403. X#include <signal.h>
  2404. X#include <sys/param.h>
  2405. X#include <unistd.h>
  2406. X
  2407. Xstatic char SccsId[] = "@(#)super.c    1.12\t4/13/93";
  2408. X
  2409. X#ifndef SUPERFILE
  2410. X#define SUPERFILE "/usr/local/lib/super.tab"
  2411. X#endif
  2412. X
  2413. X/*
  2414. X *    Copyright (c) 1993 by California Institute of Technology.
  2415. X *    Written by William Deich.  Not derived from licensed software.
  2416. X
  2417. X *    Permission is granted to anyone to use this software for any
  2418. X *    purpose on any computer system, and to redistribute it freely,
  2419. X *    subject to the following restrictions:
  2420. X *
  2421. X *    1. The author is not responsible for the consequences of use of this
  2422. X *       software, no matter how awful, even if they arise from defects in it.
  2423. X *
  2424. X *    2. The origin of this software must not be misrepresented, either
  2425. X *       by explicit claim or by omission.
  2426. X *
  2427. X *    3. Altered versions must be plainly marked as such, and must not
  2428. X *       be misrepresented as being the original software.
  2429. X */
  2430. X
  2431. X/*
  2432. X * Super allows users to execute other programs (particularly
  2433. X * scripts) as root, without unduly compromising security.
  2434. X * 
  2435. X * Use:
  2436. X * 
  2437. X *     $0 commandname args...
  2438. X * 
  2439. X * If the commandname is "-h" or "-?", or missing, super prints its current
  2440. X * list of allowed commands, but nothing executed.
  2441. X * 
  2442. X * The super.tab file names each command that super will execute, and
  2443. X * says who can use it. It contains lines like:
  2444. X * 
  2445. X *     commandname   fullpathname    valid-user/group ed-type patterns
  2446. X * 
  2447. X * See sample.tab for how to specify user & group patterns.
  2448. X * If a user is allowed to execute a given <commandname>, the <fullpathname>
  2449. X * is exec'd, with <commandname> as argv[0].
  2450. X * 
  2451. X * For security, the environment variables are discarded, save for TERM,
  2452. X * LINES, and COLUMNS.  If TERM contains any characters other than
  2453. X * [a-z][A-Z][0-9]_, it is discarded.  If LINES or COLUMNS contains any
  2454. X * characters other than [0-9], they are discarded.  To these are added
  2455. X * reasonable values for IFS, PATH, USER and HOME (USER and HOME are set
  2456. X * to the username and login directory, respectively, of the person who
  2457. X * who runs super).  LOGNAME is set to the same as USER.  SUPERCMD is set
  2458. X * to the <command>.  All descriptors excepting 0,1,2 are closed.  Signals
  2459. X * are all reset to have default handling.
  2460. X */
  2461. X
  2462. X
  2463. Xstatic char *SAFE_IFS = "IFS= \t\n";
  2464. Xstatic char *SAFE_PATH = "PATH=/bin:/usr/bin:/usr/ucb";
  2465. X
  2466. Xchar *prog;    /* This program */
  2467. Xchar *user;    /* who's invoking prog */
  2468. X
  2469. Xmain(argc, argv)
  2470. Xint argc;
  2471. Xchar **argv;
  2472. X{
  2473. X    char *s, *path, *approve();
  2474. X    char **buttonup(), **envp;
  2475. X    void exit();
  2476. X
  2477. X    s = strchr(argv[0], '/');
  2478. X    prog = (s && *(s+1)) ? s+1 : argv[0];
  2479. X
  2480. X    if ((path = approve(SUPERFILE, argv[1])) == NULL)
  2481. X    (void) exit(1);
  2482. X    else if (*path == '\0')
  2483. X    (void) exit(0);
  2484. X
  2485. X    /* Button up for security, and get a modified environment */
  2486. X    envp = buttonup(argv[1]);
  2487. X
  2488. X    if (execve(path, &argv[1], envp) == -1) {
  2489. X    (void) fprintf(stderr, "%s: Couldn't exec %s (%s): ",
  2490. X                    prog, argv[1], path);
  2491. X    perror("");
  2492. X    (void) exit(1);
  2493. X    }
  2494. X    return 0;
  2495. X}
  2496. X
  2497. Xchar **
  2498. Xbuttonup(cmd)
  2499. Xchar *cmd;    /* name of command being started */
  2500. X{
  2501. X    /* Closes all descriptors save 0,1,2.
  2502. X     * Resets all signal-handling to SIG_DFL.
  2503. X     * Discards all env. variables save for TERM, LINES, and COLUMNS.
  2504. X     * Don't allow TERM to have any but alpha characters and underscore.
  2505. X     * Don't allow LINES, COLUMNS to have anything but digits.
  2506. X     * To these are added reasonable values for IFS, PATH, USER, and HOME.
  2507. X     * LOGNAME is set to the same as USER, and SUPERCMD is set to cmd.
  2508. X     * Returned:
  2509. X     *    a pointer to the modified environment list.
  2510. X     */
  2511. X    int i, fd, n;
  2512. X    char *Getenv();
  2513. X    int getlogdir();
  2514. X    int checkenv();
  2515. X    static char *env[10];
  2516. X    static char User[100];        /* USER */
  2517. X    static char Logname[100];        /* LOGNAME (alias for USER) */
  2518. X    static char Home[MAXPATHLEN+5];    /* HOME */
  2519. X    static char Cmd[1200];        /* SUPERCMD */
  2520. X    void (*signal())();
  2521. X
  2522. X#ifdef MAXFD
  2523. X    n = MAXFD ;
  2524. X#else
  2525. X    n = getdtablesize(); 
  2526. X#endif
  2527. X    for (fd=3; fd <= n; fd++)
  2528. X    (void) close(fd);
  2529. X    
  2530. X    for (i=0; i<NSIG; i++)
  2531. X       (void) signal(i, SIG_DFL);
  2532. X
  2533. X    (void) sprintf(User, "USER=%s", user);
  2534. X    (void) sprintf(Logname, "LOGNAME=%s", user);
  2535. X    (void) sprintf(Cmd, "SUPERCMD=%s", cmd);
  2536. X    (void) strcpy(Home, "HOME=");
  2537. X    (void) getlogdir(user, Home+5);
  2538. X    i = 0;
  2539. X    env[i] = Getenv("TERM");
  2540. X    if (env[i] && checkenv("TERM", env[i]+5, "^[a-zA-Z0-9]*$")) i++;
  2541. X    env[i] = Getenv("LINES");
  2542. X    if (env[i] && checkenv("LINES", env[i]+6, "^[0-9]*$")) i++;
  2543. X    env[i] = Getenv("COLUMNS");
  2544. X    if (env[i] && checkenv("COLUMNS", env[i]+8, "^[0-9]*$")) i++;
  2545. X    env[i++] = SAFE_IFS;
  2546. X    env[i++] = SAFE_PATH;
  2547. X    env[i++] = User;
  2548. X    env[i++] = Logname;
  2549. X    env[i++] = Cmd;
  2550. X    env[i] = (char *) NULL;
  2551. X
  2552. X    return &env[0];
  2553. X}
  2554. X
  2555. Xchar *
  2556. XGetenv(s)
  2557. Xchar *s;
  2558. X{
  2559. X    /* Like getenv(), but returns ptr to the <name> in "name=xxxx",
  2560. X     * not just the xxxx.
  2561. X     */
  2562. X    char **envp; 
  2563. X    int l;
  2564. X    extern char **environ;
  2565. X
  2566. X    if (!s)
  2567. X    return (char *) NULL;
  2568. X    l = strlen(s);
  2569. X    for (envp=environ; *envp ; envp++)
  2570. X    if (strncmp(*envp, s, l) == 0  &&  *(*envp+l) == '=')
  2571. X        return *envp;
  2572. X    return (char *) NULL;
  2573. X}
  2574. X
  2575. X/* Returns 1 if pat matched; 0 otherwise.  */
  2576. Xcheckenv(name, value, pat)
  2577. Xchar *name;    /* variable name to check (e.g. "TERM") */
  2578. Xchar *value;    /* contents of variable (e.g. "vt100") */
  2579. Xchar *pat;    /* pattern that value must match */
  2580. X{
  2581. X    char *re_comp();
  2582. X    int re_exec();
  2583. X
  2584. X    if (!value)
  2585. X    return 0;
  2586. X    
  2587. X    if (re_comp(pat)) {
  2588. X    (void) fprintf(stderr,
  2589. X        "%s: Warning: couldn't compile pattern `%s'\n", prog, pat);
  2590. X    return 0;
  2591. X    }
  2592. X
  2593. X    if (re_exec(value) != 1) {
  2594. X    (void) fprintf(stderr,
  2595. X        "%s: %s (%s) doesn't match %s.\n", prog, name, value, pat);
  2596. X    return 0;
  2597. X    }
  2598. X    return 1;
  2599. X}
  2600. END_OF_FILE
  2601. if test 5731 -ne `wc -c <'super.c'`; then
  2602.     echo shar: \"'super.c'\" unpacked with wrong size!
  2603. fi
  2604. # end of 'super.c'
  2605. fi
  2606. if test -f 'version.h' -a "${1}" != "-c" ; then 
  2607.   echo shar: Will not clobber existing file \"'version.h'\"
  2608. else
  2609. echo shar: Extracting \"'version.h'\" \(46 characters\)
  2610. sed "s/^X//" >'version.h' <<'END_OF_FILE'
  2611. X#define Version        "2.0"
  2612. X#define Patchlevel    "1"
  2613. END_OF_FILE
  2614. if test 46 -ne `wc -c <'version.h'`; then
  2615.     echo shar: \"'version.h'\" unpacked with wrong size!
  2616. fi
  2617. # end of 'version.h'
  2618. fi
  2619. if test -f 'word.c' -a "${1}" != "-c" ; then 
  2620.   echo shar: Will not clobber existing file \"'word.c'\"
  2621. else
  2622. echo shar: Extracting \"'word.c'\" \(1222 characters\)
  2623. sed "s/^X//" >'word.c' <<'END_OF_FILE'
  2624. X#include <ctype.h>
  2625. X
  2626. Xstatic char SccsId[] = "@(#)word.c    1.3\t4/13/93";
  2627. X
  2628. X/* Returns a pointer to the start of the k'th word in s.
  2629. X * Numbering is that k=1 for the first word.
  2630. X * A pointer to a null string is returned if there is no k'th word.
  2631. X */
  2632. X
  2633. X/*
  2634. X * Compile with -DPROGRAM to get a standalone program that's used as
  2635. X *     $0  k  string
  2636. X * and prints the k'th whitespace-separated word of the string on stdout.
  2637. X */  
  2638. X
  2639. Xchar *
  2640. Xword(s, sep, k)
  2641. Xregister char *s;
  2642. Xregister char *sep;    /* word separators */
  2643. Xint k;
  2644. X{
  2645. X    int i;
  2646. X    
  2647. X    /* Skip leading separators */
  2648. X    s += strspn(s, sep);
  2649. X
  2650. X    /* Skip words before the k'th word */
  2651. X    for (i=1; i<k; i++) {
  2652. X    if (*s) s += strcspn(s, sep);    /* Skip a word... */
  2653. X    if (*s) s += strspn(s, sep);    /* ...and the trailing separators */
  2654. X    }
  2655. X    return s;
  2656. X}    
  2657. X
  2658. X#ifdef TEST
  2659. X#include <stdio.h>
  2660. X#include <string.h>
  2661. Xmain(argc, argv)
  2662. Xint argc;
  2663. Xchar **argv;
  2664. X{
  2665. X    char *prog, *word();
  2666. X    int atoi();
  2667. X
  2668. X    prog = strrchr(argv[0], '/');
  2669. X    prog = (prog && *(prog+1)) ? prog+1 : (prog) ? prog : argv[0];
  2670. X    if (argc != 3) {
  2671. X    (void) fprintf(stderr, "Usage: %s  k  \"string\"\n", prog);
  2672. X    (void) exit(1);
  2673. X    }
  2674. X    printf("%s\n", word(argv[2], " \t\v", atoi(argv[1])));
  2675. X    return 0;
  2676. X}
  2677. X#endif
  2678. END_OF_FILE
  2679. if test 1222 -ne `wc -c <'word.c'`; then
  2680.     echo shar: \"'word.c'\" unpacked with wrong size!
  2681. fi
  2682. # end of 'word.c'
  2683. fi
  2684. echo shar: End of archive 1 \(of 1\).
  2685. cp /dev/null ark1isdone
  2686. MISSING=""
  2687. for I in 1 ; do
  2688.     if test ! -f ark${I}isdone ; then
  2689.     MISSING="${MISSING} ${I}"
  2690.     fi
  2691. done
  2692. if test "${MISSING}" = "" ; then
  2693.     echo You have the archive.
  2694.     rm -f ark[1-9]isdone
  2695. else
  2696.     echo You still need to unpack the following archives:
  2697.     echo "        " ${MISSING}
  2698. fi
  2699. ##  End of shell archive.
  2700. exit 0
  2701.