xref: /freebsd/contrib/tcp_wrappers/options.c (revision 8297ff13fb604c86797e6a66bc654caff2cf3ce2)
12aef6930SMark Murray  /*
22aef6930SMark Murray   * General skeleton for adding options to the access control language. The
32aef6930SMark Murray   * features offered by this module are documented in the hosts_options(5)
42aef6930SMark Murray   * manual page (source file: hosts_options.5, "nroff -man" format).
52aef6930SMark Murray   *
62aef6930SMark Murray   * Notes and warnings for those who want to add features:
72aef6930SMark Murray   *
82aef6930SMark Murray   * In case of errors, abort options processing and deny access. There are too
92aef6930SMark Murray   * many irreversible side effects to make error recovery feasible. For
102aef6930SMark Murray   * example, it makes no sense to continue after we have already changed the
112aef6930SMark Murray   * userid.
122aef6930SMark Murray   *
132aef6930SMark Murray   * In case of errors, do not terminate the process: the routines might be
142aef6930SMark Murray   * called from a long-running daemon that should run forever. Instead, call
152aef6930SMark Murray   * tcpd_jump() which does a non-local goto back into the hosts_access()
162aef6930SMark Murray   * routine.
172aef6930SMark Murray   *
182aef6930SMark Murray   * In case of severe errors, use clean_exit() instead of directly calling
192aef6930SMark Murray   * exit(), or the inetd may loop on an UDP request.
202aef6930SMark Murray   *
212aef6930SMark Murray   * In verification mode (for example, with the "tcpdmatch" command) the
222aef6930SMark Murray   * "dry_run" flag is set. In this mode, an option function should just "say"
232aef6930SMark Murray   * what it is going to do instead of really doing it.
242aef6930SMark Murray   *
252aef6930SMark Murray   * Some option functions do not return (for example, the twist option passes
262aef6930SMark Murray   * control to another program). In verification mode (dry_run flag is set)
272aef6930SMark Murray   * such options should clear the "dry_run" flag to inform the caller of this
282aef6930SMark Murray   * course of action.
29b8980b27SDavid Malone   *
30b8980b27SDavid Malone   * $FreeBSD$
312aef6930SMark Murray   */
322aef6930SMark Murray 
332aef6930SMark Murray #ifndef lint
342aef6930SMark Murray static char sccsid[] = "@(#) options.c 1.17 96/02/11 17:01:31";
352aef6930SMark Murray #endif
362aef6930SMark Murray 
372aef6930SMark Murray /* System libraries. */
382aef6930SMark Murray 
392aef6930SMark Murray #include <sys/types.h>
402aef6930SMark Murray #include <sys/param.h>
412aef6930SMark Murray #include <sys/socket.h>
422aef6930SMark Murray #include <sys/stat.h>
432aef6930SMark Murray #include <netinet/in.h>
442aef6930SMark Murray #include <netdb.h>
452aef6930SMark Murray #include <stdio.h>
46b8980b27SDavid Malone #define SYSLOG_NAMES
472aef6930SMark Murray #include <syslog.h>
482aef6930SMark Murray #include <pwd.h>
492aef6930SMark Murray #include <grp.h>
502aef6930SMark Murray #include <ctype.h>
512aef6930SMark Murray #include <setjmp.h>
522aef6930SMark Murray #include <string.h>
5346bcf11dSSean Bruno #include <unistd.h>
5446bcf11dSSean Bruno #include <stdlib.h>
552aef6930SMark Murray 
562aef6930SMark Murray #ifndef MAXPATHNAMELEN
572aef6930SMark Murray #define MAXPATHNAMELEN  BUFSIZ
582aef6930SMark Murray #endif
592aef6930SMark Murray 
602aef6930SMark Murray /* Local stuff. */
612aef6930SMark Murray 
622aef6930SMark Murray #include "tcpd.h"
632aef6930SMark Murray 
642aef6930SMark Murray /* Options runtime support. */
652aef6930SMark Murray 
662aef6930SMark Murray int     dry_run = 0;			/* flag set in verification mode */
672aef6930SMark Murray extern jmp_buf tcpd_buf;		/* tcpd_jump() support */
682aef6930SMark Murray 
692aef6930SMark Murray /* Options parser support. */
702aef6930SMark Murray 
712aef6930SMark Murray static char whitespace_eq[] = "= \t\r\n";
722aef6930SMark Murray #define whitespace (whitespace_eq + 1)
732aef6930SMark Murray 
74068ad27dSBrooks Davis static char *get_field(char *string);		/* chew :-delimited field off string */
75068ad27dSBrooks Davis static char *chop_string(char *string);		/* strip leading and trailing blanks */
762aef6930SMark Murray 
772aef6930SMark Murray /* List of functions that implement the options. Add yours here. */
782aef6930SMark Murray 
79*8297ff13SPiotr Pawel Stefaniak static void user_option(char *, struct request_info *);		/* user name.group */
80*8297ff13SPiotr Pawel Stefaniak static void group_option(char *, struct request_info *);	/* group name */
81*8297ff13SPiotr Pawel Stefaniak static void umask_option(char *, struct request_info *);	/* umask mask */
82*8297ff13SPiotr Pawel Stefaniak static void linger_option(char *, struct request_info *);	/* linger time */
83*8297ff13SPiotr Pawel Stefaniak static void keepalive_option(char *, struct request_info *);	/* keepalive */
84*8297ff13SPiotr Pawel Stefaniak static void spawn_option(char *, struct request_info *);	/* spawn command */
85*8297ff13SPiotr Pawel Stefaniak static void twist_option(char *, struct request_info *);	/* twist command */
86*8297ff13SPiotr Pawel Stefaniak static void rfc931_option(char *, struct request_info *);	/* rfc931 */
87*8297ff13SPiotr Pawel Stefaniak static void setenv_option(char *, struct request_info *);	/* setenv name value */
88*8297ff13SPiotr Pawel Stefaniak static void nice_option(char *, struct request_info *);		/* nice */
89*8297ff13SPiotr Pawel Stefaniak static void severity_option(char *, struct request_info *);	/* severity value */
90*8297ff13SPiotr Pawel Stefaniak static void allow_option(char *, struct request_info *);	/* allow */
91*8297ff13SPiotr Pawel Stefaniak static void deny_option(char *, struct request_info *);		/* deny */
92*8297ff13SPiotr Pawel Stefaniak static void banners_option(char *, struct request_info *);	/* banners path */
932aef6930SMark Murray 
942aef6930SMark Murray /* Structure of the options table. */
952aef6930SMark Murray 
962aef6930SMark Murray struct option {
972aef6930SMark Murray     char   *name;			/* keyword name, case is ignored */
9814f102eaSEd Maste     void  (*func) (char *value, struct request_info *request);
9914f102eaSEd Maste 					/* function that does the real work */
1002aef6930SMark Murray     int     flags;			/* see below... */
1012aef6930SMark Murray };
1022aef6930SMark Murray 
1032aef6930SMark Murray #define NEED_ARG	(1<<1)		/* option requires argument */
1042aef6930SMark Murray #define USE_LAST	(1<<2)		/* option must be last */
1052aef6930SMark Murray #define OPT_ARG		(1<<3)		/* option has optional argument */
1062aef6930SMark Murray #define EXPAND_ARG	(1<<4)		/* do %x expansion on argument */
1072aef6930SMark Murray 
1082aef6930SMark Murray #define need_arg(o)	((o)->flags & NEED_ARG)
1092aef6930SMark Murray #define opt_arg(o)	((o)->flags & OPT_ARG)
1102aef6930SMark Murray #define permit_arg(o)	((o)->flags & (NEED_ARG | OPT_ARG))
1112aef6930SMark Murray #define use_last(o)	((o)->flags & USE_LAST)
1122aef6930SMark Murray #define expand_arg(o)	((o)->flags & EXPAND_ARG)
1132aef6930SMark Murray 
1142aef6930SMark Murray /* List of known keywords. Add yours here. */
1152aef6930SMark Murray 
1162aef6930SMark Murray static struct option option_table[] = {
1172aef6930SMark Murray     "user", user_option, NEED_ARG,
1182aef6930SMark Murray     "group", group_option, NEED_ARG,
1192aef6930SMark Murray     "umask", umask_option, NEED_ARG,
1202aef6930SMark Murray     "linger", linger_option, NEED_ARG,
1212aef6930SMark Murray     "keepalive", keepalive_option, 0,
1222aef6930SMark Murray     "spawn", spawn_option, NEED_ARG | EXPAND_ARG,
1232aef6930SMark Murray     "twist", twist_option, NEED_ARG | EXPAND_ARG | USE_LAST,
1242aef6930SMark Murray     "rfc931", rfc931_option, OPT_ARG,
1252aef6930SMark Murray     "setenv", setenv_option, NEED_ARG | EXPAND_ARG,
1262aef6930SMark Murray     "nice", nice_option, OPT_ARG,
1272aef6930SMark Murray     "severity", severity_option, NEED_ARG,
1282aef6930SMark Murray     "allow", allow_option, USE_LAST,
1292aef6930SMark Murray     "deny", deny_option, USE_LAST,
1302aef6930SMark Murray     "banners", banners_option, NEED_ARG,
1312aef6930SMark Murray     0,
1322aef6930SMark Murray };
1332aef6930SMark Murray 
1342aef6930SMark Murray /* process_options - process access control options */
1352aef6930SMark Murray 
process_options(char * options,struct request_info * request)13614f102eaSEd Maste void    process_options(char *options, struct request_info *request)
1372aef6930SMark Murray {
1382aef6930SMark Murray     char   *key;
1392aef6930SMark Murray     char   *value;
1402aef6930SMark Murray     char   *curr_opt;
1412aef6930SMark Murray     char   *next_opt;
1422aef6930SMark Murray     struct option *op;
1432aef6930SMark Murray     char    bf[BUFSIZ];
1442aef6930SMark Murray 
1452aef6930SMark Murray     for (curr_opt = get_field(options); curr_opt; curr_opt = next_opt) {
1462aef6930SMark Murray 	next_opt = get_field((char *) 0);
1472aef6930SMark Murray 
1482aef6930SMark Murray 	/*
1492aef6930SMark Murray 	 * Separate the option into name and value parts. For backwards
1502aef6930SMark Murray 	 * compatibility we ignore exactly one '=' between name and value.
1512aef6930SMark Murray 	 */
1522aef6930SMark Murray 	curr_opt = chop_string(curr_opt);
1532aef6930SMark Murray 	if (*(value = curr_opt + strcspn(curr_opt, whitespace_eq))) {
1542aef6930SMark Murray 	    if (*value != '=') {
1552aef6930SMark Murray 		*value++ = 0;
1562aef6930SMark Murray 		value += strspn(value, whitespace);
1572aef6930SMark Murray 	    }
1582aef6930SMark Murray 	    if (*value == '=') {
1592aef6930SMark Murray 		*value++ = 0;
1602aef6930SMark Murray 		value += strspn(value, whitespace);
1612aef6930SMark Murray 	    }
1622aef6930SMark Murray 	}
1632aef6930SMark Murray 	if (*value == 0)
1642aef6930SMark Murray 	    value = 0;
1652aef6930SMark Murray 	key = curr_opt;
1662aef6930SMark Murray 
1672aef6930SMark Murray 	/*
1682aef6930SMark Murray 	 * Disallow missing option names (and empty option fields).
1692aef6930SMark Murray 	 */
1702aef6930SMark Murray 	if (*key == 0)
1712aef6930SMark Murray 	    tcpd_jump("missing option name");
1722aef6930SMark Murray 
1732aef6930SMark Murray 	/*
1742aef6930SMark Murray 	 * Lookup the option-specific info and do some common error checks.
1752aef6930SMark Murray 	 * Delegate option-specific processing to the specific functions.
1762aef6930SMark Murray 	 */
1772aef6930SMark Murray 
1782aef6930SMark Murray 	for (op = option_table; op->name && STR_NE(op->name, key); op++)
1792aef6930SMark Murray 	     /* VOID */ ;
1802aef6930SMark Murray 	if (op->name == 0)
1812aef6930SMark Murray 	    tcpd_jump("bad option name: \"%s\"", key);
1822aef6930SMark Murray 	if (!value && need_arg(op))
1832aef6930SMark Murray 	    tcpd_jump("option \"%s\" requires value", key);
1842aef6930SMark Murray 	if (value && !permit_arg(op))
1852aef6930SMark Murray 	    tcpd_jump("option \"%s\" requires no value", key);
1862aef6930SMark Murray 	if (next_opt && use_last(op))
1872aef6930SMark Murray 	    tcpd_jump("option \"%s\" must be at end", key);
1882aef6930SMark Murray 	if (value && expand_arg(op))
1892aef6930SMark Murray 	    value = chop_string(percent_x(bf, sizeof(bf), value, request));
1902aef6930SMark Murray 	if (hosts_access_verbose)
1912aef6930SMark Murray 	    syslog(LOG_DEBUG, "option:   %s %s", key, value ? value : "");
1922aef6930SMark Murray 	(*(op->func)) (value, request);
1932aef6930SMark Murray     }
1942aef6930SMark Murray }
1952aef6930SMark Murray 
1962aef6930SMark Murray /* allow_option - grant access */
1972aef6930SMark Murray 
1982aef6930SMark Murray /* ARGSUSED */
1992aef6930SMark Murray 
allow_option(char * value,struct request_info * request)200*8297ff13SPiotr Pawel Stefaniak static void allow_option(char *value, struct request_info *request)
2012aef6930SMark Murray {
2022aef6930SMark Murray     longjmp(tcpd_buf, AC_PERMIT);
2032aef6930SMark Murray }
2042aef6930SMark Murray 
2052aef6930SMark Murray /* deny_option - deny access */
2062aef6930SMark Murray 
2072aef6930SMark Murray /* ARGSUSED */
2082aef6930SMark Murray 
deny_option(char * value,struct request_info * request)209*8297ff13SPiotr Pawel Stefaniak static void deny_option(char *value, struct request_info *request)
2102aef6930SMark Murray {
2112aef6930SMark Murray     longjmp(tcpd_buf, AC_DENY);
2122aef6930SMark Murray }
2132aef6930SMark Murray 
2142aef6930SMark Murray /* banners_option - expand %<char>, terminate each line with CRLF */
2152aef6930SMark Murray 
banners_option(char * value,struct request_info * request)21614f102eaSEd Maste static void banners_option(char *value, struct request_info *request)
2172aef6930SMark Murray {
2182aef6930SMark Murray     char    path[MAXPATHNAMELEN];
2192aef6930SMark Murray     char    ibuf[BUFSIZ];
2202aef6930SMark Murray     char    obuf[2 * BUFSIZ];
2212aef6930SMark Murray     struct stat st;
2222aef6930SMark Murray     int     ch;
2232aef6930SMark Murray     FILE   *fp;
2242aef6930SMark Murray 
2252aef6930SMark Murray     sprintf(path, "%s/%s", value, eval_daemon(request));
2262aef6930SMark Murray     if ((fp = fopen(path, "r")) != 0) {
2272aef6930SMark Murray 	while ((ch = fgetc(fp)) == 0)
2282aef6930SMark Murray 	    write(request->fd, "", 1);
2292aef6930SMark Murray 	ungetc(ch, fp);
2302aef6930SMark Murray 	while (fgets(ibuf, sizeof(ibuf) - 1, fp)) {
2312aef6930SMark Murray 	    if (split_at(ibuf, '\n'))
2322aef6930SMark Murray 		strcat(ibuf, "\r\n");
2332aef6930SMark Murray 	    percent_x(obuf, sizeof(obuf), ibuf, request);
2342aef6930SMark Murray 	    write(request->fd, obuf, strlen(obuf));
2352aef6930SMark Murray 	}
2362aef6930SMark Murray 	fclose(fp);
2372aef6930SMark Murray     } else if (stat(value, &st) < 0) {
2382aef6930SMark Murray 	tcpd_warn("%s: %m", value);
2392aef6930SMark Murray     }
2402aef6930SMark Murray }
2412aef6930SMark Murray 
2422aef6930SMark Murray /* group_option - switch group id */
2432aef6930SMark Murray 
2442aef6930SMark Murray /* ARGSUSED */
2452aef6930SMark Murray 
group_option(char * value,struct request_info * request)24614f102eaSEd Maste static void group_option(char *value, struct request_info *request)
2472aef6930SMark Murray {
2482aef6930SMark Murray     struct group *grp;
2492aef6930SMark Murray 
2502aef6930SMark Murray     if ((grp = getgrnam(value)) == 0)
2512aef6930SMark Murray 	tcpd_jump("unknown group: \"%s\"", value);
2522aef6930SMark Murray     endgrent();
2532aef6930SMark Murray 
2542aef6930SMark Murray     if (dry_run == 0 && setgid(grp->gr_gid))
2552aef6930SMark Murray 	tcpd_jump("setgid(%s): %m", value);
2562aef6930SMark Murray }
2572aef6930SMark Murray 
2582aef6930SMark Murray /* user_option - switch user id */
2592aef6930SMark Murray 
2602aef6930SMark Murray /* ARGSUSED */
2612aef6930SMark Murray 
user_option(char * value,struct request_info * request)26214f102eaSEd Maste static void user_option(char *value, struct request_info *request)
2632aef6930SMark Murray {
2642aef6930SMark Murray     struct passwd *pwd;
2652aef6930SMark Murray     char   *group;
2662aef6930SMark Murray 
2672aef6930SMark Murray     if ((group = split_at(value, '.')) != 0)
2682aef6930SMark Murray 	group_option(group, request);
2692aef6930SMark Murray     if ((pwd = getpwnam(value)) == 0)
2702aef6930SMark Murray 	tcpd_jump("unknown user: \"%s\"", value);
2712aef6930SMark Murray     endpwent();
2722aef6930SMark Murray 
2732aef6930SMark Murray     if (dry_run == 0 && setuid(pwd->pw_uid))
2742aef6930SMark Murray 	tcpd_jump("setuid(%s): %m", value);
2752aef6930SMark Murray }
2762aef6930SMark Murray 
2772aef6930SMark Murray /* umask_option - set file creation mask */
2782aef6930SMark Murray 
2792aef6930SMark Murray /* ARGSUSED */
2802aef6930SMark Murray 
umask_option(char * value,struct request_info * request)28114f102eaSEd Maste static void umask_option(char *value, struct request_info *request)
2822aef6930SMark Murray {
2832aef6930SMark Murray     unsigned mask;
2842aef6930SMark Murray     char    junk;
2852aef6930SMark Murray 
2862aef6930SMark Murray     if (sscanf(value, "%o%c", &mask, &junk) != 1 || (mask & 0777) != mask)
2872aef6930SMark Murray 	tcpd_jump("bad umask value: \"%s\"", value);
2882aef6930SMark Murray     (void) umask(mask);
2892aef6930SMark Murray }
2902aef6930SMark Murray 
2912aef6930SMark Murray /* spawn_option - spawn a shell command and wait */
2922aef6930SMark Murray 
2932aef6930SMark Murray /* ARGSUSED */
2942aef6930SMark Murray 
spawn_option(char * value,struct request_info * request)29514f102eaSEd Maste static void spawn_option(char *value, struct request_info *request)
2962aef6930SMark Murray {
2972aef6930SMark Murray     if (dry_run == 0)
2982aef6930SMark Murray 	shell_cmd(value);
2992aef6930SMark Murray }
3002aef6930SMark Murray 
3012aef6930SMark Murray /* linger_option - set the socket linger time (Marc Boucher <marc@cam.org>) */
3022aef6930SMark Murray 
3032aef6930SMark Murray /* ARGSUSED */
3042aef6930SMark Murray 
linger_option(char * value,struct request_info * request)30514f102eaSEd Maste static void linger_option(char *value, struct request_info *request)
3062aef6930SMark Murray {
3072aef6930SMark Murray     struct linger linger;
3082aef6930SMark Murray     char    junk;
3092aef6930SMark Murray 
3102aef6930SMark Murray     if (sscanf(value, "%d%c", &linger.l_linger, &junk) != 1
3112aef6930SMark Murray 	|| linger.l_linger < 0)
3122aef6930SMark Murray 	tcpd_jump("bad linger value: \"%s\"", value);
3132aef6930SMark Murray     if (dry_run == 0) {
3142aef6930SMark Murray 	linger.l_onoff = (linger.l_linger != 0);
3152aef6930SMark Murray 	if (setsockopt(request->fd, SOL_SOCKET, SO_LINGER, (char *) &linger,
3162aef6930SMark Murray 		       sizeof(linger)) < 0)
3172aef6930SMark Murray 	    tcpd_warn("setsockopt SO_LINGER %d: %m", linger.l_linger);
3182aef6930SMark Murray     }
3192aef6930SMark Murray }
3202aef6930SMark Murray 
3212aef6930SMark Murray /* keepalive_option - set the socket keepalive option */
3222aef6930SMark Murray 
3232aef6930SMark Murray /* ARGSUSED */
3242aef6930SMark Murray 
keepalive_option(char * value,struct request_info * request)32514f102eaSEd Maste static void keepalive_option(char *value, struct request_info *request)
3262aef6930SMark Murray {
3272aef6930SMark Murray     static int on = 1;
3282aef6930SMark Murray 
3292aef6930SMark Murray     if (dry_run == 0 && setsockopt(request->fd, SOL_SOCKET, SO_KEEPALIVE,
3302aef6930SMark Murray 				   (char *) &on, sizeof(on)) < 0)
3312aef6930SMark Murray 	tcpd_warn("setsockopt SO_KEEPALIVE: %m");
3322aef6930SMark Murray }
3332aef6930SMark Murray 
3342aef6930SMark Murray /* nice_option - set nice value */
3352aef6930SMark Murray 
3362aef6930SMark Murray /* ARGSUSED */
3372aef6930SMark Murray 
nice_option(char * value,struct request_info * request)33814f102eaSEd Maste static void nice_option(char *value, struct request_info *request)
3392aef6930SMark Murray {
3402aef6930SMark Murray     int     niceval = 10;
3412aef6930SMark Murray     char    junk;
3422aef6930SMark Murray 
3432aef6930SMark Murray     if (value != 0 && sscanf(value, "%d%c", &niceval, &junk) != 1)
3442aef6930SMark Murray 	tcpd_jump("bad nice value: \"%s\"", value);
3452aef6930SMark Murray     if (dry_run == 0 && nice(niceval) < 0)
3462aef6930SMark Murray 	tcpd_warn("nice(%d): %m", niceval);
3472aef6930SMark Murray }
3482aef6930SMark Murray 
3492aef6930SMark Murray /* twist_option - replace process by shell command */
3502aef6930SMark Murray 
twist_option(char * value,struct request_info * request)35114f102eaSEd Maste static void twist_option(char *value, struct request_info *request)
3522aef6930SMark Murray {
3532aef6930SMark Murray     char   *error;
3542aef6930SMark Murray 
3552aef6930SMark Murray     if (dry_run != 0) {
3562aef6930SMark Murray 	dry_run = 0;
3572aef6930SMark Murray     } else {
3582aef6930SMark Murray 	if (resident > 0)
3592aef6930SMark Murray 	    tcpd_jump("twist option in resident process");
3602aef6930SMark Murray 
3612aef6930SMark Murray 	syslog(deny_severity, "twist %s to %s", eval_client(request), value);
3622aef6930SMark Murray 
3632aef6930SMark Murray 	/* Before switching to the shell, set up stdin, stdout and stderr. */
3642aef6930SMark Murray 
3652aef6930SMark Murray #define maybe_dup2(from, to) ((from == to) ? to : (close(to), dup(from)))
3662aef6930SMark Murray 
3672aef6930SMark Murray 	if (maybe_dup2(request->fd, 0) != 0 ||
3682aef6930SMark Murray 	    maybe_dup2(request->fd, 1) != 1 ||
3692aef6930SMark Murray 	    maybe_dup2(request->fd, 2) != 2) {
3702aef6930SMark Murray 	    error = "twist_option: dup: %m";
3712aef6930SMark Murray 	} else {
3722aef6930SMark Murray 	    if (request->fd > 2)
3732aef6930SMark Murray 		close(request->fd);
3742aef6930SMark Murray 	    (void) execl("/bin/sh", "sh", "-c", value, (char *) 0);
3752aef6930SMark Murray 	    error = "twist_option: /bin/sh: %m";
3762aef6930SMark Murray 	}
3772aef6930SMark Murray 
3782aef6930SMark Murray 	/* Something went wrong: we MUST terminate the process. */
3792aef6930SMark Murray 
3802aef6930SMark Murray 	tcpd_warn(error);
3812aef6930SMark Murray 	clean_exit(request);
3822aef6930SMark Murray     }
3832aef6930SMark Murray }
3842aef6930SMark Murray 
3852aef6930SMark Murray /* rfc931_option - look up remote user name */
3862aef6930SMark Murray 
rfc931_option(char * value,struct request_info * request)38714f102eaSEd Maste static void rfc931_option(char *value, struct request_info *request)
3882aef6930SMark Murray {
3892aef6930SMark Murray     int     timeout;
3902aef6930SMark Murray     char    junk;
3912aef6930SMark Murray 
3922aef6930SMark Murray     if (value != 0) {
3932aef6930SMark Murray 	if (sscanf(value, "%d%c", &timeout, &junk) != 1 || timeout <= 0)
3942aef6930SMark Murray 	    tcpd_jump("bad rfc931 timeout: \"%s\"", value);
3952aef6930SMark Murray 	rfc931_timeout = timeout;
3962aef6930SMark Murray     }
3972aef6930SMark Murray     (void) eval_user(request);
3982aef6930SMark Murray }
3992aef6930SMark Murray 
4002aef6930SMark Murray /* setenv_option - set environment variable */
4012aef6930SMark Murray 
4022aef6930SMark Murray /* ARGSUSED */
4032aef6930SMark Murray 
setenv_option(char * value,struct request_info * request)40414f102eaSEd Maste static void setenv_option(char *value, struct request_info *request)
4052aef6930SMark Murray {
4062aef6930SMark Murray     char   *var_value;
4072aef6930SMark Murray 
4082aef6930SMark Murray     if (*(var_value = value + strcspn(value, whitespace)))
4092aef6930SMark Murray 	*var_value++ = 0;
4102aef6930SMark Murray     if (setenv(chop_string(value), chop_string(var_value), 1))
4112aef6930SMark Murray 	tcpd_jump("memory allocation failure");
4122aef6930SMark Murray }
4132aef6930SMark Murray 
4142aef6930SMark Murray /* severity_map - lookup facility or severity value */
4152aef6930SMark Murray 
severity_map(const CODE * table,char * name)41614f102eaSEd Maste static int severity_map(const CODE *table, char *name)
4172aef6930SMark Murray {
418bbaadbd7SSean Bruno     const CODE *t;
419bbaadbd7SSean Bruno     int ret = -1;
4202aef6930SMark Murray 
421b8980b27SDavid Malone     for (t = table; t->c_name; t++)
422bbaadbd7SSean Bruno 	if (STR_EQ(t->c_name, name)) {
423bbaadbd7SSean Bruno 	    ret = t->c_val;
424bbaadbd7SSean Bruno 	    break;
425bbaadbd7SSean Bruno 	}
426bbaadbd7SSean Bruno     if (ret == -1)
4272aef6930SMark Murray     	tcpd_jump("bad syslog facility or severity: \"%s\"", name);
428bbaadbd7SSean Bruno 
429bbaadbd7SSean Bruno     return (ret);
4302aef6930SMark Murray }
4312aef6930SMark Murray 
4322aef6930SMark Murray /* severity_option - change logging severity for this event (Dave Mitchell) */
4332aef6930SMark Murray 
4342aef6930SMark Murray /* ARGSUSED */
4352aef6930SMark Murray 
severity_option(char * value,struct request_info * request)43614f102eaSEd Maste static void severity_option(char *value, struct request_info *request)
4372aef6930SMark Murray {
4382aef6930SMark Murray     char   *level = split_at(value, '.');
4392aef6930SMark Murray 
4402aef6930SMark Murray     allow_severity = deny_severity = level ?
441b8980b27SDavid Malone 	severity_map(facilitynames, value) | severity_map(prioritynames, level)
442b8980b27SDavid Malone 	: severity_map(prioritynames, value);
4432aef6930SMark Murray }
4442aef6930SMark Murray 
4452aef6930SMark Murray /* get_field - return pointer to next field in string */
4462aef6930SMark Murray 
get_field(char * string)44714f102eaSEd Maste static char *get_field(char *string)
4482aef6930SMark Murray {
4492aef6930SMark Murray     static char *last = "";
4502aef6930SMark Murray     char   *src;
4512aef6930SMark Murray     char   *dst;
4522aef6930SMark Murray     char   *ret;
4532aef6930SMark Murray     int     ch;
4542aef6930SMark Murray 
4552aef6930SMark Murray     /*
4562aef6930SMark Murray      * This function returns pointers to successive fields within a given
4572aef6930SMark Murray      * string. ":" is the field separator; warn if the rule ends in one. It
4582aef6930SMark Murray      * replaces a "\:" sequence by ":", without treating the result of
4592aef6930SMark Murray      * substitution as field terminator. A null argument means resume search
4602aef6930SMark Murray      * where the previous call terminated. This function destroys its
4612aef6930SMark Murray      * argument.
4622aef6930SMark Murray      *
4632aef6930SMark Murray      * Work from explicit source or from memory. While processing \: we
4642aef6930SMark Murray      * overwrite the input. This way we do not have to maintain buffers for
4652aef6930SMark Murray      * copies of input fields.
4662aef6930SMark Murray      */
4672aef6930SMark Murray 
4682aef6930SMark Murray     src = dst = ret = (string ? string : last);
4692aef6930SMark Murray     if (src[0] == 0)
4702aef6930SMark Murray 	return (0);
4712aef6930SMark Murray 
4722aef6930SMark Murray     while (ch = *src) {
4732aef6930SMark Murray 	if (ch == ':') {
4742aef6930SMark Murray 	    if (*++src == 0)
4752aef6930SMark Murray 		tcpd_warn("rule ends in \":\"");
4762aef6930SMark Murray 	    break;
4772aef6930SMark Murray 	}
4782aef6930SMark Murray 	if (ch == '\\' && src[1] == ':')
4792aef6930SMark Murray 	    src++;
4802aef6930SMark Murray 	*dst++ = *src++;
4812aef6930SMark Murray     }
4822aef6930SMark Murray     last = src;
4832aef6930SMark Murray     *dst = 0;
4842aef6930SMark Murray     return (ret);
4852aef6930SMark Murray }
4862aef6930SMark Murray 
4872aef6930SMark Murray /* chop_string - strip leading and trailing blanks from string */
4882aef6930SMark Murray 
chop_string(register char * string)48914f102eaSEd Maste static char *chop_string(register char *string)
4902aef6930SMark Murray {
4912aef6930SMark Murray     char   *start = 0;
4922aef6930SMark Murray     char   *end;
4932aef6930SMark Murray     char   *cp;
4942aef6930SMark Murray 
4952aef6930SMark Murray     for (cp = string; *cp; cp++) {
4962aef6930SMark Murray 	if (!isspace(*cp)) {
4972aef6930SMark Murray 	    if (start == 0)
4982aef6930SMark Murray 		start = cp;
4992aef6930SMark Murray 	    end = cp;
5002aef6930SMark Murray 	}
5012aef6930SMark Murray     }
5022aef6930SMark Murray     return (start ? (end[1] = 0, start) : cp);
5032aef6930SMark Murray }
504