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