home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume20 / log_tcp / part01 / hosts_access.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-22  |  4.9 KB  |  164 lines

  1. #ifdef HOSTS_ACCESS
  2.  
  3.  /*
  4.   * This module implements a simple but effective form of access control
  5.   * based on host (or domain) names, netgroup, internet addresses (or network
  6.   * numbers) and daemon process names, with wild card support.
  7.   * 
  8.   * Diagnostics are reported through syslog(3).
  9.   * 
  10.   * Compile with -DHOSTS_ACCESS in order to enable access control. See the
  11.   * hosts_access(5) manual page for details.
  12.   * 
  13.   * Compile with -DNETGROUP if your library provides support for netgroups.
  14.   * 
  15.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  16.   */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#) hosts_access.c 1.5 91/05/20 13:28:03";
  20. #endif
  21.  
  22. #include <stdio.h>
  23. #include <syslog.h>
  24. #include <ctype.h>
  25.  
  26. extern char *fgets();
  27. extern char *strchr();
  28. extern char *strtok();
  29. extern void exit();
  30.  
  31.  /* Path names of the access control files. */
  32.  
  33. #define HOSTS_ALLOW    "/etc/hosts.allow"
  34. #define HOSTS_DENY    "/etc/hosts.deny"
  35.  
  36.  /* Delimiters for lists of daemons or clients. */
  37.  
  38. static char sep[] = ", \t";
  39.  
  40.  /* Constants to be used in assignments only, not in comparisons... */
  41.  
  42. #define    YES        1
  43. #define    NO        0
  44.  
  45. /* hosts_access - host access control facility */
  46.  
  47. hosts_access(daemon, client)
  48. char   *daemon;
  49. char   *client;
  50. {
  51.  
  52.     /*
  53.      * If the (daemon, client) pair is matched by an entry in the file
  54.      * /etc/hosts.allow, access is granted. Otherwise, if the (daemon,
  55.      * client) pair is matched by an entry in /etc/hosts.deny, access is
  56.      * denied. Otherwise, access is granted.
  57.      * 
  58.      * If a connection is refused, we write a syslog record, but do not notify
  59.      * the client.
  60.      */
  61.  
  62.     if (table_match(HOSTS_ALLOW, daemon, client))
  63.     return;
  64.     if (table_match(HOSTS_DENY, daemon, client)) {
  65.     syslog(LOG_WARNING, "refused connect from %s", client);
  66.     exit(0);
  67.     }
  68. }
  69.  
  70. /* table_match - match table entries with (daemon, client) pair */
  71.  
  72. int     table_match(table, daemon, client)
  73. char   *table;
  74. char   *daemon;
  75. char   *client;
  76. {
  77.     FILE   *fp;
  78.     char    sv_list[BUFSIZ];        /* becomes list of daemons */
  79.     char   *cl_list;            /* becomes list of clients */
  80.     int     match = NO;
  81.     int     end;
  82.  
  83.     /*
  84.      * Process the table one line at a time. Lines that begin with a '#'
  85.      * character are ignored. Non-comment lines are broken at the ':'
  86.      * character (we complain if there is none). The left part is matched
  87.      * against the daemon process name (argv[0]), the right part against the
  88.      * host name. A non-existing table is treated as if it were an empty
  89.      * table.
  90.      */
  91.  
  92.     if (fp = fopen(table, "r")) {
  93.     while (!match && fgets(sv_list, sizeof(sv_list), fp)) {
  94.         if (sv_list[end = strlen(sv_list) - 1] != '\n') {
  95.         syslog(LOG_ERR, "%s: line exceeds STDIO buffer size", table);
  96.         } else {
  97.         sv_list[end] = '\0';        /* strip trailing newline */
  98.         }
  99.         if (sv_list[0] == '#') {        /* skip comments */
  100.         continue;
  101.         } else if ((cl_list = strchr(sv_list, ':')) == 0) {
  102.         syslog(LOG_ERR, "%s: malformed entry: \"%s\"", table, sv_list);
  103.         continue;
  104.         } else {
  105.         *cl_list++ = '\0';        /* break line at ":" */
  106.         match = (list_match(sv_list, daemon)
  107.              && list_match(cl_list, client));
  108.         }
  109.     }
  110.     (void) fclose(fp);
  111.     }
  112.     return (match);
  113. }
  114.  
  115. /* list_match - match a string against a list of tokens */
  116.  
  117. int     list_match(list, string)
  118. char   *list;
  119. char   *string;
  120. {
  121.     char   *tok;
  122.     int     tok_len;
  123.     int     str_len;
  124.  
  125.     /*
  126.      * Process tokens one at a time. If a token has the magic value "ALL" the
  127.      * match always succeeds. If the token is a domain name, return YES if it
  128.      * matches the last fields of the string. If the token has the magic
  129.      * value "LOCAL", return YES if the string does not contain a "."
  130.      * character. If the token is a network number, return YES if it matches
  131.      * the head of the string. If the token looks like a netgroup name,
  132.      * return YES if the string is a (host) member of the netgroup.
  133.      * Otherwise, return YES if the token fully matches the string. Note: we
  134.      * assume that a daemon process name never begins or ends with a "." or
  135.      * "@" character.
  136.      */
  137.  
  138.     for (tok = strtok(list, sep); tok; tok = strtok((char *) 0, sep)) {
  139.     if (tok[0] == '.') {            /* domain: match last fields */
  140.         if ((str_len = strlen(string)) > (tok_len = strlen(tok))
  141.         && strcasecmp(tok, string + str_len - tok_len) == 0)
  142.         return (YES);
  143. #ifdef    NETGROUP
  144.     } else if (tok[0] == '@') {        /* netgroup: look it up */
  145.         if (innetgr(tok + 1, string, (char *) 0, (char *) 0))
  146.         return (YES);
  147. #endif
  148.     } else if (strcasecmp(tok, "ALL") == 0) {    /* all: match any */
  149.         return (YES);
  150.     } else if (strcasecmp(tok, "LOCAL") == 0) {    /* local: no dots */
  151.         if (strchr(string, '.') == 0)
  152.         return (YES);
  153.     } else if (!strcasecmp(tok, string)) {    /* match host name or address */
  154.         return (YES);
  155.     } else if (tok[(tok_len = strlen(tok)) - 1] == '.'    /* net number */
  156.            && strncmp(tok, string, tok_len) == 0) {
  157.         return (YES);
  158.     }
  159.     }
  160.     return (NO);
  161. }
  162.  
  163. #endif
  164.