home *** CD-ROM | disk | FTP | other *** search
- /*
- * securelib: a package to enhance network security.
- *
- * Written by William LeFebvre, EECS Department, Northwestern University
- * Internet address: phil@eecs.nwu.edu
- *
- * Configuration file code added by Sam Horrocks (sam@ics.uci.edu).
- */
-
- /* Edit these def's to customize for your site. */
-
- #ifndef CONF_FILE
- #define CONF_FILE "/etc/securelib.conf" /* Name of the config file *
- * (may be overridden by cc) */
- #endif
-
- #define MAX_LINES 8 /* Maximum number of config lines *
- * that can apply to one process */
-
- #define ENV_NAME "SL_NAME" /* Name of the environment variable *
- * to use to filter the config file. */
-
- #define ALL_NAME "all" /* Name used in config file for *
- * lines that apply to all processes */
-
- #define STAT_TIMEOUT (60*60) /* Time to wait before stat'ing *
- * the config file again. */
-
- #define MAX_TOKEN 40 /* Maximum size of one token in the *
- * configuration file */
-
- #define BUF_SIZE 80 /* Size of buffer used to read file. */
-
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <ctype.h>
-
- struct conf_line { /* Info about config file line */
- u_long adr, mask
- };
-
- static int next_token();
- extern char *getenv();
- extern time_t time();
- extern u_long inet_addr();
-
-
- /*
- * _ok_address - check the sockaddr "addr" (of length "addrlen") to see
- * if it corresponds to an acceptable host. Return true
- * (non-zero) if acceptable, otherwise return false (zero).
- * If "addr" is NULL or if "addrlen" is not long enough,
- * then use "getpeername" on socket "s" to determine the
- * address of the connecting host.
- */
-
- _ok_address(s, addr, addrlen)
-
- int s;
- struct sockaddr *addr;
- int addrlen;
-
- {
- struct sockaddr peername; /* in case we need to use getpeername */
- int peernamelen; /* ditto */
- u_long ip_addr;
-
- /* was addr actually used and was it sufficient? */
- if (addr == (struct sockaddr *)0 || addrlen < (2+2+sizeof(struct in_addr)))
- {
- /* no, so get the info with getpeername */
- peernamelen = sizeof(peername);
- if (getpeername(s, &peername, &peernamelen) < 0)
- {
- /* not sure what the appropriate thing to do here is... */
- /* so we will return "not ok" just to be safe */
- return(0);
- }
-
- /* for remainder of this function: */
- addr = &peername;
- }
-
- /* now, verify the socket type */
- if (addr->sa_family == AF_INET)
- {
- static struct conf_line conf[MAX_LINES];
- static int nconf;
- static time_t last_stat_time, last_mtime;
- struct timeval now;
- int i;
-
- (void) gettimeofday(&now, (struct timezone*)0);
-
- /* Decide whether to read our config file */
- if (last_stat_time == 0 ||
- (now.tv_sec - last_stat_time) > STAT_TIMEOUT)
- {
- struct stat stbuf;
- char *conf_file = CONF_FILE;
- char *my_name = getenv(ENV_NAME);
- char fil_buf[BUF_SIZE], buf[MAX_TOKEN];
- FILE fil;
-
- last_stat_time = now.tv_sec;
- bzero((char*)&fil, sizeof(fil));
-
- /* Stat the config file. If it changed, open it */
- if (stat(conf_file, &stbuf) != -1 &&
- last_mtime != stbuf.st_mtime &&
- freopen(conf_file, "r", &fil) == &fil)
- {
- /* Update the timestamp */
- last_mtime = stbuf.st_mtime;
- nconf = 0;
-
- /* Use the buffer on the stack instead of malloc'ing */
- setbuffer(&fil, fil_buf, sizeof(fil_buf));
-
- /* Grab the "name" */
- while ((i = next_token(&fil, buf, sizeof(buf))) != EOF)
- {
- /* If only token on the line, ignore */
- if (i == '\n') continue;
-
- /* Comment -- read until end of line then next line */
- if (buf[0] == '#') {
- while (next_token(&fil, buf, sizeof(buf)) == 0) ;
- continue;
- }
-
- /*
- * Check to make sure this says "all" or that it matches
- * the name given in the environment variable.
- */
- if (strcmp(buf, ALL_NAME) == 0 ||
- (my_name != NULL && strcmp(buf, my_name) == 0))
- {
- /* Get next token, if last on line, ignore */
- if (next_token(&fil, buf, sizeof(buf)) != 0)
- continue;
-
- /* Got address */
- conf[nconf].adr = inet_addr(buf);
-
- /* Get next token (mask) */
- i = next_token(&fil, buf, sizeof(buf));
-
- /* Only ignore if we got no text at all */
- if (i != EOF)
- {
- /* Add to list, quit if array is full */
- conf[nconf++].mask = inet_addr(buf);
- if (nconf == MAX_LINES) break;
- }
-
- /* If not at end-of-line, keep reading til we are */
- /* why isn't this outside the if(strcmp...) ??? */
- while (i == 0)
- {
- i = next_token(&fil, buf, sizeof(buf));
- }
- }
- }
- (void) fclose(&fil);
- }
- }
-
- /* Config lines now in memory so start checking address */
- /* grab just the address */
- ip_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
-
- /*
- * Go through the conf array, turn off the bits given by the mask
- * and then compare the result with the address. A match means
- * that this address is ok.
- */
- for (i = 0; i < nconf; ++i)
- {
- if ((ip_addr & ~conf[i].mask) == conf[i].adr) return 1;
- }
-
- /* no match, so we can't approve the address */
- return 0;
- }
- else
- {
- /* we don't know how to handle non-Internet connections, so
- we will give them all blanket approval */
- return 1;
- }
- /*NOTREACHED*/
- }
-
- /*
- * Grab one token out of fp. Defined as the next string of non-whitespace
- * in the file. After we get the token, continue reading until EOF, end of
- * line or the next token. If it's the last token on the line, return '\n'
- * for the value. If we get EOF before reading a token, return EOF. In all
- * other cases return 0.
- */
- static int next_token(fp, buf, bufsz)
-
- FILE *fp;
- char *buf;
- int bufsz;
-
- {
- int c;
- char *eb = buf+(bufsz-1);
-
- /* Discard inital whitespace */
- while (isspace(c = getc(fp))) ;
-
- /* EOF seen before any token so return EOF */
- if (c == EOF) return -1;
-
- /* Form a token in buf */
- do {
- if (buf < eb) *buf++ = c;
- c = getc(fp);
- } while (!isspace(c) && c != EOF);
- *buf = '\0';
-
- /* Discard trailing tabs and spaces */
- while (c == ' ' || c == '\t') c = getc(fp);
-
- /* Put back the char that was non-whitespace (putting back EOF is ok) */
- (void) ungetc(c, fp);
-
- /* If we ended with a newline, return that, otherwise return 0 */
- return (c == '\n' ? '\n' : 0);
- }
-
- /*
- * _addrcpy(to, tolenptr, from, fromlen)
- *
- * copy an address from "from" to "to". "fromlen" is the length of the
- * from address. "tolenptr" points to the length that is available in
- * the buffer "to" and will be modified the reflect the actual number of
- * bytes copied. Under no circumstances will more than *tolenptr bytes
- * be copied (even if *tolenptr == 0).
- *
- * This is a global routine and is used in the modified accept call.
- */
-
- _addrcpy(to, tolenp, from, fromlen)
-
- struct sockaddr *to, *from;
- int *tolenp;
- int fromlen;
-
- {
- register int amt = 0;
-
- /*
- * Explanation: amt is initialized to 0. If to is null, then the
- * second half of the && conditional is not done (K&R guarantees
- * this). Therefore, amt gets set to *tolenp iff amt != NULL.
- * Then, if *tolenp is greater than 0, the lesser of amt (*tolenp)
- * and fromlen is used as the length of the copy. Thus, amt is always
- * the number of bytes copied, even if that number is 0 (indicating
- * that no copying was done).
- */
-
- if (to != (struct sockaddr *)0 && (amt = *tolenp) > 0)
- {
- if (fromlen < amt)
- {
- amt = fromlen;
- }
- bcopy((char *)from, (char *)to, amt);
- }
- *tolenp = amt;
- }
-