home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1988 by George M. Sipe. All rights reserved.
-
- This software may only be redistributed without fee and without any
- other form of monetary gain (including sold, rented, leased, or
- traded), unless the express written permission of the copyright holder
- is obtained in advance.
-
- This copyright notice must be reproduced in its entirety on all copies
- of this software. Further, acknowledgment of the authorship of this
- software must not be removed from its current or derived
- documentation.
-
- No expressed or implied warranty is made for this software. No party
- connected with this software assumes any liability or responsibility
- for its use, the correctness of its operation, or its fitness for any
- purpose.
-
- Any distributor of copies of this software shall grant the recipient
- permission for further redistribution as permitted by this notice.
-
- Permission is hereby granted to copy, reproduce, redistribute and
- otherwise use this software as long as the conditions above are
- strictly adhered to. */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <pwd.h>
- #include <sys/types.h>
- #ifndef BSD
- #include <time.h>
- #define MAXPATHLEN 1024
- void exit();
- char *strchr();
- char *strrchr();
- long time();
- #else
- #include <sys/time.h>
- #include <sys/param.h>
- #undef MIN
- #define strchr(s,c) index(s,c)
- #define strrchr(s,c) rindex(s,c)
- exit();
- char *index();
- char *rindex();
- time_t time();
- #endif
-
- int execve();
- int fclose();
- int fgetc();
- char *fgets();
- FILE *fopen();
- int fputc();
- int fputs();
- int geteuid();
- struct passwd *getpwuid();
- struct tm *localtime();
- char *strcat();
- char *strcpy();
- int strlen();
- int strncmp();
- char *ttyname();
- int ungetc();
-
- /* #define DEBUG /* define for tracing information */
-
- #ifndef TRUE
- #define TRUE 1 /* true and false */
- #define FALSE 0
- #endif
- #define UNSET 3 /* unset flag */
-
- #ifndef DEBUG
- #define ACFILE "/usr/local/lib/access"
- #else
- #define ACFILE "test"
- #endif DEBUG
- #define MAXENT 1024 /* maximum entry length */
- #define MAXARGS 99 /* maximum number of arguments in file */
- #define MAXSH MAXPATHLEN+7 /* maximum size of SHELL environment variable */
-
- #define TTY 't' /* ttyname restrictor */
- #define MIN 'm' /* minute restrictor */
- #define HOUR 'h' /* hour restrictor */
- #define WDAY 'w' /* day of week restrictor */
- #define MDAY 'D' /* day of month restrictor */
- #define MON 'M' /* month restrictor */
- #define YEAR 'Y' /* year restrictor */
- #define OR 'o' /* logical or separator */
- #define PATH '/' /* pathname prefix */
-
- #define ERRNTTY 101 /* not connected to a tty */
- #define ERRSEP 102 /* missing separator between values */
- #define ERRRNG1 103 /* '-' appears twice in range */
- #define ERRRNG2 104 /* '-' does not follow value */
- #define ERRNUL 105 /* null value */
- #define ERRMIN 106 /* value below minimum */
- #define ERRMAX 107 /* value exceeds maximum */
- #define ERRBAD 108 /* invalid character */
-
- typedef char BOOL;
-
- static struct tm *timenow; /* the current local time */
- static char *name = NULL; /* pointer to username */
- static int namesz; /* size of username */
- static char *ttynm = NULL; /* pointer to ttyname */
- static int ttysz; /* size of ttyname */
-
- static BOOL user; /* TRUE or FALSE */
- static BOOL tty; /* UNSET, TRUE, or FALSE */
- static BOOL min[60]; /* 0 to 59 */
- static BOOL hour[24]; /* 0 to 23 */
- static BOOL wday[8]; /* 0 (Sunday) to 6 (Saturday); 7 = 0 too */
- static BOOL mday[32]; /* 1 to 31 */
- static BOOL mon[13]; /* 1 to 12 */
- static BOOL year[99]; /* 87 to 99 */
-
- /* Display userchk(), ttychk(), and expand() error message. */
-
- static void error(type, string, code)
- char *type;
- char *string;
- int code;
- {
- fputs("\n*** system access processing failure - ", stderr);
- fputs("report to your system manager ***\n\n", stderr);
-
- if (code == 0) {
- fputs(type, stderr);
- fputs(string, stderr);
- fputc('\n', stderr);
- exit(0);
- }
-
- fputs("invalid ", stderr);
- fputs(type, stderr);
- fputs(" specification: '", stderr);
- fputs(string, stderr);
- fputs("' ", stderr);
- switch (code) {
- case ERRNTTY:
- fputs("(not connected to a tty)\n", stderr);
- break;
- case ERRSEP:
- fputs("(missing separator between values)\n", stderr);
- break;
- case ERRRNG1:
- fputs("('-' appears twice in range)\n", stderr);
- break;
- case ERRRNG2:
- fputs("('-' does not follow value)\n", stderr);
- break;
- case ERRNUL:
- fputs("(null value)\n", stderr);
- break;
- case ERRMIN:
- fputs("(value below minimum)\n", stderr);
- break;
- case ERRMAX:
- fputs("(value exceeds maximum)\n", stderr);
- break;
- case ERRBAD:
- fputs("(invalid character)\n", stderr);
- break;
- default:
- fputs("(indeterminant error)\n", stderr);
- break;
- }
- exit(0);
- }
-
- /* Given a string containing usernames, check them against the current
- user's name. If there is a match, set the global 'user' to TRUE
- otherwise set 'user' to FALSE. In addition to a direct match, 'user'
- may be set to TRUE by '*'. Further, '!' may be used to negate its
- meaning. Return FALSE if no errors, error number otherwise.
- */
-
- static int userchk(string)
- char *string;
- {
- register char *cp, *s1;
- register BOOL seen = FALSE;
- register BOOL negate = FALSE;
- struct passwd *passwd;
-
- if (!name) {
- if (!(passwd = getpwuid(geteuid())))
- error("could not access passwd entry", "", 0);
- name = passwd->pw_name;
- namesz = strlen(name);
- #ifdef DEBUG
- fputs("My username is: ", stderr);
- fputs(name, stderr);
- fputs("\n", stderr);
- #endif DEBUG
- }
- user = FALSE;
- for (cp = string; ; ) switch (*cp) {
- case ' ': /* whitespace terminates immediately */
- case '\t':
- case '#':
- case '\n':
- return (FALSE);
- case '!': /* negation requested */
- case '^':
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- negate = !negate;
- ++cp;
- break;
- case '*': /* every username */
- case '@':
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- seen = TRUE;
- user = !negate;
- ++cp;
- break;
- case '\000': /* string/specification end */
- case ',': /* specification end */
- /* be sure value was found */
- if (!seen) return (ERRNUL);
- if (!*cp) return (FALSE);
- seen = FALSE;
- negate = FALSE;
- ++cp;
- break;
- default: /* user specification found */
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- seen = TRUE;
- s1 = cp;
- /* find the end of the specification */
- while (*cp && !strchr(" \t#\n!^*@,", *cp)) ++cp;
- /* see if it doesn't match by definition */
- if ((cp - s1) != namesz) break;
- /* see if it doesn't match */
- if (strncmp(name, s1, namesz)) break;
- user = !negate;
- break;
- }
- }
-
- /* Given a string containing the trailing portion of a ttyname, check
- it against the current tty's name. If it matches, set the global
- 'tty' to TRUE. The first time ttychk() is called within an overall
- specification, 'tty' is set to FALSE. It may be set to TRUE by '*'
- at any time. Further, '!' may be used to negate its meaning. Return
- FALSE if no errors, error number otherwise.
- */
-
- static int ttychk(string)
- char *string;
- {
- register char *cp, *s1, *s2;
- register BOOL seen = FALSE;
- register BOOL negate = FALSE;
-
- if (!ttynm) {
- if (!(ttynm = ttyname(0))) return (ERRNTTY);
- ttysz = strlen(ttynm);
- #ifdef DEBUG
- fputs("My ttyname is: ", stderr);
- fputs(ttynm, stderr);
- fputs("\n", stderr);
- #endif DEBUG
- }
- if (tty == UNSET) tty = FALSE;
- cp = string + 1; /* skip first byte */
- for (;;) switch (*cp) {
- case ' ': /* skip whitespace */
- case '\t':
- ++cp;
- break;
- case '!': /* negation requested */
- case '^':
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- negate = !negate;
- ++cp;
- break;
- case '*': /* every ttyname */
- case '@':
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- seen = TRUE;
- tty = !negate;
- ++cp;
- break;
- case '\000': /* string/specification end */
- case ',': /* specification end */
- /* be sure value was found */
- if (!seen) return (ERRNUL);
- if (!*cp) return (FALSE);
- seen = FALSE;
- negate = FALSE;
- ++cp;
- break;
- case '-': /* '-' does not follow value */
- return (ERRRNG2);
- default: /* tty specification found */
- /* be sure nothing yet specified */
- if (seen) return (ERRSEP);
- seen = TRUE;
- s1 = cp;
- /* find the end of the specification */
- while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- s2 = ttynm + ttysz - (cp - s1);
- /* see if it doesn't match by definition */
- if (s2 < ttynm) break;
- /* check for simple non-range specification */
- if (*cp != '-') {
- /* see if it doesn't match */
- if (strncmp(s2, s1, cp - s1)) break;
- tty = !negate;
- break;
- }
- /* see if < start of range */
- if (strncmp(s2, s1, cp - s1) < 0) {
- /* it is, skip past range limit */
- ++cp;
- while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- if (*cp == '-') return (ERRRNG1);
- break;
- }
- /* find the start and end of range limit */
- s1 = ++cp;
- while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- if (*cp == '-') return (ERRRNG1);
- s2 = ttynm + ttysz - (cp - s1);
- /* see if it doesn't match by definition */
- if (s2 < ttynm) break;
- /* see if > end of range */
- if (strncmp(s2, s1, cp - s1) > 0) break;
- tty = !negate;
- break;
- }
- }
-
- /* Extract a positive, integer value from the string pointed to by
- 'cp' into the int pointed to by 'pnum'. Return the first non-digit
- position in 'cp'.
- */
-
- static char *getnum(cp, pnum)
- char *cp;
- int *pnum;
- {
- register int num = 0;
-
- while (isdigit(*cp)) num = num * 10 + (*cp++ - '0');
- *pnum = num;
- return (cp);
- }
-
- /* Given a string containing numeric values and ranges separated by
- commas - generate a truth vector between 0 and 'max'-1 for those
- values which are specified. Example: "2,4,6-10,14". The first
- time expand() is called for a given vector, all values are set to
- FALSE. Thereafter, new values are added to the existing vector.
- Note: any single number or range may be preceeded by '!' to negate
- its meaning (set the specified values to FALSE). An example might
- be "*,!9-17". Further note: the first byte of the specified string
- is ignored. Return FALSE if no errors, error number otherwise.
- */
-
- static int expand(string, vector, minimum, maximum)
- char *string;
- BOOL vector[];
- int minimum, maximum;
- {
- register char *cp;
- register int i;
- register int range = -1;
- register BOOL negate = FALSE;
- int num = -1;
-
- if (vector[0] == UNSET)
- for (i = 0; i <= maximum; ++i) vector[i] = FALSE;
- cp = string + 1; /* skip first byte */
- for (;;) switch (*cp) {
- case ' ': /* skip whitespace */
- case '\t':
- ++cp;
- break;
- case '!': /* negation requested */
- case '^':
- /* be sure value is new */
- if (num >= 0) return (ERRSEP);
- negate = !negate;
- ++cp;
- break;
- case '*': /* full range */
- case '@':
- /* be sure value is new */
- if (num >= 0) return (ERRSEP);
- /* check for range started */
- if (range >= 0) {
- num = maximum;
- ++cp;
- break;
- }
- /* no range yet */
- ++cp;
- while (*cp == ' ' || *cp == '\t') ++cp;
- /* check for range continued */
- if (*cp == '-') {
- num = minimum;
- } else {
- range = minimum;
- num = maximum;
- }
- break;
- case '0': /* value found */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- /* be sure value is new */
- if (num >= 0) return (ERRSEP);
- cp = getnum(cp, &num);
- break;
- case '-': /* range specified */
- /* be sure range is new */
- if (range >= 0) return (ERRRNG1);
- /* be sure value was found */
- if (num < 0) return (ERRRNG2);
- range = num; /* save first value */
- num = -1;
- ++cp;
- break;
- case '\000': /* string/specification end */
- case ',': /* specification end */
- /* be sure value was found */
- if (num < 0) return (ERRNUL);
- /* range of one if not specified */
- if (range < 0) range = num;
- /* set range as increasing if needed */
- if (range > num) {
- i = num;
- num = range;
- range = i;
- }
- /* check against minimum */
- if (num < minimum) return (ERRMIN);
- /* check against maximum */
- if (range > maximum) return (ERRMAX);
- /* update truth vector */
- for (i = range; i <= num; ++i)
- vector[i] = !negate;
- negate = FALSE;
- /* specification done */
- num = range = -1;
- if (!*cp) return (FALSE);
- ++cp;
- break;
- default:
- return (ERRBAD);
- }
- }
-
- #ifdef DEBUG
-
- /* Display the specified string followed by a dump of the specified
- truth vector.
- */
-
- static void dump(string, vector, minimum, maximum)
- char *string;
- BOOL vector[];
- int minimum, maximum;
- {
- register int i;
-
- if (vector[0] == UNSET) return;
- fputs(string, stderr);
- for (i = minimum; i <= maximum; ++i)
- if (vector[i])
- fputc('T', stderr);
- else
- fputc('-', stderr);
- fputc('\n', stderr);
- }
-
- #endif DEBUG
-
- /* Evaluate a specific series of time specifications relative to the
- current time. Return TRUE if current time is within them. Update
- count to reflect the number of specs processed.
- */
-
- static BOOL within(specs, count)
- char **specs;
- int *count;
- {
- register int i, code;
-
- tty = UNSET;
- for (i = 0; i < 60; ++i) min[i] = UNSET;
- for (i = 0; i < 24; ++i) hour[i] = UNSET;
- for (i = 0; i < 32; ++i) mday[i] = UNSET;
- for (i = 0; i < 13; ++i) mon[i] = UNSET;
- for (i = 0; i < 99; ++i) year[i] = UNSET;
- for (i = 0; i < 8; ++i) wday[i] = UNSET;
- *count = 0;
- if (**specs == '-') ++*specs;
- do {
- #ifdef DEBUG
- fputs("processing specification: ", stderr);
- fputs(*specs, stderr);
- fputc('\n', stderr);
- #endif DEBUG
- switch (**specs) {
- case TTY:
- if (code = ttychk(*specs))
- error("tty", *specs, code);
- break;
- case MIN:
- if (code = expand(*specs, min, 0, 59))
- error("minute", *specs, code);
- break;
- case HOUR:
- if (code = expand(*specs, hour, 0, 23))
- error("hour", *specs, code);
- break;
- case MDAY:
- if (code = expand(*specs, mday, 1, 31))
- error("day of month", *specs, code);
- break;
- case MON:
- if (code = expand(*specs, mon, 1, 12))
- error("month", *specs, code);
- break;
- case YEAR:
- if (code = expand(*specs, year, 87, 99))
- error("year", *specs, code);
- break;
- case WDAY:
- if (code = expand(*specs, wday, 0, 7))
- error("day of week", *specs, code);
- if (wday[0] || wday[7])
- wday[0] = wday[7] = TRUE;
- break;
- default:
- error("invalid specification: ", *specs, 0);
- }
- ++specs;
- ++*count;
- if (**specs == '-') ++*specs;
- } while (**specs != OR && **specs != PATH);
- if (**specs == OR) {
- if (*(*specs+1) && (*(*specs+1) != 'r' || *(*specs+2)))
- error("invalid specification: ", *specs, 0);
- ++*count;
- }
-
- #ifdef DEBUG
- fputs("acceptible restrictions are...\n", stderr);
- dump(" minutes: ", min, 0, 59);
- dump(" hours: ", hour, 0, 23);
- dump(" days of week: ", wday, 0, 6);
- dump(" days of month: ", mday, 1, 31);
- dump(" months: ", mon, 1, 12);
- dump(" years: ", year, 87, 99);
- if (tty != UNSET) {
- fputs("(also no restriction on tty '", stderr);
- fputs(ttynm, stderr);
- if (tty) fputs("' - PASSED)\n", stderr);
- else fputs("' - FAILED)\n", stderr);
- }
- fputc('\n', stderr);
- #endif DEBUG
-
- return (tty && min[timenow->tm_min] && hour[timenow->tm_hour] &&
- wday[timenow->tm_wday] && mday[timenow->tm_mday] &&
- mon[timenow->tm_mon] && year[timenow->tm_year]);
- }
-
- void main(argc, argv, environ)
- int argc;
- char **argv, *environ[];
- {
- register int i;
- register BOOL runable = FALSE;
- register char *cp;
- BOOL testing = **argv != '-';
- int count;
- time_t clock;
- FILE *acfp;
- char buf[MAXENT];
- char *fargv[MAXARGS];
- char shell[MAXSH];
-
- (void) time(&clock);
- timenow = localtime(&clock);
- ++(timenow->tm_mon);
-
- #ifdef DEBUG
- min[timenow->tm_min] = TRUE;
- hour[timenow->tm_hour] = TRUE;
- wday[timenow->tm_wday] = TRUE;
- mday[timenow->tm_mday] = TRUE;
- mon[timenow->tm_mon] = TRUE;
- year[timenow->tm_year] = TRUE;
-
- fputs("time now is...\n", stderr);
- dump(" minute: ", min, 0, 59);
- dump(" hour: ", hour, 0, 23);
- dump(" day of week: ", wday, 0, 6);
- dump(" day of month: ", mday, 1, 31);
- dump(" month: ", mon, 1, 12);
- dump(" year: ", year, 87, 99);
- fputc('\n', stderr);
- #endif DEBUG
-
- if (argc < 2) {
- if (!(acfp = fopen(ACFILE, "r")))
- error("could not open control file: ", ACFILE, 0);
- /* find this user's entry in the control file */
- while (!user && fgets(buf, MAXENT, acfp))
- if (i = userchk(buf)) {
- for (cp = buf; *cp && !strchr(" \t#\n", *cp);
- ++cp) ;
- *cp = '\000';
- error("user", buf, i);
- }
- if (!user) error(name, " not in control file", 0);
- /* find the end of the first line */
- for (cp = buf; *cp && !strchr("#\n", *cp); ++cp) ;
- *cp = '\000';
- /* append continuation lines */
- while (count = MAXENT - (cp - buf)) {
- i = fgetc(acfp);
- if (!strchr(" \t#\n", i)) break;
- (void) ungetc(i, acfp);
- if (!fgets(cp, count, acfp)) break;
- while (*cp && !strchr("#\n", *cp)) ++cp;
- *cp = '\000';
- }
- (void) fclose(acfp);
- #ifdef DEBUG
- fputs("control entry: ", stderr);
- fputs(buf, stderr);
- fputc('\n', stderr);
- #endif DEBUG
- argc = 0;
- argv = fargv;
- argv[argc++] = cp = buf;
- /* process arguments */
- while (*cp) {
- /* scan past last argument */
- while (*cp && *cp != ' ' && *cp != '\t') ++cp;
- /* terminate it with null */
- if (*cp) *cp++ = '\000';
- /* find the next argument */
- while (*cp && (*cp == ' ' || *cp == '\t')) ++cp;
- if (*cp) {
- /* found one, enter it into argv */
- if (argc == MAXARGS)
- error("too many arguments ",
- "in control file", 0);
- argv[argc++] = cp;
- }
- }
- argv[argc] = NULL;
- #ifdef DEBUG
- for (i = 1; i < argc; ++i) {
- fputs("found specification: ", stderr);
- fputs(argv[i], stderr);
- fputs("\n", stderr);
- }
- fputs("\n", stderr);
- #endif DEBUG
- }
-
- for (i = 1; i < argc; ++i) if (*argv[i] == PATH) break;
- if (i == argc)
- error("full pathname to exec() required", "", 0);
-
- if (**(++argv) == PATH) runable = TRUE;
- else do {
- runable |= within(argv, &count);
- argv += count;
- } while (**argv != PATH);
-
- if (runable) {
- #ifdef DEBUG
- fputs("\ntime and tty IS within specifications\n", stderr);
- #endif DEBUG
- /* set the shell buffer to be "SHELL=pathname" */
- (void) strcpy(shell, "SHELL=");
- (void) strcat(shell, *argv);
- /* fix argv[0] to point to '-progname' */
- if (cp = strrchr(*argv, '/')) {
- *cp = '-';
- (void) strcpy(*argv, cp);
- }
- /* set cp to point to the pathname to execute */
- cp = shell + 6;
- /* find and fix the SHELL environment variable */
- for (i = 0; environ[i]; ++i) {
- if (!strncmp(environ[i], "SHELL=", 6)) {
- environ[i] = shell;
- break;
- }
- }
- if (testing) {
- fputs(cp, stderr);
- fputs(": ", stderr);
- for (i = 0; argv[i]; ++i) {
- fputs(" \"", stderr);
- fputs(argv[i], stderr);
- fputc('"', stderr);
- }
- fputc('\n', stderr);
- exit(0);
- }
- (void) execve(cp, argv, environ);
- error("could not exec() ", cp, 0);
- } else {
- #ifdef DEBUG
- fputs("\ntime or tty is NOT within specifications\n", stderr);
- #endif DEBUG
- fputs("\n*** your access ", stderr);
- if (ttynm) fputs("(on this tty port) ", stderr);
- fputs("is not permitted at this time ***\n", stderr);
- }
- }
-