Home | History | Annotate | Line # | Download | only in libwrap
options.c revision 1.11.6.1
      1  1.11.6.1      tron /*	$NetBSD: options.c,v 1.11.6.1 2005/07/11 11:12:47 tron Exp $	*/
      2       1.3  christos 
      3       1.1       mrg  /*
      4       1.1       mrg   * General skeleton for adding options to the access control language. The
      5       1.1       mrg   * features offered by this module are documented in the hosts_options(5)
      6       1.1       mrg   * manual page (source file: hosts_options.5, "nroff -man" format).
      7       1.6    simonb   *
      8       1.1       mrg   * Notes and warnings for those who want to add features:
      9       1.6    simonb   *
     10       1.1       mrg   * In case of errors, abort options processing and deny access. There are too
     11       1.1       mrg   * many irreversible side effects to make error recovery feasible. For
     12       1.1       mrg   * example, it makes no sense to continue after we have already changed the
     13       1.1       mrg   * userid.
     14       1.6    simonb   *
     15       1.1       mrg   * In case of errors, do not terminate the process: the routines might be
     16       1.1       mrg   * called from a long-running daemon that should run forever. Instead, call
     17       1.1       mrg   * tcpd_jump() which does a non-local goto back into the hosts_access()
     18       1.1       mrg   * routine.
     19       1.6    simonb   *
     20       1.1       mrg   * In case of severe errors, use clean_exit() instead of directly calling
     21       1.1       mrg   * exit(), or the inetd may loop on an UDP request.
     22       1.6    simonb   *
     23       1.1       mrg   * In verification mode (for example, with the "tcpdmatch" command) the
     24       1.1       mrg   * "dry_run" flag is set. In this mode, an option function should just "say"
     25       1.1       mrg   * what it is going to do instead of really doing it.
     26       1.6    simonb   *
     27       1.1       mrg   * Some option functions do not return (for example, the twist option passes
     28       1.1       mrg   * control to another program). In verification mode (dry_run flag is set)
     29       1.1       mrg   * such options should clear the "dry_run" flag to inform the caller of this
     30       1.1       mrg   * course of action.
     31       1.1       mrg   */
     32       1.1       mrg 
     33       1.3  christos #include <sys/cdefs.h>
     34       1.1       mrg #ifndef lint
     35       1.3  christos #if 0
     36       1.1       mrg static char sccsid[] = "@(#) options.c 1.17 96/02/11 17:01:31";
     37       1.3  christos #else
     38  1.11.6.1      tron __RCSID("$NetBSD: options.c,v 1.11.6.1 2005/07/11 11:12:47 tron Exp $");
     39       1.3  christos #endif
     40       1.1       mrg #endif
     41       1.1       mrg 
     42       1.1       mrg /* System libraries. */
     43       1.1       mrg 
     44       1.1       mrg #include <sys/types.h>
     45       1.1       mrg #include <sys/param.h>
     46       1.1       mrg #include <sys/socket.h>
     47       1.1       mrg #include <sys/stat.h>
     48       1.1       mrg #include <netinet/in.h>
     49       1.1       mrg #include <netdb.h>
     50       1.1       mrg #include <stdio.h>
     51       1.1       mrg #include <syslog.h>
     52       1.3  christos #include <unistd.h>
     53       1.3  christos #include <stdlib.h>
     54       1.1       mrg #include <pwd.h>
     55       1.1       mrg #include <grp.h>
     56       1.1       mrg #include <ctype.h>
     57       1.1       mrg #include <setjmp.h>
     58       1.1       mrg #include <string.h>
     59       1.1       mrg 
     60       1.1       mrg /* Local stuff. */
     61       1.1       mrg 
     62       1.1       mrg #include "tcpd.h"
     63       1.1       mrg 
     64       1.1       mrg /* Options runtime support. */
     65       1.1       mrg 
     66       1.1       mrg int     dry_run = 0;			/* flag set in verification mode */
     67       1.1       mrg extern jmp_buf tcpd_buf;		/* tcpd_jump() support */
     68       1.1       mrg 
     69       1.1       mrg /* Options parser support. */
     70       1.1       mrg 
     71       1.1       mrg static char whitespace_eq[] = "= \t\r\n";
     72       1.1       mrg #define whitespace (whitespace_eq + 1)
     73       1.1       mrg 
     74       1.3  christos static char *get_field			/* chew :-delimited field off string */
     75       1.3  christos 		__P((char *));
     76       1.3  christos static char *chop_string		/* strip leading and trailing blanks */
     77       1.3  christos 		__P((char *));
     78       1.3  christos struct syslog_names;
     79       1.6    simonb static int severity_map
     80       1.3  christos 		__P((struct syslog_names *, char *));
     81       1.1       mrg 
     82       1.1       mrg /* List of functions that implement the options. Add yours here. */
     83       1.1       mrg 
     84       1.3  christos static void user_option			/* execute "user name.group" option */
     85       1.3  christos 		__P((char *, struct request_info *));
     86       1.3  christos static void group_option		/* execute "group name" option */
     87       1.3  christos 		__P((char *, struct request_info *));
     88       1.3  christos static void umask_option		/* execute "umask mask" option */
     89       1.3  christos 		__P((char *, struct request_info *));
     90       1.3  christos static void linger_option		/* execute "linger time" option */
     91       1.3  christos 		__P((char *, struct request_info *));
     92       1.3  christos static void keepalive_option		/* execute "keepalive" option */
     93       1.3  christos 		__P((char *, struct request_info *));
     94       1.3  christos static void spawn_option		/* execute "spawn command" option */
     95       1.3  christos 		__P((char *, struct request_info *));
     96       1.3  christos static void twist_option		/* execute "twist command" option */
     97       1.3  christos 		__P((char *, struct request_info *));
     98       1.3  christos static void rfc931_option		/* execute "rfc931" option */
     99       1.3  christos 		__P((char *, struct request_info *));
    100       1.3  christos static void setenv_option		/* execute "setenv name value" */
    101       1.3  christos 		__P((char *, struct request_info *));
    102       1.3  christos static void nice_option			/* execute "nice" option */
    103       1.3  christos 		__P((char *, struct request_info *));
    104       1.3  christos static void severity_option		/* execute "severity value" */
    105       1.3  christos 		__P((char *, struct request_info *));
    106       1.3  christos static void allow_option		/* execute "allow" option */
    107       1.3  christos 		__P((char *, struct request_info *));
    108       1.3  christos static void deny_option			/* execute "deny" option */
    109       1.3  christos 		__P((char *, struct request_info *));
    110       1.3  christos static void banners_option		/* execute "banners path" option */
    111       1.3  christos 		__P((char *, struct request_info *));
    112       1.1       mrg 
    113       1.1       mrg /* Structure of the options table. */
    114       1.1       mrg 
    115       1.8     billc struct option {
    116       1.1       mrg     char   *name;			/* keyword name, case is ignored */
    117       1.3  christos     void  (*func)			/* function that does the real work */
    118       1.3  christos 		__P((char *, struct request_info *));
    119       1.1       mrg     int     flags;			/* see below... */
    120       1.1       mrg };
    121       1.1       mrg 
    122       1.1       mrg #define NEED_ARG	(1<<1)		/* option requires argument */
    123       1.1       mrg #define USE_LAST	(1<<2)		/* option must be last */
    124       1.1       mrg #define OPT_ARG		(1<<3)		/* option has optional argument */
    125       1.1       mrg #define EXPAND_ARG	(1<<4)		/* do %x expansion on argument */
    126       1.1       mrg 
    127       1.1       mrg #define need_arg(o)	((o)->flags & NEED_ARG)
    128       1.1       mrg #define opt_arg(o)	((o)->flags & OPT_ARG)
    129       1.1       mrg #define permit_arg(o)	((o)->flags & (NEED_ARG | OPT_ARG))
    130       1.1       mrg #define use_last(o)	((o)->flags & USE_LAST)
    131       1.1       mrg #define expand_arg(o)	((o)->flags & EXPAND_ARG)
    132       1.1       mrg 
    133       1.1       mrg /* List of known keywords. Add yours here. */
    134       1.1       mrg 
    135       1.8     billc static struct option option_table[] = {
    136       1.3  christos     { "user", user_option, NEED_ARG },
    137       1.3  christos     { "group", group_option, NEED_ARG },
    138       1.3  christos     { "umask", umask_option, NEED_ARG },
    139       1.3  christos     { "linger", linger_option, NEED_ARG },
    140       1.3  christos     { "keepalive", keepalive_option, 0 },
    141       1.3  christos     { "spawn", spawn_option, NEED_ARG | EXPAND_ARG },
    142       1.3  christos     { "twist", twist_option, NEED_ARG | EXPAND_ARG | USE_LAST },
    143       1.3  christos     { "rfc931", rfc931_option, OPT_ARG },
    144       1.3  christos     { "setenv", setenv_option, NEED_ARG | EXPAND_ARG },
    145       1.3  christos     { "nice", nice_option, OPT_ARG },
    146       1.3  christos     { "severity", severity_option, NEED_ARG },
    147       1.3  christos     { "allow", allow_option, USE_LAST },
    148       1.3  christos     { "deny", deny_option, USE_LAST },
    149       1.3  christos     { "banners", banners_option, NEED_ARG },
    150       1.3  christos     { NULL, NULL, 0 }
    151       1.1       mrg };
    152       1.1       mrg 
    153       1.1       mrg /* process_options - process access control options */
    154       1.1       mrg 
    155       1.1       mrg void    process_options(options, request)
    156       1.1       mrg char   *options;
    157       1.1       mrg struct request_info *request;
    158       1.1       mrg {
    159       1.1       mrg     char   *key;
    160       1.1       mrg     char   *value;
    161       1.1       mrg     char   *curr_opt;
    162       1.1       mrg     char   *next_opt;
    163       1.8     billc     struct option *op;
    164       1.1       mrg     char    bf[BUFSIZ];
    165       1.1       mrg 
    166       1.1       mrg     for (curr_opt = get_field(options); curr_opt; curr_opt = next_opt) {
    167       1.1       mrg 	next_opt = get_field((char *) 0);
    168       1.1       mrg 
    169       1.1       mrg 	/*
    170       1.1       mrg 	 * Separate the option into name and value parts. For backwards
    171       1.1       mrg 	 * compatibility we ignore exactly one '=' between name and value.
    172       1.1       mrg 	 */
    173       1.1       mrg 	curr_opt = chop_string(curr_opt);
    174       1.1       mrg 	if (*(value = curr_opt + strcspn(curr_opt, whitespace_eq))) {
    175       1.1       mrg 	    if (*value != '=') {
    176       1.1       mrg 		*value++ = 0;
    177       1.1       mrg 		value += strspn(value, whitespace);
    178       1.1       mrg 	    }
    179       1.1       mrg 	    if (*value == '=') {
    180       1.1       mrg 		*value++ = 0;
    181       1.1       mrg 		value += strspn(value, whitespace);
    182       1.1       mrg 	    }
    183       1.1       mrg 	}
    184       1.1       mrg 	if (*value == 0)
    185       1.1       mrg 	    value = 0;
    186       1.1       mrg 	key = curr_opt;
    187       1.1       mrg 
    188       1.1       mrg 	/*
    189       1.1       mrg 	 * Disallow missing option names (and empty option fields).
    190       1.1       mrg 	 */
    191       1.1       mrg 	if (*key == 0)
    192       1.1       mrg 	    tcpd_jump("missing option name");
    193       1.1       mrg 
    194       1.1       mrg 	/*
    195       1.1       mrg 	 * Lookup the option-specific info and do some common error checks.
    196       1.1       mrg 	 * Delegate option-specific processing to the specific functions.
    197       1.1       mrg 	 */
    198       1.1       mrg 
    199       1.1       mrg 	for (op = option_table; op->name && STR_NE(op->name, key); op++)
    200       1.1       mrg 	     /* VOID */ ;
    201       1.1       mrg 	if (op->name == 0)
    202       1.1       mrg 	    tcpd_jump("bad option name: \"%s\"", key);
    203       1.1       mrg 	if (!value && need_arg(op))
    204       1.1       mrg 	    tcpd_jump("option \"%s\" requires value", key);
    205       1.1       mrg 	if (value && !permit_arg(op))
    206       1.1       mrg 	    tcpd_jump("option \"%s\" requires no value", key);
    207       1.1       mrg 	if (next_opt && use_last(op))
    208       1.1       mrg 	    tcpd_jump("option \"%s\" must be at end", key);
    209       1.1       mrg 	if (value && expand_arg(op))
    210       1.1       mrg 	    value = chop_string(percent_x(bf, sizeof(bf), value, request));
    211       1.1       mrg 	if (hosts_access_verbose)
    212       1.1       mrg 	    syslog(LOG_DEBUG, "option:   %s %s", key, value ? value : "");
    213       1.1       mrg 	(*(op->func)) (value, request);
    214       1.1       mrg     }
    215       1.1       mrg }
    216       1.1       mrg 
    217       1.1       mrg /* allow_option - grant access */
    218       1.1       mrg 
    219       1.1       mrg /* ARGSUSED */
    220       1.1       mrg 
    221       1.1       mrg static void allow_option(value, request)
    222       1.1       mrg char   *value;
    223       1.1       mrg struct request_info *request;
    224       1.1       mrg {
    225       1.1       mrg     longjmp(tcpd_buf, AC_PERMIT);
    226       1.1       mrg }
    227       1.1       mrg 
    228       1.1       mrg /* deny_option - deny access */
    229       1.1       mrg 
    230       1.1       mrg /* ARGSUSED */
    231       1.1       mrg 
    232       1.1       mrg static void deny_option(value, request)
    233       1.1       mrg char   *value;
    234       1.1       mrg struct request_info *request;
    235       1.1       mrg {
    236       1.1       mrg     longjmp(tcpd_buf, AC_DENY);
    237       1.1       mrg }
    238       1.1       mrg 
    239       1.1       mrg /* banners_option - expand %<char>, terminate each line with CRLF */
    240       1.1       mrg 
    241       1.1       mrg static void banners_option(value, request)
    242       1.1       mrg char   *value;
    243       1.1       mrg struct request_info *request;
    244       1.1       mrg {
    245      1.11    itojun     char    path[MAXPATHLEN];
    246       1.1       mrg     char    ibuf[BUFSIZ];
    247       1.1       mrg     char    obuf[2 * BUFSIZ];
    248       1.1       mrg     struct stat st;
    249       1.1       mrg     int     ch;
    250       1.1       mrg     FILE   *fp;
    251       1.1       mrg 
    252       1.2       mrg     (void)snprintf(path, sizeof path, "%s/%s", value, eval_daemon(request));
    253       1.1       mrg     if ((fp = fopen(path, "r")) != 0) {
    254       1.1       mrg 	while ((ch = fgetc(fp)) == 0)
    255       1.1       mrg 	    write(request->fd, "", 1);
    256       1.1       mrg 	ungetc(ch, fp);
    257       1.2       mrg 	while (fgets(ibuf, sizeof(ibuf) - 2, fp)) {
    258       1.1       mrg 	    if (split_at(ibuf, '\n'))
    259       1.2       mrg 		strcat(ibuf, "\r\n");	/* XXX strcat is safe */
    260       1.1       mrg 	    percent_x(obuf, sizeof(obuf), ibuf, request);
    261       1.1       mrg 	    write(request->fd, obuf, strlen(obuf));
    262       1.1       mrg 	}
    263       1.1       mrg 	fclose(fp);
    264       1.1       mrg     } else if (stat(value, &st) < 0) {
    265       1.1       mrg 	tcpd_warn("%s: %m", value);
    266       1.1       mrg     }
    267       1.1       mrg }
    268       1.1       mrg 
    269       1.1       mrg /* group_option - switch group id */
    270       1.1       mrg 
    271       1.1       mrg /* ARGSUSED */
    272       1.1       mrg 
    273       1.1       mrg static void group_option(value, request)
    274       1.1       mrg char   *value;
    275       1.1       mrg struct request_info *request;
    276       1.1       mrg {
    277       1.1       mrg     struct group *grp;
    278       1.1       mrg 
    279       1.1       mrg     if ((grp = getgrnam(value)) == 0)
    280       1.1       mrg 	tcpd_jump("unknown group: \"%s\"", value);
    281       1.1       mrg     endgrent();
    282       1.1       mrg 
    283       1.1       mrg     if (dry_run == 0 && setgid(grp->gr_gid))
    284       1.1       mrg 	tcpd_jump("setgid(%s): %m", value);
    285       1.1       mrg }
    286       1.1       mrg 
    287       1.1       mrg /* user_option - switch user id */
    288       1.1       mrg 
    289       1.1       mrg /* ARGSUSED */
    290       1.1       mrg 
    291       1.1       mrg static void user_option(value, request)
    292       1.1       mrg char   *value;
    293       1.1       mrg struct request_info *request;
    294       1.1       mrg {
    295  1.11.6.1      tron     struct passwd *pwd, pws;
    296       1.1       mrg     char   *group;
    297  1.11.6.1      tron     char   pwbuf[1024];
    298       1.1       mrg 
    299       1.1       mrg     if ((group = split_at(value, '.')) != 0)
    300       1.1       mrg 	group_option(group, request);
    301  1.11.6.1      tron     if (getpwnam_r(value, &pws, pwbuf, sizeof(pwbuf), &pwd) != 0)
    302       1.1       mrg 	tcpd_jump("unknown user: \"%s\"", value);
    303       1.1       mrg     endpwent();
    304       1.1       mrg 
    305       1.1       mrg     if (dry_run == 0 && setuid(pwd->pw_uid))
    306       1.1       mrg 	tcpd_jump("setuid(%s): %m", value);
    307       1.1       mrg }
    308       1.1       mrg 
    309       1.1       mrg /* umask_option - set file creation mask */
    310       1.1       mrg 
    311       1.1       mrg /* ARGSUSED */
    312       1.1       mrg 
    313       1.1       mrg static void umask_option(value, request)
    314       1.1       mrg char   *value;
    315       1.1       mrg struct request_info *request;
    316       1.1       mrg {
    317       1.1       mrg     unsigned mask;
    318       1.1       mrg     char    junk;
    319       1.1       mrg 
    320       1.1       mrg     if (sscanf(value, "%o%c", &mask, &junk) != 1 || (mask & 0777) != mask)
    321       1.1       mrg 	tcpd_jump("bad umask value: \"%s\"", value);
    322       1.1       mrg     (void) umask(mask);
    323       1.1       mrg }
    324       1.1       mrg 
    325       1.1       mrg /* spawn_option - spawn a shell command and wait */
    326       1.1       mrg 
    327       1.1       mrg /* ARGSUSED */
    328       1.1       mrg 
    329       1.1       mrg static void spawn_option(value, request)
    330       1.1       mrg char   *value;
    331       1.1       mrg struct request_info *request;
    332       1.1       mrg {
    333       1.1       mrg     if (dry_run == 0)
    334       1.1       mrg 	shell_cmd(value);
    335       1.1       mrg }
    336       1.1       mrg 
    337       1.1       mrg /* linger_option - set the socket linger time (Marc Boucher <marc (at) cam.org>) */
    338       1.1       mrg 
    339       1.1       mrg /* ARGSUSED */
    340       1.1       mrg 
    341       1.1       mrg static void linger_option(value, request)
    342       1.1       mrg char   *value;
    343       1.1       mrg struct request_info *request;
    344       1.1       mrg {
    345       1.1       mrg     struct linger linger;
    346       1.1       mrg     char    junk;
    347       1.1       mrg 
    348       1.1       mrg     if (sscanf(value, "%d%c", &linger.l_linger, &junk) != 1
    349       1.1       mrg 	|| linger.l_linger < 0)
    350       1.1       mrg 	tcpd_jump("bad linger value: \"%s\"", value);
    351       1.1       mrg     if (dry_run == 0) {
    352       1.1       mrg 	linger.l_onoff = (linger.l_linger != 0);
    353       1.1       mrg 	if (setsockopt(request->fd, SOL_SOCKET, SO_LINGER, (char *) &linger,
    354       1.1       mrg 		       sizeof(linger)) < 0)
    355       1.1       mrg 	    tcpd_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
    356       1.1       mrg     }
    357       1.1       mrg }
    358       1.1       mrg 
    359       1.1       mrg /* keepalive_option - set the socket keepalive option */
    360       1.1       mrg 
    361       1.1       mrg /* ARGSUSED */
    362       1.1       mrg 
    363       1.1       mrg static void keepalive_option(value, request)
    364       1.1       mrg char   *value;
    365       1.1       mrg struct request_info *request;
    366       1.1       mrg {
    367       1.1       mrg     static int on = 1;
    368       1.1       mrg 
    369       1.1       mrg     if (dry_run == 0 && setsockopt(request->fd, SOL_SOCKET, SO_KEEPALIVE,
    370       1.1       mrg 				   (char *) &on, sizeof(on)) < 0)
    371       1.1       mrg 	tcpd_warn("setsockopt SO_KEEPALIVE: %m");
    372       1.1       mrg }
    373       1.1       mrg 
    374       1.1       mrg /* nice_option - set nice value */
    375       1.1       mrg 
    376       1.1       mrg /* ARGSUSED */
    377       1.1       mrg 
    378       1.1       mrg static void nice_option(value, request)
    379       1.1       mrg char   *value;
    380       1.1       mrg struct request_info *request;
    381       1.1       mrg {
    382       1.1       mrg     int     niceval = 10;
    383       1.1       mrg     char    junk;
    384       1.1       mrg 
    385       1.1       mrg     if (value != 0 && sscanf(value, "%d%c", &niceval, &junk) != 1)
    386       1.1       mrg 	tcpd_jump("bad nice value: \"%s\"", value);
    387       1.1       mrg     if (dry_run == 0 && nice(niceval) < 0)
    388       1.1       mrg 	tcpd_warn("nice(%d): %m", niceval);
    389       1.1       mrg }
    390       1.1       mrg 
    391       1.1       mrg /* twist_option - replace process by shell command */
    392       1.1       mrg 
    393       1.1       mrg static void twist_option(value, request)
    394       1.1       mrg char   *value;
    395       1.1       mrg struct request_info *request;
    396       1.1       mrg {
    397       1.1       mrg     if (dry_run != 0) {
    398       1.1       mrg 	dry_run = 0;
    399       1.1       mrg     } else {
    400       1.1       mrg 	if (resident > 0)
    401       1.1       mrg 	    tcpd_jump("twist option in resident process");
    402       1.1       mrg 
    403       1.1       mrg 	syslog(deny_severity, "twist %s to %s", eval_client(request), value);
    404       1.1       mrg 
    405       1.1       mrg 	/* Before switching to the shell, set up stdin, stdout and stderr. */
    406       1.1       mrg 
    407       1.1       mrg #define maybe_dup2(from, to) ((from == to) ? to : (close(to), dup(from)))
    408       1.1       mrg 
    409       1.1       mrg 	if (maybe_dup2(request->fd, 0) != 0 ||
    410       1.1       mrg 	    maybe_dup2(request->fd, 1) != 1 ||
    411       1.1       mrg 	    maybe_dup2(request->fd, 2) != 2) {
    412      1.10  sommerfe 	    tcpd_warn("twist_option: dup: %m");
    413       1.1       mrg 	} else {
    414       1.1       mrg 	    if (request->fd > 2)
    415       1.1       mrg 		close(request->fd);
    416       1.1       mrg 	    (void) execl("/bin/sh", "sh", "-c", value, (char *) 0);
    417      1.10  sommerfe 	    tcpd_warn("twist_option: /bin/sh: %m");
    418       1.1       mrg 	}
    419       1.1       mrg 
    420       1.1       mrg 	/* Something went wrong: we MUST terminate the process. */
    421       1.1       mrg 	clean_exit(request);
    422       1.1       mrg     }
    423       1.1       mrg }
    424       1.1       mrg 
    425       1.1       mrg /* rfc931_option - look up remote user name */
    426       1.1       mrg 
    427       1.1       mrg static void rfc931_option(value, request)
    428       1.1       mrg char   *value;
    429       1.1       mrg struct request_info *request;
    430       1.1       mrg {
    431       1.1       mrg     int     timeout;
    432       1.1       mrg     char    junk;
    433       1.1       mrg 
    434       1.1       mrg     if (value != 0) {
    435       1.1       mrg 	if (sscanf(value, "%d%c", &timeout, &junk) != 1 || timeout <= 0)
    436       1.1       mrg 	    tcpd_jump("bad rfc931 timeout: \"%s\"", value);
    437       1.1       mrg 	rfc931_timeout = timeout;
    438       1.1       mrg     }
    439       1.1       mrg     (void) eval_user(request);
    440       1.1       mrg }
    441       1.1       mrg 
    442       1.1       mrg /* setenv_option - set environment variable */
    443       1.1       mrg 
    444       1.1       mrg /* ARGSUSED */
    445       1.1       mrg 
    446       1.1       mrg static void setenv_option(value, request)
    447       1.1       mrg char   *value;
    448       1.1       mrg struct request_info *request;
    449       1.1       mrg {
    450       1.1       mrg     char   *var_value;
    451       1.1       mrg 
    452       1.1       mrg     if (*(var_value = value + strcspn(value, whitespace)))
    453       1.1       mrg 	*var_value++ = 0;
    454       1.1       mrg     if (setenv(chop_string(value), chop_string(var_value), 1))
    455       1.1       mrg 	tcpd_jump("memory allocation failure");
    456       1.1       mrg }
    457       1.1       mrg 
    458       1.1       mrg  /*
    459       1.1       mrg   * The severity option goes last because it comes with a huge amount of ugly
    460       1.1       mrg   * #ifdefs and tables.
    461       1.1       mrg   */
    462       1.1       mrg 
    463       1.1       mrg struct syslog_names {
    464       1.1       mrg     char   *name;
    465       1.1       mrg     int     value;
    466       1.1       mrg };
    467       1.1       mrg 
    468       1.1       mrg static struct syslog_names log_fac[] = {
    469       1.1       mrg #ifdef LOG_KERN
    470       1.3  christos     { "kern", LOG_KERN },
    471       1.1       mrg #endif
    472       1.1       mrg #ifdef LOG_USER
    473       1.3  christos     { "user", LOG_USER },
    474       1.1       mrg #endif
    475       1.1       mrg #ifdef LOG_MAIL
    476       1.3  christos     { "mail", LOG_MAIL },
    477       1.1       mrg #endif
    478       1.1       mrg #ifdef LOG_DAEMON
    479       1.3  christos     { "daemon", LOG_DAEMON },
    480       1.1       mrg #endif
    481       1.1       mrg #ifdef LOG_AUTH
    482       1.3  christos     { "auth", LOG_AUTH },
    483       1.1       mrg #endif
    484       1.1       mrg #ifdef LOG_LPR
    485       1.3  christos     { "lpr", LOG_LPR },
    486       1.1       mrg #endif
    487       1.1       mrg #ifdef LOG_NEWS
    488       1.3  christos     { "news", LOG_NEWS },
    489       1.1       mrg #endif
    490       1.1       mrg #ifdef LOG_UUCP
    491       1.3  christos     { "uucp", LOG_UUCP },
    492       1.1       mrg #endif
    493       1.1       mrg #ifdef LOG_CRON
    494       1.3  christos     { "cron", LOG_CRON },
    495       1.4        tv #endif
    496       1.4        tv #ifdef LOG_AUTHPRIV
    497       1.4        tv     { "authpriv", LOG_AUTHPRIV },
    498       1.4        tv #endif
    499       1.4        tv #ifdef LOG_FTP
    500       1.4        tv     { "ftp", LOG_FTP },
    501       1.1       mrg #endif
    502       1.1       mrg #ifdef LOG_LOCAL0
    503       1.3  christos     { "local0", LOG_LOCAL0 },
    504       1.1       mrg #endif
    505       1.1       mrg #ifdef LOG_LOCAL1
    506       1.3  christos     { "local1", LOG_LOCAL1 },
    507       1.1       mrg #endif
    508       1.1       mrg #ifdef LOG_LOCAL2
    509       1.3  christos     { "local2", LOG_LOCAL2 },
    510       1.1       mrg #endif
    511       1.1       mrg #ifdef LOG_LOCAL3
    512       1.3  christos     { "local3", LOG_LOCAL3 },
    513       1.1       mrg #endif
    514       1.1       mrg #ifdef LOG_LOCAL4
    515       1.3  christos     { "local4", LOG_LOCAL4 },
    516       1.1       mrg #endif
    517       1.1       mrg #ifdef LOG_LOCAL5
    518       1.3  christos     { "local5", LOG_LOCAL5 },
    519       1.1       mrg #endif
    520       1.1       mrg #ifdef LOG_LOCAL6
    521       1.3  christos     { "local6", LOG_LOCAL6 },
    522       1.1       mrg #endif
    523       1.1       mrg #ifdef LOG_LOCAL7
    524       1.3  christos     { "local7", LOG_LOCAL7 },
    525       1.1       mrg #endif
    526       1.3  christos     { NULL, 0 }
    527       1.1       mrg };
    528       1.1       mrg 
    529       1.1       mrg static struct syslog_names log_sev[] = {
    530       1.1       mrg #ifdef LOG_EMERG
    531       1.3  christos     { "emerg", LOG_EMERG },
    532       1.1       mrg #endif
    533       1.1       mrg #ifdef LOG_ALERT
    534       1.3  christos     { "alert", LOG_ALERT },
    535       1.1       mrg #endif
    536       1.1       mrg #ifdef LOG_CRIT
    537       1.3  christos     { "crit", LOG_CRIT },
    538       1.1       mrg #endif
    539       1.1       mrg #ifdef LOG_ERR
    540       1.3  christos     { "err", LOG_ERR },
    541       1.1       mrg #endif
    542       1.1       mrg #ifdef LOG_WARNING
    543       1.3  christos     { "warning", LOG_WARNING },
    544       1.1       mrg #endif
    545       1.1       mrg #ifdef LOG_NOTICE
    546       1.3  christos     { "notice", LOG_NOTICE },
    547       1.1       mrg #endif
    548       1.1       mrg #ifdef LOG_INFO
    549       1.3  christos     { "info", LOG_INFO },
    550       1.1       mrg #endif
    551       1.1       mrg #ifdef LOG_DEBUG
    552       1.3  christos     { "debug", LOG_DEBUG },
    553       1.1       mrg #endif
    554       1.3  christos     { NULL, 0 }
    555       1.1       mrg };
    556       1.1       mrg 
    557       1.1       mrg /* severity_map - lookup facility or severity value */
    558       1.1       mrg 
    559       1.1       mrg static int severity_map(table, name)
    560       1.1       mrg struct syslog_names *table;
    561       1.1       mrg char   *name;
    562       1.1       mrg {
    563       1.1       mrg     struct syslog_names *t;
    564       1.1       mrg 
    565       1.1       mrg     for (t = table; t->name; t++)
    566       1.1       mrg 	if (STR_EQ(t->name, name))
    567       1.1       mrg 	    return (t->value);
    568       1.1       mrg     tcpd_jump("bad syslog facility or severity: \"%s\"", name);
    569       1.1       mrg     /* NOTREACHED */
    570       1.3  christos     return -1;
    571       1.1       mrg }
    572       1.1       mrg 
    573       1.1       mrg /* severity_option - change logging severity for this event (Dave Mitchell) */
    574       1.1       mrg 
    575       1.1       mrg /* ARGSUSED */
    576       1.1       mrg 
    577       1.1       mrg static void severity_option(value, request)
    578       1.1       mrg char   *value;
    579       1.1       mrg struct request_info *request;
    580       1.1       mrg {
    581       1.1       mrg     char   *level = split_at(value, '.');
    582       1.1       mrg 
    583       1.1       mrg     allow_severity = deny_severity = level ?
    584       1.1       mrg 	severity_map(log_fac, value) | severity_map(log_sev, level) :
    585       1.1       mrg 	severity_map(log_sev, value);
    586       1.1       mrg }
    587       1.1       mrg 
    588       1.1       mrg /* get_field - return pointer to next field in string */
    589       1.1       mrg 
    590       1.1       mrg static char *get_field(string)
    591       1.1       mrg char   *string;
    592       1.1       mrg {
    593       1.1       mrg     static char *last = "";
    594       1.1       mrg     char   *src;
    595       1.1       mrg     char   *dst;
    596       1.1       mrg     char   *ret;
    597       1.1       mrg     int     ch;
    598       1.1       mrg 
    599       1.1       mrg     /*
    600       1.1       mrg      * This function returns pointers to successive fields within a given
    601       1.1       mrg      * string. ":" is the field separator; warn if the rule ends in one. It
    602       1.1       mrg      * replaces a "\:" sequence by ":", without treating the result of
    603       1.1       mrg      * substitution as field terminator. A null argument means resume search
    604       1.1       mrg      * where the previous call terminated. This function destroys its
    605       1.1       mrg      * argument.
    606       1.6    simonb      *
    607       1.1       mrg      * Work from explicit source or from memory. While processing \: we
    608       1.1       mrg      * overwrite the input. This way we do not have to maintain buffers for
    609       1.1       mrg      * copies of input fields.
    610       1.1       mrg      */
    611       1.1       mrg 
    612       1.1       mrg     src = dst = ret = (string ? string : last);
    613       1.1       mrg     if (src[0] == 0)
    614       1.1       mrg 	return (0);
    615       1.1       mrg 
    616       1.3  christos     while ((ch = *src) != '\0') {
    617       1.1       mrg 	if (ch == ':') {
    618       1.1       mrg 	    if (*++src == 0)
    619       1.1       mrg 		tcpd_warn("rule ends in \":\"");
    620       1.1       mrg 	    break;
    621       1.1       mrg 	}
    622       1.1       mrg 	if (ch == '\\' && src[1] == ':')
    623       1.1       mrg 	    src++;
    624       1.1       mrg 	*dst++ = *src++;
    625       1.1       mrg     }
    626       1.1       mrg     last = src;
    627       1.1       mrg     *dst = 0;
    628       1.1       mrg     return (ret);
    629       1.1       mrg }
    630       1.1       mrg 
    631       1.1       mrg /* chop_string - strip leading and trailing blanks from string */
    632       1.1       mrg 
    633       1.1       mrg static char *chop_string(string)
    634       1.1       mrg register char *string;
    635       1.1       mrg {
    636       1.3  christos     char   *start = NULL;
    637       1.3  christos     char   *end = NULL;
    638       1.1       mrg     char   *cp;
    639       1.1       mrg 
    640       1.1       mrg     for (cp = string; *cp; cp++) {
    641       1.9     itohy 	if (!isspace((unsigned char) *cp)) {
    642       1.1       mrg 	    if (start == 0)
    643       1.1       mrg 		start = cp;
    644       1.1       mrg 	    end = cp;
    645       1.1       mrg 	}
    646       1.1       mrg     }
    647       1.1       mrg     return (start ? (end[1] = 0, start) : cp);
    648       1.1       mrg }
    649