home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume4 / access / access.c next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  18.7 KB  |  735 lines

  1. /*   Copyright (c) 1988 by George M. Sipe.  All rights reserved.
  2.  
  3. This software may only be redistributed without fee and without any
  4. other form of monetary gain (including sold, rented, leased, or
  5. traded), unless the express written permission of the copyright holder
  6. is obtained in advance.
  7.  
  8. This copyright notice must be reproduced in its entirety on all copies
  9. of this software.  Further, acknowledgment of the authorship of this
  10. software must not be removed from its current or derived
  11. documentation.
  12.  
  13. No expressed or implied warranty is made for this software.  No party
  14. connected with this software assumes any liability or responsibility
  15. for its use, the correctness of its operation, or its fitness for any
  16. purpose.
  17.  
  18. Any distributor of copies of this software shall grant the recipient
  19. permission for further redistribution as permitted by this notice.
  20.  
  21. Permission is hereby granted to copy, reproduce, redistribute and
  22. otherwise use this software as long as the conditions above are
  23. strictly adhered to.                            */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <pwd.h>
  28. #include <sys/types.h>
  29. #ifndef    BSD
  30. #include <time.h>
  31. #define    MAXPATHLEN    1024
  32. void exit();
  33. char *strchr();
  34. char *strrchr();
  35. long time();
  36. #else
  37. #include <sys/time.h>
  38. #include <sys/param.h>
  39. #undef    MIN
  40. #define    strchr(s,c)    index(s,c)
  41. #define    strrchr(s,c)    rindex(s,c)
  42. exit();
  43. char *index();
  44. char *rindex();
  45. time_t time();
  46. #endif
  47.  
  48. int execve();
  49. int fclose();
  50. int fgetc();
  51. char *fgets();
  52. FILE *fopen();
  53. int fputc();
  54. int fputs();
  55. int geteuid();
  56. struct passwd *getpwuid();
  57. struct tm *localtime();
  58. char *strcat();
  59. char *strcpy();
  60. int strlen();
  61. int strncmp();
  62. char *ttyname();
  63. int ungetc();
  64.  
  65. /* #define    DEBUG        /* define for tracing information */
  66.  
  67. #ifndef    TRUE
  68. #define    TRUE    1        /* true and false */
  69. #define    FALSE    0
  70. #endif
  71. #define    UNSET    3        /* unset flag */
  72.  
  73. #ifndef    DEBUG
  74. #define    ACFILE    "/usr/local/lib/access"
  75. #else
  76. #define    ACFILE    "test"
  77. #endif    DEBUG
  78. #define    MAXENT    1024        /* maximum entry length */
  79. #define    MAXARGS    99        /* maximum number of arguments in file */
  80. #define    MAXSH    MAXPATHLEN+7    /* maximum size of SHELL environment variable */
  81.  
  82. #define    TTY    't'        /* ttyname restrictor */
  83. #define    MIN    'm'        /* minute restrictor */
  84. #define    HOUR    'h'        /* hour restrictor */
  85. #define    WDAY    'w'        /* day of week restrictor */
  86. #define    MDAY    'D'        /* day of month restrictor */
  87. #define    MON    'M'        /* month restrictor */
  88. #define    YEAR    'Y'        /* year restrictor */
  89. #define    OR    'o'        /* logical or separator */
  90. #define    PATH    '/'        /* pathname prefix */
  91.  
  92. #define    ERRNTTY    101        /* not connected to a tty */
  93. #define    ERRSEP    102        /* missing separator between values */
  94. #define    ERRRNG1    103        /* '-' appears twice in range */
  95. #define    ERRRNG2    104        /* '-' does not follow value */
  96. #define    ERRNUL    105        /* null value */
  97. #define    ERRMIN    106        /* value below minimum */
  98. #define    ERRMAX    107        /* value exceeds maximum */
  99. #define    ERRBAD    108        /* invalid character */
  100.  
  101. typedef    char BOOL;
  102.  
  103. static struct tm *timenow;    /* the current local time */
  104. static char *name = NULL;    /* pointer to username */
  105. static int namesz;        /* size of username */
  106. static char *ttynm = NULL;    /* pointer to ttyname */
  107. static int ttysz;        /* size of ttyname */
  108.  
  109. static BOOL user;        /* TRUE or FALSE */
  110. static BOOL tty;        /* UNSET, TRUE, or FALSE */
  111. static BOOL min[60];        /* 0 to 59 */
  112. static BOOL hour[24];        /* 0 to 23 */
  113. static BOOL wday[8];        /* 0 (Sunday) to 6 (Saturday);  7 = 0 too */
  114. static BOOL mday[32];        /* 1 to 31 */
  115. static BOOL mon[13];        /* 1 to 12 */
  116. static BOOL year[99];        /* 87 to 99 */
  117.  
  118. /* Display userchk(), ttychk(), and expand() error message. */
  119.  
  120. static void error(type, string, code)
  121. char *type;
  122. char *string;
  123. int code;
  124. {
  125.     fputs("\n*** system access processing failure - ", stderr);
  126.     fputs("report to your system manager ***\n\n", stderr);
  127.  
  128.     if (code == 0) {
  129.         fputs(type, stderr);
  130.         fputs(string, stderr);
  131.         fputc('\n', stderr);
  132.         exit(0);
  133.     }
  134.  
  135.     fputs("invalid ", stderr);
  136.     fputs(type, stderr);
  137.     fputs(" specification:  '", stderr);
  138.     fputs(string, stderr);
  139.     fputs("'  ", stderr);
  140.     switch (code) {
  141.         case ERRNTTY:
  142.             fputs("(not connected to a tty)\n", stderr);
  143.             break;
  144.         case ERRSEP:
  145.             fputs("(missing separator between values)\n", stderr);
  146.             break;
  147.         case ERRRNG1:
  148.             fputs("('-' appears twice in range)\n", stderr);
  149.             break;
  150.         case ERRRNG2:
  151.             fputs("('-' does not follow value)\n", stderr);
  152.             break;
  153.         case ERRNUL:
  154.             fputs("(null value)\n", stderr);
  155.             break;
  156.         case ERRMIN:
  157.             fputs("(value below minimum)\n", stderr);
  158.             break;
  159.         case ERRMAX:
  160.             fputs("(value exceeds maximum)\n", stderr);
  161.             break;
  162.         case ERRBAD:
  163.             fputs("(invalid character)\n", stderr);
  164.             break;
  165.         default:
  166.             fputs("(indeterminant error)\n", stderr);
  167.             break;
  168.     }
  169.     exit(0);
  170. }
  171.  
  172. /* Given a string containing usernames, check them against the current
  173.    user's name.  If there is a match, set the global 'user' to TRUE
  174.    otherwise set 'user' to FALSE.  In addition to a direct match, 'user'
  175.    may be set to TRUE by '*'.  Further, '!' may be used to negate its
  176.    meaning.  Return FALSE if no errors, error number otherwise.
  177. */
  178.  
  179. static int userchk(string)
  180. char *string;
  181. {
  182.     register char *cp, *s1;
  183.     register BOOL seen = FALSE;
  184.     register BOOL negate = FALSE;
  185.     struct passwd *passwd;
  186.  
  187.     if (!name) {
  188.         if (!(passwd = getpwuid(geteuid())))
  189.             error("could not access passwd entry", "", 0);
  190.         name = passwd->pw_name;
  191.         namesz = strlen(name);
  192. #ifdef    DEBUG
  193.         fputs("My username is:  ", stderr);
  194.         fputs(name, stderr);
  195.         fputs("\n", stderr);
  196. #endif    DEBUG
  197.     }
  198.     user = FALSE;
  199.     for (cp = string; ; ) switch (*cp) {
  200.         case ' ':    /* whitespace terminates immediately */
  201.         case '\t':
  202.         case '#':
  203.         case '\n':
  204.             return (FALSE);
  205.         case '!':    /* negation requested */
  206.         case '^':
  207.             /* be sure nothing yet specified */
  208.             if (seen) return (ERRSEP);
  209.             negate = !negate;
  210.             ++cp;
  211.             break;
  212.         case '*':    /* every username */
  213.         case '@':
  214.             /* be sure nothing yet specified */
  215.             if (seen) return (ERRSEP);
  216.             seen = TRUE;
  217.             user = !negate;
  218.             ++cp;
  219.             break;
  220.         case '\000':    /* string/specification end */
  221.         case ',':    /* specification end */
  222.             /* be sure value was found */
  223.             if (!seen) return (ERRNUL);
  224.             if (!*cp) return (FALSE);
  225.             seen = FALSE;
  226.             negate = FALSE;
  227.             ++cp;
  228.             break;
  229.         default:    /* user specification found */
  230.             /* be sure nothing yet specified */
  231.             if (seen) return (ERRSEP);
  232.             seen = TRUE;
  233.             s1 = cp;
  234.             /* find the end of the specification */
  235.             while (*cp && !strchr(" \t#\n!^*@,", *cp)) ++cp;
  236.             /* see if it doesn't match by definition */
  237.             if ((cp - s1) != namesz) break;
  238.             /* see if it doesn't match */
  239.             if (strncmp(name, s1, namesz)) break;
  240.             user = !negate;
  241.             break;
  242.     }
  243. }
  244.  
  245. /* Given a string containing the trailing portion of a ttyname, check
  246.    it against the current tty's name.  If it matches, set the global
  247.    'tty' to TRUE.  The first time ttychk() is called within an overall
  248.    specification, 'tty' is set to FALSE.  It may be set to TRUE by '*'
  249.    at any time.  Further, '!' may be used to negate its meaning.  Return
  250.    FALSE if no errors, error number otherwise.
  251. */
  252.  
  253. static int ttychk(string)
  254. char *string;
  255. {
  256.     register char *cp, *s1, *s2;
  257.     register BOOL seen = FALSE;
  258.     register BOOL negate = FALSE;
  259.  
  260.     if (!ttynm) {
  261.         if (!(ttynm = ttyname(0))) return (ERRNTTY);
  262.         ttysz = strlen(ttynm);
  263. #ifdef    DEBUG
  264.         fputs("My ttyname is:  ", stderr);
  265.         fputs(ttynm, stderr);
  266.         fputs("\n", stderr);
  267. #endif    DEBUG
  268.     }
  269.     if (tty == UNSET) tty = FALSE;
  270.     cp = string + 1;            /* skip first byte */
  271.     for (;;) switch (*cp) {
  272.         case ' ':    /* skip whitespace */
  273.         case '\t':
  274.             ++cp;
  275.             break;
  276.         case '!':    /* negation requested */
  277.         case '^':
  278.             /* be sure nothing yet specified */
  279.             if (seen) return (ERRSEP);
  280.             negate = !negate;
  281.             ++cp;
  282.             break;
  283.         case '*':    /* every ttyname */
  284.         case '@':
  285.             /* be sure nothing yet specified */
  286.             if (seen) return (ERRSEP);
  287.             seen = TRUE;
  288.             tty = !negate;
  289.             ++cp;
  290.             break;
  291.         case '\000':    /* string/specification end */
  292.         case ',':    /* specification end */
  293.             /* be sure value was found */
  294.             if (!seen) return (ERRNUL);
  295.             if (!*cp) return (FALSE);
  296.             seen = FALSE;
  297.             negate = FALSE;
  298.             ++cp;
  299.             break;
  300.         case '-':    /* '-' does not follow value */
  301.             return (ERRRNG2);
  302.         default:    /* tty specification found */
  303.             /* be sure nothing yet specified */
  304.             if (seen) return (ERRSEP);
  305.             seen = TRUE;
  306.             s1 = cp;
  307.             /* find the end of the specification */
  308.             while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  309.             s2 = ttynm + ttysz - (cp - s1);
  310.             /* see if it doesn't match by definition */
  311.             if (s2 < ttynm) break;
  312.             /* check for simple non-range specification */
  313.             if (*cp != '-') {
  314.                 /* see if it doesn't match */
  315.                 if (strncmp(s2, s1, cp - s1)) break;
  316.                 tty = !negate;
  317.                 break;
  318.             }
  319.             /* see if < start of range */
  320.             if (strncmp(s2, s1, cp - s1) < 0) {
  321.                 /* it is, skip past range limit */
  322.                 ++cp;
  323.                 while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  324.                 if (*cp == '-') return (ERRRNG1);
  325.                 break;
  326.             }
  327.             /* find the start and end of range limit */
  328.             s1 = ++cp;
  329.             while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
  330.             if (*cp == '-') return (ERRRNG1);
  331.             s2 = ttynm + ttysz - (cp - s1);
  332.             /* see if it doesn't match by definition */
  333.             if (s2 < ttynm) break;
  334.             /* see if > end of range */
  335.             if (strncmp(s2, s1, cp - s1) > 0) break;
  336.             tty = !negate;
  337.             break;
  338.     }
  339. }
  340.  
  341. /* Extract a positive, integer value from the string pointed to by
  342.    'cp' into the int pointed to by 'pnum'.  Return the first non-digit
  343.    position in 'cp'.
  344. */
  345.  
  346. static char *getnum(cp, pnum)
  347. char *cp;
  348. int *pnum;
  349. {
  350.     register int num = 0;
  351.  
  352.     while (isdigit(*cp)) num = num * 10 + (*cp++ - '0');
  353.     *pnum = num;
  354.     return (cp);
  355. }
  356.  
  357. /* Given a string containing numeric values and ranges separated by
  358.    commas - generate a truth vector between 0 and 'max'-1 for those
  359.    values which are specified.  Example:  "2,4,6-10,14".  The first
  360.    time expand() is called for a given vector, all values are set to
  361.    FALSE.  Thereafter, new values are added to the existing vector.
  362.    Note:  any single number or range may be preceeded by '!' to negate
  363.    its meaning (set the specified values to FALSE).  An example might
  364.    be "*,!9-17".  Further note:  the first byte of the specified string
  365.    is ignored.  Return FALSE if no errors, error number otherwise.
  366. */
  367.  
  368. static int expand(string, vector, minimum, maximum)
  369. char *string;
  370. BOOL vector[];
  371. int minimum, maximum;
  372. {
  373.     register char *cp;
  374.     register int i;
  375.     register int range = -1;
  376.     register BOOL negate = FALSE;
  377.     int num = -1;
  378.  
  379.     if (vector[0] == UNSET)
  380.         for (i = 0; i <= maximum; ++i) vector[i] = FALSE;
  381.     cp = string + 1;    /* skip first byte */
  382.     for (;;) switch (*cp) {
  383.         case ' ':    /* skip whitespace */
  384.         case '\t':
  385.             ++cp;
  386.             break;
  387.         case '!':    /* negation requested */
  388.         case '^':
  389.             /* be sure value is new */
  390.             if (num >= 0) return (ERRSEP);
  391.             negate = !negate;
  392.             ++cp;
  393.             break;
  394.         case '*':    /* full range */
  395.         case '@':
  396.             /* be sure value is new */
  397.             if (num >= 0) return (ERRSEP);
  398.             /* check for range started */
  399.             if (range >= 0) {
  400.                 num = maximum;
  401.                 ++cp;
  402.                 break;
  403.             }
  404.             /* no range yet */
  405.             ++cp;
  406.             while (*cp == ' ' || *cp == '\t') ++cp;
  407.             /* check for range continued */
  408.             if (*cp == '-') {
  409.                 num = minimum;
  410.             } else {
  411.                 range = minimum;
  412.                 num = maximum;
  413.             }
  414.             break;
  415.         case '0':    /* value found */
  416.         case '1':
  417.         case '2':
  418.         case '3':
  419.         case '4':
  420.         case '5':
  421.         case '6':
  422.         case '7':
  423.         case '8':
  424.         case '9':
  425.             /* be sure value is new */
  426.             if (num >= 0) return (ERRSEP);
  427.             cp = getnum(cp, &num);
  428.             break;
  429.         case '-':    /* range specified */
  430.             /* be sure range is new */
  431.             if (range >= 0) return (ERRRNG1);
  432.             /* be sure value was found */
  433.             if (num < 0) return (ERRRNG2);
  434.             range = num;    /* save first value */
  435.             num = -1;
  436.             ++cp;
  437.             break;
  438.         case '\000':    /* string/specification end */
  439.         case ',':    /* specification end */
  440.             /* be sure value was found */
  441.             if (num < 0) return (ERRNUL);
  442.             /* range of one if not specified */
  443.             if (range < 0) range = num;
  444.             /* set range as increasing if needed */
  445.             if (range > num) {
  446.                 i = num;
  447.                 num = range;
  448.                 range = i;
  449.             }
  450.             /* check against minimum */
  451.             if (num < minimum) return (ERRMIN);
  452.             /* check against maximum */
  453.             if (range > maximum) return (ERRMAX);
  454.             /* update truth vector */
  455.             for (i = range; i <= num; ++i)
  456.                 vector[i] = !negate;
  457.             negate = FALSE;
  458.             /* specification done */
  459.             num = range = -1;
  460.             if (!*cp) return (FALSE);
  461.             ++cp;
  462.             break;
  463.         default:
  464.             return (ERRBAD);
  465.     }
  466. }
  467.  
  468. #ifdef    DEBUG
  469.  
  470. /* Display the specified string followed by a dump of the specified
  471.    truth vector.
  472. */
  473.  
  474. static void dump(string, vector, minimum, maximum)
  475. char *string;
  476. BOOL vector[];
  477. int minimum, maximum;
  478. {
  479.     register int i;
  480.  
  481.     if (vector[0] == UNSET) return;
  482.     fputs(string, stderr);
  483.     for (i = minimum; i <= maximum; ++i)
  484.         if (vector[i])
  485.             fputc('T', stderr);
  486.         else
  487.             fputc('-', stderr);
  488.     fputc('\n', stderr);
  489. }
  490.  
  491. #endif    DEBUG
  492.  
  493. /* Evaluate a specific series of time specifications relative to the
  494.    current time.  Return TRUE if current time is within them.  Update
  495.    count to reflect the number of specs processed.
  496. */
  497.  
  498. static BOOL within(specs, count)
  499. char **specs;
  500. int *count;
  501. {
  502.     register int i, code;
  503.  
  504.     tty = UNSET;
  505.     for (i = 0; i < 60; ++i) min[i]  = UNSET;
  506.     for (i = 0; i < 24; ++i) hour[i] = UNSET;
  507.     for (i = 0; i < 32; ++i) mday[i] = UNSET;
  508.     for (i = 0; i < 13; ++i) mon[i]  = UNSET;
  509.     for (i = 0; i < 99; ++i) year[i] = UNSET;
  510.     for (i = 0; i <  8; ++i) wday[i] = UNSET;
  511.     *count = 0;
  512.     if (**specs == '-') ++*specs;
  513.     do {
  514. #ifdef    DEBUG
  515.         fputs("processing specification:  ", stderr);
  516.         fputs(*specs, stderr);
  517.         fputc('\n', stderr);
  518. #endif    DEBUG
  519.         switch (**specs) {
  520.             case TTY:
  521.                 if (code = ttychk(*specs))
  522.                     error("tty", *specs, code);
  523.                 break;
  524.             case MIN:
  525.                 if (code = expand(*specs, min, 0, 59))
  526.                     error("minute", *specs, code);
  527.                 break;
  528.             case HOUR:
  529.                 if (code = expand(*specs, hour, 0, 23))
  530.                     error("hour", *specs, code);
  531.                 break;
  532.             case MDAY:
  533.                 if (code = expand(*specs, mday, 1, 31))
  534.                     error("day of month", *specs, code);
  535.                 break;
  536.             case MON:
  537.                 if (code = expand(*specs, mon, 1, 12))
  538.                     error("month", *specs, code);
  539.                 break;
  540.             case YEAR:
  541.                 if (code = expand(*specs, year, 87, 99))
  542.                     error("year", *specs, code);
  543.                 break;
  544.             case WDAY:
  545.                 if (code = expand(*specs, wday, 0, 7))
  546.                     error("day of week", *specs, code);
  547.                 if (wday[0] || wday[7])
  548.                     wday[0] = wday[7] = TRUE;
  549.                 break;
  550.             default:
  551.                 error("invalid specification:  ", *specs, 0);
  552.         }
  553.         ++specs;
  554.         ++*count;
  555.         if (**specs == '-') ++*specs;
  556.     } while (**specs != OR && **specs != PATH);
  557.     if (**specs == OR) {
  558.         if (*(*specs+1) && (*(*specs+1) != 'r' || *(*specs+2)))
  559.             error("invalid specification:  ", *specs, 0);
  560.         ++*count;
  561.     }
  562.  
  563. #ifdef    DEBUG
  564.     fputs("acceptible restrictions are...\n", stderr);
  565.     dump("  minutes:        ", min, 0, 59);
  566.     dump("  hours:          ", hour, 0, 23);
  567.     dump("  days of week:   ", wday, 0, 6);
  568.     dump("  days of month:  ", mday, 1, 31);
  569.     dump("  months:         ", mon, 1, 12);
  570.     dump("  years:          ", year, 87, 99);
  571.     if (tty != UNSET) {
  572.         fputs("(also no restriction on tty '", stderr);
  573.         fputs(ttynm, stderr);
  574.         if (tty) fputs("' - PASSED)\n", stderr);
  575.         else fputs("' - FAILED)\n", stderr);
  576.     }
  577.     fputc('\n', stderr);
  578. #endif    DEBUG
  579.  
  580.     return (tty && min[timenow->tm_min] && hour[timenow->tm_hour] &&
  581.         wday[timenow->tm_wday] && mday[timenow->tm_mday] &&
  582.         mon[timenow->tm_mon] && year[timenow->tm_year]);
  583. }
  584.  
  585. void main(argc, argv, environ)
  586. int argc;
  587. char **argv, *environ[];
  588. {
  589.     register int i;
  590.     register BOOL runable = FALSE;
  591.     register char *cp;
  592.     BOOL testing = **argv != '-';
  593.     int count;
  594.     time_t clock;
  595.     FILE *acfp;
  596.     char buf[MAXENT];
  597.     char *fargv[MAXARGS];
  598.     char shell[MAXSH];
  599.  
  600.     (void) time(&clock);
  601.     timenow = localtime(&clock);
  602.     ++(timenow->tm_mon);
  603.  
  604. #ifdef    DEBUG
  605.     min[timenow->tm_min] = TRUE;
  606.     hour[timenow->tm_hour] = TRUE;
  607.     wday[timenow->tm_wday] = TRUE;
  608.     mday[timenow->tm_mday] = TRUE;
  609.     mon[timenow->tm_mon] = TRUE;
  610.     year[timenow->tm_year] = TRUE;
  611.  
  612.     fputs("time now is...\n", stderr);
  613.     dump("  minute:         ", min, 0, 59);
  614.     dump("  hour:           ", hour, 0, 23);
  615.     dump("  day of week:    ", wday, 0, 6);
  616.     dump("  day of month:   ", mday, 1, 31);
  617.     dump("  month:          ", mon, 1, 12);
  618.     dump("  year:           ", year, 87, 99);
  619.     fputc('\n', stderr);
  620. #endif    DEBUG
  621.  
  622.     if (argc < 2) {
  623.         if (!(acfp = fopen(ACFILE, "r")))
  624.             error("could not open control file:  ", ACFILE, 0);
  625.         /* find this user's entry in the control file */
  626.         while (!user && fgets(buf, MAXENT, acfp))
  627.             if (i = userchk(buf)) {
  628.                 for (cp = buf; *cp && !strchr(" \t#\n", *cp);
  629.                     ++cp) ;
  630.                 *cp = '\000';
  631.                 error("user", buf, i);
  632.             }
  633.         if (!user) error(name, " not in control file", 0);
  634.         /* find the end of the first line */
  635.         for (cp = buf; *cp && !strchr("#\n", *cp); ++cp) ;
  636.         *cp = '\000';
  637.         /* append continuation lines */
  638.         while (count = MAXENT - (cp - buf)) {
  639.             i = fgetc(acfp);
  640.             if (!strchr(" \t#\n", i)) break;
  641.             (void) ungetc(i, acfp);
  642.             if (!fgets(cp, count, acfp)) break;
  643.             while (*cp && !strchr("#\n", *cp)) ++cp;
  644.             *cp = '\000';
  645.         }
  646.         (void) fclose(acfp);
  647. #ifdef    DEBUG
  648.         fputs("control entry:  ", stderr);
  649.         fputs(buf, stderr);
  650.         fputc('\n', stderr);
  651. #endif    DEBUG
  652.         argc = 0;
  653.         argv = fargv;
  654.         argv[argc++] = cp = buf;
  655.         /* process arguments */
  656.         while (*cp) {
  657.             /* scan past last argument */
  658.             while (*cp && *cp != ' ' && *cp != '\t') ++cp;
  659.             /* terminate it with null */
  660.             if (*cp) *cp++ = '\000';
  661.             /* find the next argument */
  662.             while (*cp && (*cp == ' ' || *cp == '\t')) ++cp;
  663.             if (*cp) {
  664.                 /* found one, enter it into argv */
  665.                 if (argc == MAXARGS)
  666.                     error("too many arguments ",
  667.                         "in control file", 0);
  668.                 argv[argc++] = cp;
  669.             }
  670.         }
  671.         argv[argc] = NULL;
  672. #ifdef    DEBUG
  673.         for (i = 1; i < argc; ++i) {
  674.             fputs("found specification:  ", stderr);
  675.             fputs(argv[i], stderr);
  676.             fputs("\n", stderr);
  677.         }
  678.         fputs("\n", stderr);
  679. #endif    DEBUG
  680.     }
  681.  
  682.     for (i = 1; i < argc; ++i) if (*argv[i] == PATH) break;
  683.     if (i == argc)
  684.         error("full pathname to exec() required", "", 0);
  685.  
  686.     if (**(++argv) == PATH) runable = TRUE;
  687.     else do {
  688.         runable |= within(argv, &count);
  689.         argv += count;
  690.     } while (**argv != PATH);
  691.  
  692.     if (runable) {
  693. #ifdef    DEBUG
  694.         fputs("\ntime and tty IS within specifications\n", stderr);
  695. #endif    DEBUG
  696.         /* set the shell buffer to be "SHELL=pathname" */
  697.         (void) strcpy(shell, "SHELL=");
  698.         (void) strcat(shell, *argv);
  699.         /* fix argv[0] to point to '-progname' */
  700.         if (cp = strrchr(*argv, '/')) {
  701.             *cp = '-';
  702.             (void) strcpy(*argv, cp);
  703.         }
  704.         /* set cp to point to the pathname to execute */
  705.         cp = shell + 6;
  706.         /* find and fix the SHELL environment variable */
  707.         for (i = 0; environ[i]; ++i) {
  708.             if (!strncmp(environ[i], "SHELL=", 6)) {
  709.                 environ[i] = shell;
  710.                 break;
  711.             }
  712.         }
  713.         if (testing) {
  714.             fputs(cp, stderr);
  715.             fputs(": ", stderr);
  716.             for (i = 0; argv[i]; ++i) {
  717.                 fputs(" \"", stderr);
  718.                 fputs(argv[i], stderr);
  719.                 fputc('"', stderr);
  720.             }
  721.             fputc('\n', stderr);
  722.             exit(0);
  723.         }
  724.         (void) execve(cp, argv, environ);
  725.         error("could not exec() ", cp, 0);
  726.     } else {
  727. #ifdef    DEBUG
  728.         fputs("\ntime or tty is NOT within specifications\n", stderr);
  729. #endif    DEBUG
  730.         fputs("\n*** your access ", stderr);
  731.         if (ttynm) fputs("(on this tty port) ", stderr);
  732.         fputs("is not permitted at this time ***\n", stderr);
  733.     }
  734. }
  735.