home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-A.06 / NETKIT-A / NetKit-A-0.06 / tcp_wrapper-6.3 / options.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-27  |  19.1 KB  |  759 lines

  1.  /*
  2.   * General skeleton for adding options to the access control language. The
  3.   * features offered by this module are documented in the hosts_options(5)
  4.   * manual page (source file: hosts_options.5, "nroff -man" format).
  5.   * 
  6.   * Notes and warnings for those who want to add features:
  7.   * 
  8.   * In case of errors, abort options processing and deny access. There are too
  9.   * many irreversible side effects to make error recovery feasible. For example,
  10.   * it makes no sense to continue after we have already changed the userid.
  11.   * 
  12.   * In case of errors, do not terminate the process: the routines might be
  13.   * called from a long-running daemon that should run forever.
  14.   * 
  15.   * In case of fatal errors, use clean_exit() instead of directly calling
  16.   * exit(), or the inetd may loop on an UDP request.
  17.   * 
  18.   * In verification mode (for example, with the "try" command) the "dry_run"
  19.   * flag is set. In this mode, an option function should just "say" what it
  20.   * is going to do instead of really doing it.
  21.   * 
  22.   * Some option functions do not return (for example, the twist option passes
  23.   * control to another program). In verification mode (dry_run flag is set)
  24.   * such options should clear the "dry_run" flag to inform the caller of this
  25.   * course of action.
  26.   */
  27.  
  28. #ifndef lint
  29. static char sccsid[] = "@(#) options.c 1.13 94/03/23 16:15:59";
  30. #endif
  31.  
  32. /* System libraries. */
  33.  
  34. #include <sys/types.h>
  35. #include <sys/param.h>
  36. #include <sys/socket.h>
  37. #include <sys/stat.h>
  38. #include <netinet/in.h>
  39. #include <netdb.h>
  40. #include <stdio.h>
  41. #include <syslog.h>
  42. #include <pwd.h>
  43. #include <grp.h>
  44. #include <ctype.h>
  45. #include <setjmp.h>
  46.  
  47. extern char *strchr();
  48. extern void closelog();
  49.  
  50. /* Local stuff. */
  51.  
  52. #include "log_tcp.h"
  53. #include "options.h"
  54.  
  55. int     dry_run = 0;            /* flag set in verification mode */
  56. jmp_buf options_buf;            /* quick way back to hosts_access() */
  57.  
  58. /* List of functions that implement the options. Add yours here. */
  59.  
  60. static void user_option();        /* execute "user=name" option */
  61. static void group_option();        /* execute "group=name" option */
  62. static void umask_option();        /* execute "umask=mask" option */
  63. static void linger_option();        /* execute "linger=time" option */
  64. static void keepalive_option();        /* execute "keepalive" option */
  65. static void spawn_option();        /* execute "spawn=command" option */
  66. static void twist_option();        /* execute "twist=command" option */
  67. static void rfc931_option();        /* execute "rfc931" option */
  68. static void setenv_option();        /* execute "setenv=name value" */
  69. static void nice_option();        /* execute "nice" option */
  70. static void severity_option();        /* execute "severity=value" */
  71. static void allow_option();        /* execute "allow" option */
  72. static void deny_option();        /* execute "deny" option */
  73.  
  74. static char *get_field();        /* chew :-delimited field off string */
  75. static char *chop_string();        /* strip leading and trailing blanks */
  76.  
  77. /* Structure of the options table. */
  78.  
  79. struct option {
  80.     char   *name;            /* keyword name, case is ignored */
  81.     void  (*func) ();            /* function that does the real work */
  82.     int     flags;            /* see below... */
  83. };
  84.  
  85. #define NEED_ARG    (1<<1)        /* option requires argument */
  86. #define USE_LAST    (1<<2)        /* option must be last */
  87. #define OPT_ARG        (1<<3)        /* option has optional argument */
  88.  
  89. #define need_arg(o)    ((o)->flags & NEED_ARG)
  90. #define opt_arg(o)    ((o)->flags & OPT_ARG)
  91. #define use_last(o)    ((o)->flags & USE_LAST)
  92.  
  93. /* List of known keywords. Add yours here. */
  94.  
  95. static struct option option_table[] = {
  96.     "user", user_option, NEED_ARG,    /* switch user id */
  97.     "group", group_option, NEED_ARG,    /* switch group id */
  98.     "umask", umask_option, NEED_ARG,    /* change umask */
  99.     "linger", linger_option, NEED_ARG,    /* change socket linger time */
  100.     "keepalive", keepalive_option, 0,    /* set socket keepalive option */
  101.     "spawn", spawn_option, NEED_ARG,    /* spawn shell command */
  102.     "twist", twist_option, NEED_ARG | USE_LAST,    /* replace current process */
  103.     "rfc931", rfc931_option, OPT_ARG,    /* do RFC 931 lookup */
  104.     "setenv", setenv_option, NEED_ARG,    /* update environment */
  105.     "nice", nice_option, OPT_ARG,    /* change nice value */
  106.     "severity", severity_option, NEED_ARG,    /* adjust logging level */
  107.     "allow", allow_option, USE_LAST,    /* grant access */
  108.     "deny", deny_option, USE_LAST,    /* deny access */
  109.     0,
  110. };
  111.  
  112. static char whitespace[] = " \t\r\n";
  113.  
  114. /* process_options - process access control options */
  115.  
  116. void    process_options(options, daemon, client)
  117. char   *options;
  118. char   *daemon;
  119. struct client_info *client;
  120. {
  121.     char   *key;
  122.     char   *value;
  123.     char   *curr_opt;
  124.     char   *next_opt;
  125.     struct option *op;
  126.  
  127.     /*
  128.      * Light-weight parser. Being easy to comprehend is more important than
  129.      * being smart.
  130.      */
  131.  
  132.     for (curr_opt = get_field(options); curr_opt; curr_opt = next_opt) {
  133.     next_opt = get_field((char *) 0);
  134.  
  135.     /*
  136.      * Separate the option into name and value parts.
  137.      */
  138.  
  139.     if (value = strchr(curr_opt, '=')) {    /* name=value */
  140.         *value++ = 0;
  141.         value = chop_string(value);        /* strip blanks around value */
  142.         if (*value == 0)
  143.         value = 0;            /* no value left */
  144.     }
  145.     key = chop_string(curr_opt);        /* strip blanks around key */
  146.  
  147.     /*
  148.      * Disallow missing option names (and empty option fields).
  149.      */
  150.  
  151.     if (*key == 0) {
  152.         syslog(LOG_ERR, "error: %s, line %d: missing option name",
  153.            hosts_access_file, hosts_access_line);
  154.         longjmp(options_buf, OPT_DENY);
  155.     }
  156.  
  157.     /*
  158.      * Lookup the option-specific info and do some common error checks.
  159.      * Delegate option-specific processing to the specific fuctions.
  160.      */
  161.  
  162.     for (op = option_table; op->name; op++)    /* find keyword */
  163.         if (strcasecmp(op->name, key) == 0)
  164.         break;
  165.     if (op->name == 0) {
  166.         syslog(LOG_ERR, "error: %s, line %d: bad option name or syntax: \"%s\"",
  167.            hosts_access_file, hosts_access_line, key);
  168.         longjmp(options_buf, OPT_DENY);
  169.     } else if (!value && need_arg(op)) {
  170.         syslog(LOG_ERR, "error: %s, line %d: option \"%s\" requires value",
  171.            hosts_access_file, hosts_access_line, key);
  172.         longjmp(options_buf, OPT_DENY);
  173.     } else if (value && !need_arg(op) && !opt_arg(op)) {
  174.         syslog(LOG_ERR, "error: %s, line %d: option \"%s\" cannot have value",
  175.            hosts_access_file, hosts_access_line, key);
  176.         longjmp(options_buf, OPT_DENY);
  177.     } else if (next_opt && use_last(op)) {
  178.         syslog(LOG_ERR, "error: %s, line %d: option \"%s\" must be last option",
  179.            hosts_access_file, hosts_access_line, key);
  180.         longjmp(options_buf, OPT_DENY);
  181.     } else {
  182.         (*(op->func)) (value, daemon, client);
  183.     }
  184.     }
  185. }
  186.  
  187. /* allow_option - grant access */
  188.  
  189. /* ARGSUSED */
  190.  
  191. static void allow_option(value, daemon, client)
  192. char   *value;
  193. char   *daemon;
  194. struct client_info *client;
  195. {
  196.     if (dry_run)
  197.     syslog(LOG_DEBUG, "option:   allow");
  198.     longjmp(options_buf, OPT_ALLOW);
  199. }
  200.  
  201. /* deny_option - deny access */
  202.  
  203. /* ARGSUSED */
  204.  
  205. static void deny_option(value, daemon, client)
  206. char   *value;
  207. char   *daemon;
  208. struct client_info *client;
  209. {
  210.     if (dry_run)
  211.     syslog(LOG_DEBUG, "option:   deny");
  212.     longjmp(options_buf, OPT_DENY);
  213. }
  214.  
  215. /* user_option - switch user id */
  216.  
  217. /* ARGSUSED */
  218.  
  219. static void user_option(value, daemon, client)
  220. char   *value;
  221. char   *daemon;
  222. struct client_info *client;
  223. {
  224.     struct passwd *pwd;
  225.     struct passwd *getpwnam();
  226.  
  227.     if ((pwd = getpwnam(value)) == 0) {
  228.     syslog(LOG_ERR, "error: %s, line %d: unknown user: \"%s\"",
  229.            hosts_access_file, hosts_access_line, value);
  230.     longjmp(options_buf, OPT_DENY);
  231.     }
  232.     endpwent();
  233.  
  234.     if (dry_run) {
  235.     syslog(LOG_DEBUG, "option:   user = %s", value);
  236.     return;
  237.     }
  238.     if (setuid(pwd->pw_uid)) {
  239.     syslog(LOG_ERR, "error: %s, line %d: setuid(%s): %m",
  240.            hosts_access_file, hosts_access_line, value);
  241.     longjmp(options_buf, OPT_DENY);
  242.     }
  243. }
  244.  
  245. /* group_option - switch group id */
  246.  
  247. /* ARGSUSED */
  248.  
  249. static void group_option(value, daemon, client)
  250. char   *value;
  251. char   *daemon;
  252. struct client_info *client;
  253. {
  254.     struct group *grp;
  255.     struct group *getgrnam();
  256.  
  257.     if ((grp = getgrnam(value)) == 0) {
  258.     syslog(LOG_ERR, "error: %s, line %d: unknown group: \"%s\"",
  259.            hosts_access_file, hosts_access_line, value);
  260.     longjmp(options_buf, OPT_DENY);
  261.     }
  262.     endgrent();
  263.  
  264.     if (dry_run) {
  265.     syslog(LOG_DEBUG, "option:   group = %s", value);
  266.     return;
  267.     }
  268.     if (setgid(grp->gr_gid)) {
  269.     syslog(LOG_ERR, "error: %s, line %d: setgid(%s): %m",
  270.            hosts_access_file, hosts_access_line, value);
  271.     longjmp(options_buf, OPT_DENY);
  272.     }
  273. }
  274.  
  275. /* umask_option - set file creation mask */
  276.  
  277. /* ARGSUSED */
  278.  
  279. static void umask_option(value, daemon, client)
  280. char   *value;
  281. char   *daemon;
  282. struct client_info *client;
  283. {
  284.     unsigned mask;
  285.     char    junk;
  286.  
  287.     if (sscanf(value, "%o%c", &mask, &junk) != 1 || (mask & 0777) != mask) {
  288.     syslog(LOG_ERR, "error: %s, line %d: bad umask value: \"%s\"",
  289.            hosts_access_file, hosts_access_line, value);
  290.     longjmp(options_buf, OPT_DENY);
  291.     }
  292.     if (dry_run) {
  293.     syslog(LOG_DEBUG, "option:   umask = %o", mask);
  294.     return;
  295.     }
  296.     (void) umask(mask);
  297. }
  298.  
  299. /* spawn_option - spawn a shell command and wait */
  300.  
  301. static void spawn_option(value, daemon, client)
  302. char   *value;
  303. char   *daemon;
  304. struct client_info *client;
  305. {
  306.     char    buf[BUFSIZ];
  307.     int     pid = getpid();
  308.  
  309.     if (dry_run) {
  310.     percent_x(buf, sizeof(buf), value, daemon, client, pid);
  311.     syslog(LOG_DEBUG, "option:   spawn = %s", buf);
  312.     return;
  313.     }
  314.     shell_cmd(value, daemon, client);
  315. }
  316.  
  317. /* linger_option - set the socket linger time (Marc Boucher <marc@cam.org>) */
  318.  
  319. /* ARGSUSED */
  320.  
  321. static void linger_option(value, daemon, client)
  322. char   *value;
  323. char   *daemon;
  324. struct client_info *client;
  325. {
  326. #if defined(SO_LINGER) && !defined(BROKEN_SO_LINGER)    /* broken linux */
  327.     struct linger linger;
  328.     char    junk;
  329.  
  330.     if (sscanf(value, "%d%c", &linger.l_linger, &junk) != 1
  331.     || linger.l_linger < 0) {
  332.     syslog(LOG_ERR, "error: %s, line %d: bad linger value: \"%s\"",
  333.            hosts_access_file, hosts_access_line, value);
  334.     longjmp(options_buf, OPT_DENY);
  335.     }
  336.     if (dry_run) {
  337.     syslog(LOG_DEBUG, "option:   linger = %d", linger.l_linger);
  338.     return;
  339.     }
  340.     linger.l_onoff = (linger.l_linger != 0);
  341.     if (setsockopt(client->fd, SOL_SOCKET, SO_LINGER, (char *) &linger, 
  342.     sizeof(linger)) < 0) {
  343.     syslog(LOG_ERR, "error: %s, line %d: setsockopt SO_LINGER %d: %m",
  344.            hosts_access_file, hosts_access_line, linger.l_linger);
  345.     longjmp(options_buf, OPT_DENY);
  346.     }
  347. #else
  348.     syslog(LOG_ERR, "error: %s, line %d: SO_LINGER not supported",
  349.        hosts_access_file, hosts_access_line);
  350.     longjmp(options_buf, OPT_DENY);
  351. #endif
  352. }
  353.  
  354. /* keepalive_option - set the socket keepalive option */
  355.  
  356. /* ARGSUSED */
  357.  
  358. static void keepalive_option(value, daemon, client)
  359. char   *value;
  360. char   *daemon;
  361. struct client_info *client;
  362. {
  363. #if defined(SO_KEEPALIVE) && !defined(BROKEN_SO_KEEPALIVE)
  364.     int     on = 1;
  365.  
  366.     if (dry_run) {
  367.     syslog(LOG_DEBUG, "option:   keepalive");
  368.     return;
  369.     }
  370.     if (setsockopt(client->fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
  371.            sizeof(on)) < 0)
  372.     syslog(LOG_WARNING, "warning: %s, line %d: setsockopt SO_KEEPALIVE: %m",
  373.            hosts_access_file, hosts_access_line);
  374. #else
  375.     syslog(LOG_WARNING, "warning: %s, line %d: SO_KEEPALIVE not supported",
  376.        hosts_access_file, hosts_access_line);
  377. #endif
  378. }
  379.  
  380. /* nice_option - set nice value */
  381.  
  382. /* ARGSUSED */
  383.  
  384. static void nice_option(value, daemon, client)
  385. char   *value;
  386. char   *daemon;
  387. struct client_info *client;
  388. {
  389.     int     niceval = 10;
  390.     char    junk;
  391.  
  392.     if (value != 0 && sscanf(value, "%d%c", &niceval, &junk) != 1) {
  393.     syslog(LOG_ERR, "error: %s, line %d: bad nice value: \"%s\"",
  394.            hosts_access_file, hosts_access_line, value);
  395.     longjmp(options_buf, OPT_DENY);
  396.     }
  397.     if (dry_run) {
  398.     syslog(LOG_DEBUG, "option:   nice = %d", niceval);
  399.     return;
  400.     }
  401.     if (nice(niceval) < 0) {
  402.     syslog(LOG_WARNING, "warning: %s, line %d: nice(%d): %m",
  403.            hosts_access_file, hosts_access_line, niceval);
  404.     }
  405. }
  406.  
  407. /* maybe_dup2 - conditional dup2 */
  408.  
  409. static int maybe_dup2(fd1, fd2)
  410. int fd1;
  411. int fd2;
  412. {
  413.     if (fd1 == fd2) {                /* already OK */
  414.     return (fd2);
  415.     } else {                    /* dup new to old */
  416.     close(fd2);
  417.     return (dup(fd1));
  418.     }
  419. }
  420.  
  421. /* twist_option - replace process by shell command */
  422.  
  423. static void twist_option(value, daemon, client)
  424. char   *value;
  425. char   *daemon;
  426. struct client_info *client;
  427. {
  428.     char    buf[BUFSIZ];
  429.     int     pid = getpid();
  430.     char   *error;
  431.  
  432.     percent_x(buf, sizeof(buf), value, daemon, client, pid);
  433.  
  434.     if (dry_run) {
  435.     syslog(LOG_DEBUG, "option:   twist = %s", buf);
  436.     dry_run = 0;
  437.     return;
  438.     }
  439.     syslog(deny_severity, "twist %s to %s", hosts_info(client), buf);
  440.     closelog();
  441.  
  442.     /* Before switching to the shell, set up stdin, stdout and stderr. */
  443.  
  444.     if (maybe_dup2(client->fd, 0) != 0 ||
  445.     maybe_dup2(client->fd, 1) != 1 ||
  446.     maybe_dup2(client->fd, 2) != 2) {
  447.     error = "twist_option: dup: %m";
  448.     } else {
  449.     if (client->fd > 2)
  450.         close(client->fd);
  451.     (void) execl("/bin/sh", "sh", "-c", buf, (char *) 0);
  452.     error = "twist_option: /bin/sh: %m";
  453.     }
  454.  
  455.     /* Can get here only in case of errors. */
  456.  
  457. #ifdef LOG_MAIL
  458.     (void) openlog(daemon, LOG_PID, FACILITY);
  459. #else
  460.     (void) openlog(daemon, LOG_PID);
  461. #endif
  462.     syslog(LOG_ERR, error);
  463.  
  464.     /* We MUST terminate the process. */
  465.  
  466.     clean_exit(client);
  467. }
  468.  
  469. /* rfc931_option - look up remote user name */
  470.  
  471. /* ARGSUSED */
  472.  
  473. static void rfc931_option(value, daemon, client)
  474. char   *value;
  475. char   *daemon;
  476. struct client_info *client;
  477. {
  478.     int     timeout;
  479.     char    junk;
  480.  
  481.     if (value) {
  482.     if (sscanf(value, "%d%c", &timeout, &junk) != 1 || timeout <= 0) {
  483.         syslog(LOG_ERR, "error: %s, line %d: bad rfc931 timeout: \"%s\"",
  484.            hosts_access_file, hosts_access_line, value);
  485.         longjmp(options_buf, OPT_DENY);
  486.     }
  487.     rfc931_timeout = timeout;
  488.     }
  489.     if (dry_run) {
  490.     syslog(LOG_DEBUG, "option:   rfc931 = %d", rfc931_timeout);
  491.     return;
  492.     }
  493.     if (client->user[0] == 0 && RFC931_POSSIBLE(client))
  494.     client->user = rfc931(client->rmt_sin, client->our_sin);
  495. }
  496.  
  497. /* setenv_option - set environment variable */
  498.  
  499. /* ARGSUSED */
  500.  
  501. static void setenv_option(value, daemon, client)
  502. char   *value;
  503. char   *daemon;
  504. struct client_info *client;
  505. {
  506.     char   *var_name;
  507.     char   *var_value;
  508.     char    buf[BUFSIZ];
  509.     int     pid;
  510.  
  511.     /*
  512.      * Separate the argument into a name and value part.
  513.      */
  514.  
  515.     var_value = value + strcspn(value, whitespace);
  516.  
  517.     if (*var_value == 0) {            /* just a name, that's all */
  518.     var_name = value;
  519.     } else {                    /* expand %stuff in value */
  520.     *var_value++ = 0;
  521.     var_name = chop_string(value);
  522.     pid = getpid();
  523.     percent_x(buf, sizeof(buf), var_value, daemon, client, pid);
  524.     var_value = chop_string(buf);
  525.     }
  526.     if (dry_run) {
  527.     syslog(LOG_DEBUG, "option:   setenv = %s %s", var_name, var_value);
  528.     return;
  529.     }
  530.     if (setenv(var_name, var_value, 1)) {
  531.     syslog(LOG_ERR, "error: %s, line %d: memory allocation failure",
  532.            hosts_access_file, hosts_access_line);
  533.     longjmp(options_buf, OPT_DENY);
  534.     }
  535. }
  536.  
  537. /* get_field - return pointer to next field in string */
  538.  
  539. static char *get_field(string)
  540. char   *string;
  541. {
  542.     static char *last = "";
  543.     char   *src;
  544.     char   *dst;
  545.     char   *ret;
  546.  
  547.     /*
  548.      * This function returns pointers to successive fields within a given
  549.      * string. ":" is the field separator; warn if the rule ends in one. It
  550.      * replaces a "\:" sequence by ":", without treating the result of
  551.      * substitution as field terminator. A null argument means resume search
  552.      * where the previous call terminated. This function destroys its
  553.      * argument.
  554.      */
  555.  
  556.     /*
  557.      * Work from explicit source or from memory.
  558.      */
  559.  
  560.     if (string == 0)
  561.     string = last;
  562.     if (string[0] == 0)
  563.     return (0);
  564.  
  565.     /*
  566.      * While processing \: we overwrite the input. This way we do not have to
  567.      * maintain buffers for copies of input fields.
  568.      */
  569.  
  570.     src = dst = ret = string;
  571.  
  572.     for (;;) {
  573.     switch (*src) {
  574.     case '\\':                /* handle escape */
  575.         switch (src[1]) {
  576.         case ':':                /* convert \: to : */
  577.         src++;
  578.         /* FALLTHROUGH */
  579.         case '\0':                /* don't run off end */
  580.         *dst++ = *src++;
  581.         break;
  582.         default:                /* copy \other verbatim */
  583.         *dst++ = *src++, *dst++ = *src++;
  584.         break;
  585.         }
  586.         break;
  587.     case ':':                /* field separator */
  588.         src++;
  589.         if (*src == 0)
  590.         syslog(LOG_WARNING, "warning: %s, line %d: rule ends in \":\"",
  591.                hosts_access_file, hosts_access_line);
  592.         /* FALLTHROUGH */
  593.     case '\0':                /* end of string */
  594.         last = src;
  595.         *dst = 0;
  596.         return (ret);
  597.     default:                /* anything else */
  598.         *dst++ = *src++;
  599.         break;
  600.     }
  601.     }
  602. }
  603.  
  604. /* chop_string - strip leading and trailing blanks from string */
  605.  
  606. static char *chop_string(start)
  607. register char *start;
  608. {
  609.     register char *end;
  610.  
  611.     while (*start && isspace(*start))
  612.     start++;
  613.  
  614.     for (end = start + strlen(start); end > start && isspace(end[-1]); end--)
  615.      /* void */ ;
  616.     *end = 0;
  617.  
  618.     return (start);
  619. }
  620.  
  621.  /*
  622.   * The severity option goes last because it comes with a huge amount of ugly
  623.   * #ifdefs and tables.
  624.   */
  625.  
  626. struct syslog_names {
  627.     char   *name;
  628.     int     value;
  629. };
  630.  
  631. static struct syslog_names log_facilities[] = {
  632. #ifdef LOG_KERN
  633.     "kern", LOG_KERN,
  634. #endif
  635. #ifdef LOG_USER
  636.     "user", LOG_USER,
  637. #endif
  638. #ifdef LOG_MAIL
  639.     "mail", LOG_MAIL,
  640. #endif
  641. #ifdef LOG_DAEMON
  642.     "daemon", LOG_DAEMON,
  643. #endif
  644. #ifdef LOG_AUTH
  645.     "auth", LOG_AUTH,
  646. #endif
  647. #ifdef LOG_LPR
  648.     "lpr", LOG_LPR,
  649. #endif
  650. #ifdef LOG_NEWS
  651.     "news", LOG_NEWS,
  652. #endif
  653. #ifdef LOG_UUCP
  654.     "uucp", LOG_UUCP,
  655. #endif
  656. #ifdef LOG_CRON
  657.     "cron", LOG_CRON,
  658. #endif
  659. #ifdef LOG_LOCAL0
  660.     "local0", LOG_LOCAL0,
  661. #endif
  662. #ifdef LOG_LOCAL1
  663.     "local1", LOG_LOCAL1,
  664. #endif
  665. #ifdef LOG_LOCAL2
  666.     "local2", LOG_LOCAL2,
  667. #endif
  668. #ifdef LOG_LOCAL3
  669.     "local3", LOG_LOCAL3,
  670. #endif
  671. #ifdef LOG_LOCAL4
  672.     "local4", LOG_LOCAL4,
  673. #endif
  674. #ifdef LOG_LOCAL5
  675.     "local5", LOG_LOCAL5,
  676. #endif
  677. #ifdef LOG_LOCAL6
  678.     "local6", LOG_LOCAL6,
  679. #endif
  680. #ifdef LOG_LOCAL7
  681.     "local7", LOG_LOCAL7,
  682. #endif
  683.     0,
  684. };
  685.  
  686. static struct syslog_names log_severities[] = {
  687. #ifdef LOG_EMERG
  688.     "emerg", LOG_EMERG,
  689. #endif
  690. #ifdef LOG_ALERT
  691.     "alert", LOG_ALERT,
  692. #endif
  693. #ifdef LOG_CRIT
  694.     "crit", LOG_CRIT,
  695. #endif
  696. #ifdef LOG_ERR
  697.     "err", LOG_ERR,
  698. #endif
  699. #ifdef LOG_WARNING
  700.     "warning", LOG_WARNING,
  701. #endif
  702. #ifdef LOG_NOTICE
  703.     "notice", LOG_NOTICE,
  704. #endif
  705. #ifdef LOG_INFO
  706.     "info", LOG_INFO,
  707. #endif
  708. #ifdef LOG_DEBUG
  709.     "debug", LOG_DEBUG,
  710. #endif
  711.     0,
  712. };
  713.  
  714. /* severity_map - lookup facility or severity value */
  715.  
  716. static int severity_map(table, name)
  717. struct syslog_names *table;
  718. char   *name;
  719. {
  720.     struct syslog_names *t;
  721.  
  722.     for (t = table; t->name; t++) {
  723.     if (strcasecmp(t->name, name) == 0)
  724.         return (t->value);
  725.     }
  726.     syslog(LOG_ERR,
  727.        "error: %s, line %d: bad syslog facility or severity: \"%s\"",
  728.        hosts_access_file, hosts_access_line, name);
  729.     longjmp(options_buf, OPT_DENY);
  730.     /* NOTREACHED */
  731. }
  732.  
  733. /* severity_option - change logging severity for this event (Dave Mitchell) */
  734.  
  735. /* ARGSUSED */
  736.  
  737. static void severity_option(value, daemon, client)
  738. char   *value;
  739. char   *daemon;
  740. struct client_info *client;
  741. {
  742.     int     new_severity;
  743.     char   *dot;
  744.  
  745.     if (dot = strchr(value, '.')) {        /* facility.level */
  746.     *dot = 0;
  747.     new_severity = severity_map(log_facilities, chop_string(value))
  748.         | severity_map(log_severities, chop_string(dot + 1));
  749.     *dot = '.';
  750.     } else {                    /* no facility, just level */
  751.     new_severity = severity_map(log_severities, chop_string(value));
  752.     }
  753.     if (dry_run) {
  754.     syslog(LOG_DEBUG, "option:   severity = %s", value);
  755.     return;
  756.     }
  757.     allow_severity = deny_severity = new_severity;
  758. }
  759.