home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume23 / log_tcp / part01 / hosts_access.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-19  |  5.5 KB  |  183 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. Upon the first
  7.   * match with an entry in the access-control tables, an optional shell
  8.   * command is executed.
  9.   * 
  10.   * Diagnostics are reported through syslog(3).
  11.   * 
  12.   * Compile with -DHOSTS_ACCESS in order to enable access control. See the
  13.   * hosts_access(5) manual page for details.
  14.   * 
  15.   * Compile with -DNETGROUP if your library provides support for netgroups.
  16.   * 
  17.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  18.   */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#) hosts_access.c 1.6 91/10/02 23:01:49";
  22. #endif
  23.  
  24.  /* System libraries. */
  25.  
  26. #include <sys/types.h>
  27. #include <sys/param.h>
  28. #include <stdio.h>
  29. #include <syslog.h>
  30. #include <ctype.h>
  31.  
  32. extern char *fgets();
  33. extern char *strchr();
  34. extern char *strtok();
  35. extern void exit();
  36.  
  37. /* Local stuff. */
  38.  
  39. #include "log_tcp.h"
  40.  
  41. /* Path names of the access control files. */
  42.  
  43. #define HOSTS_ALLOW    "/etc/hosts.allow"
  44. #define HOSTS_DENY    "/etc/hosts.deny"
  45.  
  46. /* Delimiters for lists of daemons or clients. */
  47.  
  48. static char sep[] = ", \t";
  49.  
  50. /* Constants to be used in assignments only, not in comparisons... */
  51.  
  52. #define    YES        1
  53. #define    NO        0
  54.  
  55. /* Forward declarations. */
  56.  
  57. static int table_match();
  58. static int list_match();
  59.  
  60. /* hosts_access - host access control facility */
  61.  
  62. int hosts_access(daemon, client)
  63. char   *daemon;
  64. char   *client;
  65. {
  66.  
  67.     /*
  68.      * If the (daemon, client) pair is matched by an entry in the file
  69.      * /etc/hosts.allow, access is granted. Otherwise, if the (daemon,
  70.      * client) pair is matched by an entry in the file /etc/hosts.deny,
  71.      * access is denied. Otherwise, access is granted. A non-existent
  72.      * access-control file is treated as an empty file.
  73.      */
  74.  
  75.     if (table_match(HOSTS_ALLOW, daemon, client))
  76.     return (YES);
  77.     if (table_match(HOSTS_DENY, daemon, client)) 
  78.     return (NO);
  79.     return (YES);
  80. }
  81.  
  82. /* table_match - match table entries with (daemon, client) pair */
  83.  
  84. static int table_match(table, daemon, client)
  85. char   *table;
  86. char   *daemon;
  87. char   *client;
  88. {
  89.     FILE   *fp;
  90.     char    sv_list[BUFSIZ];        /* becomes list of daemons */
  91.     char   *cl_list;            /* becomes list of clients */
  92.     char   *sh_cmd;            /* becomes optional shell command */
  93.     int     match = NO;
  94.     int     end;
  95.  
  96.     /*
  97.      * Process the table one line at a time. Lines that begin with a '#'
  98.      * character are ignored. Non-comment lines are broken at the ':'
  99.      * character (we complain if there is none). The first field is matched
  100.      * against the daemon process name (argv[0]), the second field against
  101.      * the host name. A non-existing table is treated as if it were an empty
  102.      * table. The optional shell command (third field) is executed when the
  103.      * first match is found.
  104.      */
  105.  
  106.     if (fp = fopen(table, "r")) {
  107.     while (match == 0 && fgets(sv_list, sizeof(sv_list), fp)) {
  108.         if (sv_list[end = strlen(sv_list) - 1] != '\n') {
  109.         syslog(LOG_ERR, "%s: line exceeds STDIO buffer size", table);
  110.         continue;
  111.         } else {
  112.         sv_list[end] = '\0';        /* strip trailing newline */
  113.         }
  114.         if (sv_list[0] == '#') {        /* skip comments */
  115.         continue;
  116.         } else if ((cl_list = strchr(sv_list, ':')) == 0) {
  117.         syslog(LOG_ERR, "%s: malformed entry: \"%s\"", table, sv_list);
  118.         continue;
  119.         } else {
  120.         *cl_list++ = '\0';        /* split 1st and 2nd fields */
  121.         if ((sh_cmd = strchr(cl_list, ':')) != 0)
  122.             *sh_cmd++ = '\0';        /* split 2nd and 3rd fields */
  123.         match = (list_match(sv_list, daemon)
  124.              && list_match(cl_list, client));
  125.         }
  126.     }
  127.     (void) fclose(fp);
  128.     }
  129.     if (match && sh_cmd)
  130.     shell_cmd(sh_cmd, daemon, client);
  131.     return (match);
  132. }
  133.  
  134. /* list_match - match a string against a list of tokens */
  135.  
  136. static int list_match(list, string)
  137. char   *list;
  138. char   *string;
  139. {
  140.     char   *tok;
  141.     int     tok_len;
  142.     int     str_len;
  143.  
  144.     /*
  145.      * Process tokens one at a time. If a token has the magic value "ALL" the
  146.      * match always succeeds. If the token is a domain name, return YES if it
  147.      * matches the last fields of the string. If the token has the magic
  148.      * value "LOCAL", return YES if the string does not contain a "."
  149.      * character. If the token is a network number, return YES if it matches
  150.      * the head of the string. If the token looks like a netgroup name,
  151.      * return YES if the string is a (host) member of the netgroup.
  152.      * Otherwise, return YES if the token fully matches the string. Note: we
  153.      * assume that a daemon process name never begins or ends with a "." or
  154.      * "@" character.
  155.      */
  156.  
  157.     for (tok = strtok(list, sep); tok; tok = strtok((char *) 0, sep)) {
  158.     if (tok[0] == '.') {            /* domain: match last fields */
  159.         if ((str_len = strlen(string)) > (tok_len = strlen(tok))
  160.         && strcasecmp(tok, string + str_len - tok_len) == 0)
  161.         return (YES);
  162. #ifdef    NETGROUP
  163.     } else if (tok[0] == '@') {        /* netgroup: look it up */
  164.         if (innetgr(tok + 1, string, (char *) 0, (char *) 0))
  165.         return (YES);
  166. #endif
  167.     } else if (strcasecmp(tok, "ALL") == 0) {    /* all: match any */
  168.         return (YES);
  169.     } else if (strcasecmp(tok, "LOCAL") == 0) {    /* local: no dots */
  170.         if (strchr(string, '.') == 0)
  171.         return (YES);
  172.     } else if (!strcasecmp(tok, string)) {    /* match host name or address */
  173.         return (YES);
  174.     } else if (tok[(tok_len = strlen(tok)) - 1] == '.'    /* net number */
  175.            && strncmp(tok, string, tok_len) == 0) {
  176.         return (YES);
  177.     }
  178.     }
  179.     return (NO);
  180. }
  181.  
  182. #endif
  183.