Index: stable/9/contrib/tcp_wrappers/clean_exit.c =================================================================== --- stable/9/contrib/tcp_wrappers/clean_exit.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/clean_exit.c (revision 311816) @@ -1,42 +1,43 @@ /* * clean_exit() cleans up and terminates the program. It should be called * instead of exit() when for some reason the real network daemon will not or * cannot be run. Reason: in the case of a datagram-oriented service we must * discard the not-yet received data from the client. Otherwise, inetd will * see the same datagram again and again, and go into a loop. * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #ifndef lint static char sccsid[] = "@(#) clean_exit.c 1.4 94/12/28 17:42:19"; #endif #include +#include extern void exit(); #include "tcpd.h" /* clean_exit - clean up and exit */ void clean_exit(request) struct request_info *request; { /* * In case of unconnected protocols we must eat up the not-yet received * data or inetd will loop. */ if (request->sink) request->sink(request->fd); /* * Be kind to the inetd. We already reported the problem via the syslogd, * and there is no need for additional garbage in the logfile. */ sleep(5); exit(0); } Index: stable/9/contrib/tcp_wrappers/hosts_access.c =================================================================== --- stable/9/contrib/tcp_wrappers/hosts_access.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/hosts_access.c (revision 311816) @@ -1,499 +1,505 @@ /* * This module implements a simple access control language that is based on * host (or domain) names, NIS (host) netgroup names, IP addresses (or * network numbers) and daemon process names. When a match is found the * search is terminated, and depending on whether PROCESS_OPTIONS is defined, * a list of options is executed or an optional shell command is executed. * * Host and user names are looked up on demand, provided that suitable endpoint * information is available as sockaddr_in structures or TLI netbufs. As a * side effect, the pattern matching process may change the contents of * request structure fields. * * Diagnostics are reported through syslog(3). * * Compile with -DNETGROUP if your library provides support for netgroups. * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * $FreeBSD$ */ #ifndef lint static char sccsid[] = "@(#) hosts_access.c 1.21 97/02/12 02:13:22"; #endif /* System libraries. */ #include #ifdef INT32_T typedef uint32_t u_int32_t; #endif #include #ifdef INET6 #include #endif #include #include #include #include #include #include #include #include #ifdef INET6 #include #endif +#include extern char *fgets(); extern int errno; #ifndef INADDR_NONE #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ #endif /* Local stuff. */ #include "tcpd.h" /* Error handling. */ extern jmp_buf tcpd_buf; /* Delimiters for lists of daemons or clients. */ static char sep[] = ", \t\r\n"; /* Constants to be used in assignments only, not in comparisons... */ #define YES 1 #define NO 0 /* * These variables are globally visible so that they can be redirected in * verification mode. */ char *hosts_allow_table = HOSTS_ALLOW; char *hosts_deny_table = HOSTS_DENY; int hosts_access_verbose = 0; /* * In a long-running process, we are not at liberty to just go away. */ int resident = (-1); /* -1, 0: unknown; +1: yes */ /* Forward declarations. */ static int table_match(); static int list_match(); static int server_match(); static int client_match(); static int host_match(); static int string_match(); static int masked_match(); #ifdef INET6 static int masked_match4(); static int masked_match6(); #endif /* Size of logical line buffer. */ #define BUFLEN 2048 +/* definition to be used from workarounds.c */ +#ifdef NETGROUP +int yp_get_default_domain(char **); +#endif + /* hosts_access - host access control facility */ int hosts_access(request) struct request_info *request; { int verdict; /* * If the (daemon, client) pair is matched by an entry in the file * /etc/hosts.allow, access is granted. Otherwise, if the (daemon, * client) pair is matched by an entry in the file /etc/hosts.deny, * access is denied. Otherwise, access is granted. A non-existent * access-control file is treated as an empty file. * * After a rule has been matched, the optional language extensions may * decide to grant or refuse service anyway. Or, while a rule is being * processed, a serious error is found, and it seems better to play safe * and deny service. All this is done by jumping back into the * hosts_access() routine, bypassing the regular return from the * table_match() function calls below. */ if (resident <= 0) resident++; verdict = setjmp(tcpd_buf); if (verdict != 0) return (verdict == AC_PERMIT); if (table_match(hosts_allow_table, request)) return (YES); if (table_match(hosts_deny_table, request)) return (NO); return (YES); } /* table_match - match table entries with (daemon, client) pair */ static int table_match(table, request) char *table; struct request_info *request; { FILE *fp; char sv_list[BUFLEN]; /* becomes list of daemons */ char *cl_list; /* becomes list of clients */ char *sh_cmd; /* becomes optional shell command */ int match = NO; struct tcpd_context saved_context; char *cp; saved_context = tcpd_context; /* stupid compilers */ /* * Between the fopen() and fclose() calls, avoid jumps that may cause * file descriptor leaks. */ if ((fp = fopen(table, "r")) != 0) { tcpd_context.file = table; tcpd_context.line = 0; while (match == NO && xgets(sv_list, sizeof(sv_list), fp) != 0) { if (sv_list[strlen(sv_list) - 1] != '\n') { tcpd_warn("missing newline or line too long"); continue; } /* Ignore anything after unescaped # character */ for (cp = strchr(sv_list, '#'); cp != NULL;) { if (cp > sv_list && cp[-1] == '\\') { cp = strchr(cp + 1, '#'); continue; } *cp = '\0'; break; } if (sv_list[strspn(sv_list, " \t\r\n")] == 0) continue; if ((cl_list = split_at(sv_list, ':')) == 0) { tcpd_warn("missing \":\" separator"); continue; } sh_cmd = split_at(cl_list, ':'); match = list_match(sv_list, request, server_match) && list_match(cl_list, request, client_match); } (void) fclose(fp); } else if (errno != ENOENT) { tcpd_warn("cannot open %s: %m", table); } if (match) { if (hosts_access_verbose > 1) syslog(LOG_DEBUG, "matched: %s line %d", tcpd_context.file, tcpd_context.line); if (sh_cmd) { #ifdef PROCESS_OPTIONS process_options(sh_cmd, request); #else char cmd[BUFSIZ]; shell_cmd(percent_x(cmd, sizeof(cmd), sh_cmd, request)); #endif } } tcpd_context = saved_context; return (match); } /* list_match - match a request against a list of patterns with exceptions */ static int list_match(list, request, match_fn) char *list; struct request_info *request; int (*match_fn) (); { char *tok; /* * Process tokens one at a time. We have exhausted all possible matches * when we reach an "EXCEPT" token or the end of the list. If we do find * a match, look for an "EXCEPT" list and recurse to determine whether * the match is affected by any exceptions. */ for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { if (STR_EQ(tok, "EXCEPT")) /* EXCEPT: give up */ return (NO); if (match_fn(tok, request)) { /* YES: look for exceptions */ while ((tok = strtok((char *) 0, sep)) && STR_NE(tok, "EXCEPT")) /* VOID */ ; return (tok == 0 || list_match((char *) 0, request, match_fn) == 0); } } return (NO); } /* server_match - match server information */ static int server_match(tok, request) char *tok; struct request_info *request; { char *host; if ((host = split_at(tok + 1, '@')) == 0) { /* plain daemon */ return (string_match(tok, eval_daemon(request))); } else { /* daemon@host */ return (string_match(tok, eval_daemon(request)) && host_match(host, request->server)); } } /* client_match - match client information */ static int client_match(tok, request) char *tok; struct request_info *request; { char *host; if ((host = split_at(tok + 1, '@')) == 0) { /* plain host */ return (host_match(tok, request->client)); } else { /* user@host */ return (host_match(host, request->client) && string_match(tok, eval_user(request))); } } /* hostfile_match - look up host patterns from file */ static int hostfile_match(path, host) char *path; -struct hosts_info *host; +struct host_info *host; { char tok[BUFSIZ]; int match = NO; FILE *fp; if ((fp = fopen(path, "r")) != 0) { while (fscanf(fp, "%s", tok) == 1 && !(match = host_match(tok, host))) /* void */ ; fclose(fp); } else if (errno != ENOENT) { tcpd_warn("open %s: %m", path); } return (match); } /* host_match - match host name and/or address against pattern */ static int host_match(tok, host) char *tok; struct host_info *host; { char *mask; /* * This code looks a little hairy because we want to avoid unnecessary * hostname lookups. * * The KNOWN pattern requires that both address AND name be known; some * patterns are specific to host names or to host addresses; all other * patterns are satisfied when either the address OR the name match. */ if (tok[0] == '@') { /* netgroup: look it up */ #ifdef NETGROUP static char *mydomain = 0; if (mydomain == 0) yp_get_default_domain(&mydomain); return (innetgr(tok + 1, eval_hostname(host), (char *) 0, mydomain)); #else tcpd_warn("netgroup support is disabled"); /* not tcpd_jump() */ return (NO); #endif } else if (tok[0] == '/') { /* /file hack */ return (hostfile_match(tok, host)); } else if (STR_EQ(tok, "KNOWN")) { /* check address and name */ char *name = eval_hostname(host); return (STR_NE(eval_hostaddr(host), unknown) && HOSTNAME_KNOWN(name)); } else if (STR_EQ(tok, "LOCAL")) { /* local: no dots in name */ char *name = eval_hostname(host); return (strchr(name, '.') == 0 && HOSTNAME_KNOWN(name)); } else if ((mask = split_at(tok, '/')) != 0) { /* net/mask */ return (masked_match(tok, mask, eval_hostaddr(host))); } else { /* anything else */ return (string_match(tok, eval_hostaddr(host)) || (NOT_INADDR(tok) && string_match(tok, eval_hostname(host)))); } } /* string_match - match string against pattern */ static int string_match(tok, string) char *tok; char *string; { int n; #ifdef INET6 /* convert IPv4 mapped IPv6 address to IPv4 address */ if (STRN_EQ(string, "::ffff:", 7) && dot_quad_addr(string + 7) != INADDR_NONE) { string += 7; } #endif if (tok[0] == '.') { /* suffix */ n = strlen(string) - strlen(tok); return (n > 0 && STR_EQ(tok, string + n)); } else if (STR_EQ(tok, "ALL")) { /* all: match any */ return (YES); } else if (STR_EQ(tok, "KNOWN")) { /* not unknown */ return (STR_NE(string, unknown)); } else if (tok[(n = strlen(tok)) - 1] == '.') { /* prefix */ return (STRN_EQ(tok, string, n)); } else { /* exact match */ #ifdef INET6 struct addrinfo hints, *res; struct sockaddr_in6 pat, addr; int len, ret; char ch; len = strlen(tok); if (*tok == '[' && tok[len - 1] == ']') { ch = tok[len - 1]; tok[len - 1] = '\0'; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if ((ret = getaddrinfo(tok + 1, NULL, &hints, &res)) == 0) { memcpy(&pat, res->ai_addr, sizeof(pat)); freeaddrinfo(res); } tok[len - 1] = ch; if (ret != 0 || getaddrinfo(string, NULL, &hints, &res) != 0) return NO; memcpy(&addr, res->ai_addr, sizeof(addr)); freeaddrinfo(res); if (pat.sin6_scope_id != 0 && addr.sin6_scope_id != pat.sin6_scope_id) return NO; return (!memcmp(&pat.sin6_addr, &addr.sin6_addr, sizeof(struct in6_addr))); return (ret); } #endif return (STR_EQ(tok, string)); } } /* masked_match - match address against netnumber/netmask */ #ifdef INET6 static int masked_match(net_tok, mask_tok, string) char *net_tok; char *mask_tok; char *string; { return (masked_match4(net_tok, mask_tok, string) || masked_match6(net_tok, mask_tok, string)); } static int masked_match4(net_tok, mask_tok, string) #else static int masked_match(net_tok, mask_tok, string) #endif char *net_tok; char *mask_tok; char *string; { #ifdef INET6 u_int32_t net; u_int32_t mask; u_int32_t addr; #else unsigned long net; unsigned long mask; unsigned long addr; #endif /* * Disallow forms other than dotted quad: the treatment that inet_addr() * gives to forms with less than four components is inconsistent with the * access control language. John P. Rouillard . */ if ((addr = dot_quad_addr(string)) == INADDR_NONE) return (NO); if ((net = dot_quad_addr(net_tok)) == INADDR_NONE || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE) { #ifndef INET6 tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok); #endif return (NO); /* not tcpd_jump() */ } return ((addr & mask) == net); } #ifdef INET6 static int masked_match6(net_tok, mask_tok, string) char *net_tok; char *mask_tok; char *string; { struct addrinfo hints, *res; struct sockaddr_in6 net, addr; u_int32_t mask; int len, mask_len, i = 0; char ch; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(string, NULL, &hints, &res) != 0) return NO; memcpy(&addr, res->ai_addr, sizeof(addr)); freeaddrinfo(res); if (IN6_IS_ADDR_V4MAPPED(&addr.sin6_addr)) { if ((*(u_int32_t *)&net.sin6_addr.s6_addr[12] = dot_quad_addr(net_tok)) == INADDR_NONE || (mask = dot_quad_addr(mask_tok)) == INADDR_NONE) return (NO); return ((*(u_int32_t *)&addr.sin6_addr.s6_addr[12] & mask) == *(u_int32_t *)&net.sin6_addr.s6_addr[12]); } /* match IPv6 address against netnumber/prefixlen */ len = strlen(net_tok); if (*net_tok != '[' || net_tok[len - 1] != ']') return NO; ch = net_tok[len - 1]; net_tok[len - 1] = '\0'; if (getaddrinfo(net_tok + 1, NULL, &hints, &res) != 0) { net_tok[len - 1] = ch; return NO; } memcpy(&net, res->ai_addr, sizeof(net)); freeaddrinfo(res); net_tok[len - 1] = ch; if ((mask_len = atoi(mask_tok)) < 0 || mask_len > 128) return NO; if (net.sin6_scope_id != 0 && addr.sin6_scope_id != net.sin6_scope_id) return NO; while (mask_len > 0) { if (mask_len < 32) { mask = htonl(~(0xffffffff >> mask_len)); if ((*(u_int32_t *)&addr.sin6_addr.s6_addr[i] & mask) != (*(u_int32_t *)&net.sin6_addr.s6_addr[i] & mask)) return NO; break; } if (*(u_int32_t *)&addr.sin6_addr.s6_addr[i] != *(u_int32_t *)&net.sin6_addr.s6_addr[i]) return NO; i += 4; mask_len -= 32; } return YES; } #endif /* INET6 */ Index: stable/9/contrib/tcp_wrappers/options.c =================================================================== --- stable/9/contrib/tcp_wrappers/options.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/options.c (revision 311816) @@ -1,531 +1,538 @@ /* * General skeleton for adding options to the access control language. The * features offered by this module are documented in the hosts_options(5) * manual page (source file: hosts_options.5, "nroff -man" format). * * Notes and warnings for those who want to add features: * * In case of errors, abort options processing and deny access. There are too * many irreversible side effects to make error recovery feasible. For * example, it makes no sense to continue after we have already changed the * userid. * * In case of errors, do not terminate the process: the routines might be * called from a long-running daemon that should run forever. Instead, call * tcpd_jump() which does a non-local goto back into the hosts_access() * routine. * * In case of severe errors, use clean_exit() instead of directly calling * exit(), or the inetd may loop on an UDP request. * * In verification mode (for example, with the "tcpdmatch" command) the * "dry_run" flag is set. In this mode, an option function should just "say" * what it is going to do instead of really doing it. * * Some option functions do not return (for example, the twist option passes * control to another program). In verification mode (dry_run flag is set) * such options should clear the "dry_run" flag to inform the caller of this * course of action. * * $FreeBSD$ */ #ifndef lint static char sccsid[] = "@(#) options.c 1.17 96/02/11 17:01:31"; #endif /* System libraries. */ #include #include #include #include #include #include #include #define SYSLOG_NAMES #include #include #include #include #include #include +#include +#include #ifndef MAXPATHNAMELEN #define MAXPATHNAMELEN BUFSIZ #endif /* Local stuff. */ #include "tcpd.h" /* Options runtime support. */ int dry_run = 0; /* flag set in verification mode */ extern jmp_buf tcpd_buf; /* tcpd_jump() support */ /* Options parser support. */ static char whitespace_eq[] = "= \t\r\n"; #define whitespace (whitespace_eq + 1) static char *get_field(); /* chew :-delimited field off string */ static char *chop_string(); /* strip leading and trailing blanks */ /* List of functions that implement the options. Add yours here. */ static void user_option(); /* execute "user name.group" option */ static void group_option(); /* execute "group name" option */ static void umask_option(); /* execute "umask mask" option */ static void linger_option(); /* execute "linger time" option */ static void keepalive_option(); /* execute "keepalive" option */ static void spawn_option(); /* execute "spawn command" option */ static void twist_option(); /* execute "twist command" option */ static void rfc931_option(); /* execute "rfc931" option */ static void setenv_option(); /* execute "setenv name value" */ static void nice_option(); /* execute "nice" option */ static void severity_option(); /* execute "severity value" */ static void allow_option(); /* execute "allow" option */ static void deny_option(); /* execute "deny" option */ static void banners_option(); /* execute "banners path" option */ /* Structure of the options table. */ struct option { char *name; /* keyword name, case is ignored */ void (*func) (); /* function that does the real work */ int flags; /* see below... */ }; #define NEED_ARG (1<<1) /* option requires argument */ #define USE_LAST (1<<2) /* option must be last */ #define OPT_ARG (1<<3) /* option has optional argument */ #define EXPAND_ARG (1<<4) /* do %x expansion on argument */ #define need_arg(o) ((o)->flags & NEED_ARG) #define opt_arg(o) ((o)->flags & OPT_ARG) #define permit_arg(o) ((o)->flags & (NEED_ARG | OPT_ARG)) #define use_last(o) ((o)->flags & USE_LAST) #define expand_arg(o) ((o)->flags & EXPAND_ARG) /* List of known keywords. Add yours here. */ static struct option option_table[] = { "user", user_option, NEED_ARG, "group", group_option, NEED_ARG, "umask", umask_option, NEED_ARG, "linger", linger_option, NEED_ARG, "keepalive", keepalive_option, 0, "spawn", spawn_option, NEED_ARG | EXPAND_ARG, "twist", twist_option, NEED_ARG | EXPAND_ARG | USE_LAST, "rfc931", rfc931_option, OPT_ARG, "setenv", setenv_option, NEED_ARG | EXPAND_ARG, "nice", nice_option, OPT_ARG, "severity", severity_option, NEED_ARG, "allow", allow_option, USE_LAST, "deny", deny_option, USE_LAST, "banners", banners_option, NEED_ARG, 0, }; /* process_options - process access control options */ void process_options(options, request) char *options; struct request_info *request; { char *key; char *value; char *curr_opt; char *next_opt; struct option *op; char bf[BUFSIZ]; for (curr_opt = get_field(options); curr_opt; curr_opt = next_opt) { next_opt = get_field((char *) 0); /* * Separate the option into name and value parts. For backwards * compatibility we ignore exactly one '=' between name and value. */ curr_opt = chop_string(curr_opt); if (*(value = curr_opt + strcspn(curr_opt, whitespace_eq))) { if (*value != '=') { *value++ = 0; value += strspn(value, whitespace); } if (*value == '=') { *value++ = 0; value += strspn(value, whitespace); } } if (*value == 0) value = 0; key = curr_opt; /* * Disallow missing option names (and empty option fields). */ if (*key == 0) tcpd_jump("missing option name"); /* * Lookup the option-specific info and do some common error checks. * Delegate option-specific processing to the specific functions. */ for (op = option_table; op->name && STR_NE(op->name, key); op++) /* VOID */ ; if (op->name == 0) tcpd_jump("bad option name: \"%s\"", key); if (!value && need_arg(op)) tcpd_jump("option \"%s\" requires value", key); if (value && !permit_arg(op)) tcpd_jump("option \"%s\" requires no value", key); if (next_opt && use_last(op)) tcpd_jump("option \"%s\" must be at end", key); if (value && expand_arg(op)) value = chop_string(percent_x(bf, sizeof(bf), value, request)); if (hosts_access_verbose) syslog(LOG_DEBUG, "option: %s %s", key, value ? value : ""); (*(op->func)) (value, request); } } /* allow_option - grant access */ /* ARGSUSED */ static void allow_option(value, request) char *value; struct request_info *request; { longjmp(tcpd_buf, AC_PERMIT); } /* deny_option - deny access */ /* ARGSUSED */ static void deny_option(value, request) char *value; struct request_info *request; { longjmp(tcpd_buf, AC_DENY); } /* banners_option - expand %, terminate each line with CRLF */ static void banners_option(value, request) char *value; struct request_info *request; { char path[MAXPATHNAMELEN]; char ibuf[BUFSIZ]; char obuf[2 * BUFSIZ]; struct stat st; int ch; FILE *fp; sprintf(path, "%s/%s", value, eval_daemon(request)); if ((fp = fopen(path, "r")) != 0) { while ((ch = fgetc(fp)) == 0) write(request->fd, "", 1); ungetc(ch, fp); while (fgets(ibuf, sizeof(ibuf) - 1, fp)) { if (split_at(ibuf, '\n')) strcat(ibuf, "\r\n"); percent_x(obuf, sizeof(obuf), ibuf, request); write(request->fd, obuf, strlen(obuf)); } fclose(fp); } else if (stat(value, &st) < 0) { tcpd_warn("%s: %m", value); } } /* group_option - switch group id */ /* ARGSUSED */ static void group_option(value, request) char *value; struct request_info *request; { struct group *grp; struct group *getgrnam(); if ((grp = getgrnam(value)) == 0) tcpd_jump("unknown group: \"%s\"", value); endgrent(); if (dry_run == 0 && setgid(grp->gr_gid)) tcpd_jump("setgid(%s): %m", value); } /* user_option - switch user id */ /* ARGSUSED */ static void user_option(value, request) char *value; struct request_info *request; { struct passwd *pwd; struct passwd *getpwnam(); char *group; if ((group = split_at(value, '.')) != 0) group_option(group, request); if ((pwd = getpwnam(value)) == 0) tcpd_jump("unknown user: \"%s\"", value); endpwent(); if (dry_run == 0 && setuid(pwd->pw_uid)) tcpd_jump("setuid(%s): %m", value); } /* umask_option - set file creation mask */ /* ARGSUSED */ static void umask_option(value, request) char *value; struct request_info *request; { unsigned mask; char junk; if (sscanf(value, "%o%c", &mask, &junk) != 1 || (mask & 0777) != mask) tcpd_jump("bad umask value: \"%s\"", value); (void) umask(mask); } /* spawn_option - spawn a shell command and wait */ /* ARGSUSED */ static void spawn_option(value, request) char *value; struct request_info *request; { if (dry_run == 0) shell_cmd(value); } /* linger_option - set the socket linger time (Marc Boucher ) */ /* ARGSUSED */ static void linger_option(value, request) char *value; struct request_info *request; { struct linger linger; char junk; if (sscanf(value, "%d%c", &linger.l_linger, &junk) != 1 || linger.l_linger < 0) tcpd_jump("bad linger value: \"%s\"", value); if (dry_run == 0) { linger.l_onoff = (linger.l_linger != 0); if (setsockopt(request->fd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)) < 0) tcpd_warn("setsockopt SO_LINGER %d: %m", linger.l_linger); } } /* keepalive_option - set the socket keepalive option */ /* ARGSUSED */ static void keepalive_option(value, request) char *value; struct request_info *request; { static int on = 1; if (dry_run == 0 && setsockopt(request->fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) tcpd_warn("setsockopt SO_KEEPALIVE: %m"); } /* nice_option - set nice value */ /* ARGSUSED */ static void nice_option(value, request) char *value; struct request_info *request; { int niceval = 10; char junk; if (value != 0 && sscanf(value, "%d%c", &niceval, &junk) != 1) tcpd_jump("bad nice value: \"%s\"", value); if (dry_run == 0 && nice(niceval) < 0) tcpd_warn("nice(%d): %m", niceval); } /* twist_option - replace process by shell command */ static void twist_option(value, request) char *value; struct request_info *request; { char *error; if (dry_run != 0) { dry_run = 0; } else { if (resident > 0) tcpd_jump("twist option in resident process"); syslog(deny_severity, "twist %s to %s", eval_client(request), value); /* Before switching to the shell, set up stdin, stdout and stderr. */ #define maybe_dup2(from, to) ((from == to) ? to : (close(to), dup(from))) if (maybe_dup2(request->fd, 0) != 0 || maybe_dup2(request->fd, 1) != 1 || maybe_dup2(request->fd, 2) != 2) { error = "twist_option: dup: %m"; } else { if (request->fd > 2) close(request->fd); (void) execl("/bin/sh", "sh", "-c", value, (char *) 0); error = "twist_option: /bin/sh: %m"; } /* Something went wrong: we MUST terminate the process. */ tcpd_warn(error); clean_exit(request); } } /* rfc931_option - look up remote user name */ static void rfc931_option(value, request) char *value; struct request_info *request; { int timeout; char junk; if (value != 0) { if (sscanf(value, "%d%c", &timeout, &junk) != 1 || timeout <= 0) tcpd_jump("bad rfc931 timeout: \"%s\"", value); rfc931_timeout = timeout; } (void) eval_user(request); } /* setenv_option - set environment variable */ /* ARGSUSED */ static void setenv_option(value, request) char *value; struct request_info *request; { char *var_value; if (*(var_value = value + strcspn(value, whitespace))) *var_value++ = 0; if (setenv(chop_string(value), chop_string(var_value), 1)) tcpd_jump("memory allocation failure"); } /* severity_map - lookup facility or severity value */ static int severity_map(table, name) -CODE *table; +const CODE *table; char *name; { - CODE *t; + const CODE *t; + int ret = -1; for (t = table; t->c_name; t++) - if (STR_EQ(t->c_name, name)) - return (t->c_val); - tcpd_jump("bad syslog facility or severity: \"%s\"", name); - /* NOTREACHED */ + if (STR_EQ(t->c_name, name)) { + ret = t->c_val; + break; + } + if (ret == -1) + tcpd_jump("bad syslog facility or severity: \"%s\"", name); + + return (ret); } /* severity_option - change logging severity for this event (Dave Mitchell) */ /* ARGSUSED */ static void severity_option(value, request) char *value; struct request_info *request; { char *level = split_at(value, '.'); allow_severity = deny_severity = level ? severity_map(facilitynames, value) | severity_map(prioritynames, level) : severity_map(prioritynames, value); } /* get_field - return pointer to next field in string */ static char *get_field(string) char *string; { static char *last = ""; char *src; char *dst; char *ret; int ch; /* * This function returns pointers to successive fields within a given * string. ":" is the field separator; warn if the rule ends in one. It * replaces a "\:" sequence by ":", without treating the result of * substitution as field terminator. A null argument means resume search * where the previous call terminated. This function destroys its * argument. * * Work from explicit source or from memory. While processing \: we * overwrite the input. This way we do not have to maintain buffers for * copies of input fields. */ src = dst = ret = (string ? string : last); if (src[0] == 0) return (0); while (ch = *src) { if (ch == ':') { if (*++src == 0) tcpd_warn("rule ends in \":\""); break; } if (ch == '\\' && src[1] == ':') src++; *dst++ = *src++; } last = src; *dst = 0; return (ret); } /* chop_string - strip leading and trailing blanks from string */ static char *chop_string(string) register char *string; { char *start = 0; char *end; char *cp; for (cp = string; *cp; cp++) { if (!isspace(*cp)) { if (start == 0) start = cp; end = cp; } } return (start ? (end[1] = 0, start) : cp); } Index: stable/9/contrib/tcp_wrappers/percent_x.c =================================================================== --- stable/9/contrib/tcp_wrappers/percent_x.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/percent_x.c (revision 311816) @@ -1,86 +1,87 @@ /* * percent_x() takes a string and performs % expansions. It aborts the * program when the expansion would overflow the output buffer. The result * of % expansion may be passed on to a shell process. For this * reason, characters with a special meaning to shells are replaced by * underscores. * * Diagnostics are reported through syslog(3). * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #ifndef lint static char sccsid[] = "@(#) percent_x.c 1.4 94/12/28 17:42:37"; #endif /* System libraries. */ #include #include #include +#include extern void exit(); /* Local stuff. */ #include "tcpd.h" /* percent_x - do % expansion, abort if result buffer is too small */ char *percent_x(result, result_len, string, request) char *result; int result_len; char *string; struct request_info *request; { char *bp = result; char *end = result + result_len - 1; /* end of result buffer */ char *expansion; int expansion_len; static char ok_chars[] = "1234567890!@%-_=+:,./\ abcdefghijklmnopqrstuvwxyz\ ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char *str = string; char *cp; int ch; /* * Warning: we may be called from a child process or after pattern * matching, so we cannot use clean_exit() or tcpd_jump(). */ while (*str) { if (*str == '%' && (ch = str[1]) != 0) { str += 2; expansion = ch == 'a' ? eval_hostaddr(request->client) : ch == 'A' ? eval_hostaddr(request->server) : ch == 'c' ? eval_client(request) : ch == 'd' ? eval_daemon(request) : ch == 'h' ? eval_hostinfo(request->client) : ch == 'H' ? eval_hostinfo(request->server) : ch == 'n' ? eval_hostname(request->client) : ch == 'N' ? eval_hostname(request->server) : ch == 'p' ? eval_pid(request) : ch == 's' ? eval_server(request) : ch == 'u' ? eval_user(request) : ch == '%' ? "%" : (tcpd_warn("unrecognized %%%c", ch), ""); for (cp = expansion; *(cp += strspn(cp, ok_chars)); /* */ ) *cp = '_'; expansion_len = cp - expansion; } else { expansion = str++; expansion_len = 1; } if (bp + expansion_len >= end) { tcpd_warn("percent_x: expansion too long: %.30s...", result); sleep(5); exit(0); } memcpy(bp, expansion, expansion_len); bp += expansion_len; } *bp = 0; return (result); } Index: stable/9/contrib/tcp_wrappers/rfc931.c =================================================================== --- stable/9/contrib/tcp_wrappers/rfc931.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/rfc931.c (revision 311816) @@ -1,232 +1,233 @@ /* * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote * host to look up the owner of a connection. The information should not be * used for authentication purposes. This routine intercepts alarm signals. * * Diagnostics are reported through syslog(3). * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * $FreeBSD$ */ #ifndef lint static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34"; #endif /* System libraries. */ #include #include #include #include #include #include #include #include +#include #ifndef SEEK_SET #define SEEK_SET 0 #endif /* Local stuff. */ #include "tcpd.h" #define RFC931_PORT 113 /* Semi-well-known port */ #define ANY_PORT 0 /* Any old port will do */ int rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */ static jmp_buf timebuf; /* fsocket - open stdio stream on top of socket */ static FILE *fsocket(domain, type, protocol) int domain; int type; int protocol; { int s; FILE *fp; if ((s = socket(domain, type, protocol)) < 0) { tcpd_warn("socket: %m"); return (0); } else { if ((fp = fdopen(s, "r+")) == 0) { tcpd_warn("fdopen: %m"); close(s); } return (fp); } } /* timeout - handle timeouts */ static void timeout(sig) int sig; { longjmp(timebuf, sig); } /* rfc931 - return remote user name, given socket structures */ void rfc931(rmt_sin, our_sin, dest) #ifdef INET6 struct sockaddr *rmt_sin; struct sockaddr *our_sin; #else struct sockaddr_in *rmt_sin; struct sockaddr_in *our_sin; #endif char *dest; { unsigned rmt_port; unsigned our_port; #ifdef INET6 struct sockaddr_storage rmt_query_sin; struct sockaddr_storage our_query_sin; int alen; #else struct sockaddr_in rmt_query_sin; struct sockaddr_in our_query_sin; #endif char user[256]; /* XXX */ char buffer[512]; /* XXX */ char *cp; char *result = unknown; FILE *fp; #ifdef INET6 /* address family must be the same */ if (rmt_sin->sa_family != our_sin->sa_family) { STRN_CPY(dest, result, STRING_LENGTH); return; } switch (our_sin->sa_family) { case AF_INET: alen = sizeof(struct sockaddr_in); break; case AF_INET6: alen = sizeof(struct sockaddr_in6); break; default: STRN_CPY(dest, result, STRING_LENGTH); return; } #endif /* * If we use a single, buffered, bidirectional stdio stream ("r+" or * "w+" mode) we may read our own output. Such behaviour would make sense * with resources that support random-access operations, but not with * sockets. ANSI C suggests several functions which can be called when * you want to change IO direction, fseek seems the most portable. */ #ifdef INET6 if ((fp = fsocket(our_sin->sa_family, SOCK_STREAM, 0)) != 0) { #else if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) { #endif /* * Set up a timer so we won't get stuck while waiting for the server. */ if (setjmp(timebuf) == 0) { signal(SIGALRM, timeout); alarm(rfc931_timeout); /* * Bind the local and remote ends of the query socket to the same * IP addresses as the connection under investigation. We go * through all this trouble because the local or remote system * might have more than one network address. The RFC931 etc. * client sends only port numbers; the server takes the IP * addresses from the query socket. */ #ifdef INET6 memcpy(&our_query_sin, our_sin, alen); memcpy(&rmt_query_sin, rmt_sin, alen); switch (our_sin->sa_family) { case AF_INET: ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT); ((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC931_PORT); break; case AF_INET6: ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT); ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC931_PORT); break; } if (bind(fileno(fp), (struct sockaddr *) & our_query_sin, alen) >= 0 && connect(fileno(fp), (struct sockaddr *) & rmt_query_sin, alen) >= 0) { #else our_query_sin = *our_sin; our_query_sin.sin_port = htons(ANY_PORT); rmt_query_sin = *rmt_sin; rmt_query_sin.sin_port = htons(RFC931_PORT); if (bind(fileno(fp), (struct sockaddr *) & our_query_sin, sizeof(our_query_sin)) >= 0 && connect(fileno(fp), (struct sockaddr *) & rmt_query_sin, sizeof(rmt_query_sin)) >= 0) { #endif /* * Send query to server. Neglect the risk that a 13-byte * write would have to be fragmented by the local system and * cause trouble with buggy System V stdio libraries. */ fprintf(fp, "%u,%u\r\n", #ifdef INET6 ntohs(((struct sockaddr_in *)rmt_sin)->sin_port), ntohs(((struct sockaddr_in *)our_sin)->sin_port)); #else ntohs(rmt_sin->sin_port), ntohs(our_sin->sin_port)); #endif fflush(fp); fseek(fp, 0, SEEK_SET); /* * Read response from server. Use fgets()/sscanf() so we can * work around System V stdio libraries that incorrectly * assume EOF when a read from a socket returns less than * requested. */ if (fgets(buffer, sizeof(buffer), fp) != 0 && ferror(fp) == 0 && feof(fp) == 0 && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s", &rmt_port, &our_port, user) == 3 #ifdef INET6 && ntohs(((struct sockaddr_in *)rmt_sin)->sin_port) == rmt_port && ntohs(((struct sockaddr_in *)our_sin)->sin_port) == our_port) { #else && ntohs(rmt_sin->sin_port) == rmt_port && ntohs(our_sin->sin_port) == our_port) { #endif /* * Strip trailing carriage return. It is part of the * protocol, not part of the data. */ if (cp = strchr(user, '\r')) *cp = 0; result = user; } } alarm(0); } fclose(fp); } STRN_CPY(dest, result, STRING_LENGTH); } Index: stable/9/contrib/tcp_wrappers/scaffold.c =================================================================== --- stable/9/contrib/tcp_wrappers/scaffold.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/scaffold.c (revision 311816) @@ -1,272 +1,262 @@ /* * Routines for testing only. Not really industrial strength. * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * $FreeBSD$ */ #ifndef lint static char sccs_id[] = "@(#) scaffold.c 1.6 97/03/21 19:27:24"; #endif /* System libraries. */ #include #include #include #include #include #include #include #include #include #include #ifndef INADDR_NONE #define INADDR_NONE (-1) /* XXX should be 0xffffffff */ #endif #ifndef INET6 extern char *malloc(); #endif /* Application-specific. */ #include "tcpd.h" #include "scaffold.h" /* * These are referenced by the options module and by rfc931.c. */ int allow_severity = SEVERITY; int deny_severity = LOG_WARNING; int rfc931_timeout = RFC931_TIMEOUT; #ifndef INET6 /* dup_hostent - create hostent in one memory block */ static struct hostent *dup_hostent(hp) struct hostent *hp; { struct hostent_block { struct hostent host; char *addr_list[1]; }; struct hostent_block *hb; int count; char *data; char *addr; for (count = 0; hp->h_addr_list[count] != 0; count++) /* void */ ; if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block) + (hp->h_length + sizeof(char *)) * count)) == 0) { fprintf(stderr, "Sorry, out of memory\n"); exit(1); } memset((char *) &hb->host, 0, sizeof(hb->host)); hb->host.h_length = hp->h_length; hb->host.h_addr_list = hb->addr_list; hb->host.h_addr_list[count] = 0; data = (char *) (hb->host.h_addr_list + count + 1); for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { hb->host.h_addr_list[count] = data + hp->h_length * count; memcpy(hb->host.h_addr_list[count], addr, hp->h_length); } return (&hb->host); } #endif /* find_inet_addr - find all addresses for this host, result to free() */ #ifdef INET6 struct addrinfo *find_inet_addr(host) char *host; { struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(host, NULL, &hints, &res) == 0) return (res); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_CANONNAME; if (getaddrinfo(host, NULL, &hints, &res) != 0) { tcpd_warn("%s: host not found", host); return (0); } if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) { tcpd_warn("%d: not an internet host", res->ai_family); freeaddrinfo(res); return (0); } if (!res->ai_canonname) { tcpd_warn("%s: hostname alias", host); tcpd_warn("(cannot obtain official name)", res->ai_canonname); } else if (STR_NE(host, res->ai_canonname)) { tcpd_warn("%s: hostname alias", host); tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname); } return (res); } #else struct hostent *find_inet_addr(host) char *host; { struct in_addr addr; struct hostent *hp; static struct hostent h; static char *addr_list[2]; /* * Host address: translate it to internal form. */ if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) { h.h_addr_list = addr_list; h.h_addr_list[0] = (char *) &addr; h.h_length = sizeof(addr); return (dup_hostent(&h)); } /* * Map host name to a series of addresses. Watch out for non-internet * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has * been "enhanced" to accept numeric addresses. Make a copy of the * address list so that later gethostbyXXX() calls will not clobber it. */ if (NOT_INADDR(host) == 0) { tcpd_warn("%s: not an internet address", host); return (0); } if ((hp = gethostbyname(host)) == 0) { tcpd_warn("%s: host not found", host); return (0); } if (hp->h_addrtype != AF_INET) { tcpd_warn("%d: not an internet host", hp->h_addrtype); return (0); } if (STR_NE(host, hp->h_name)) { tcpd_warn("%s: hostname alias", host); tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name); } return (dup_hostent(hp)); } #endif /* check_dns - give each address thorough workout, return address count */ int check_dns(host) char *host; { struct request_info request; #ifdef INET6 struct sockaddr_storage sin; struct addrinfo *hp, *res; #else struct sockaddr_in sin; struct hostent *hp; #endif int count; char *addr; if ((hp = find_inet_addr(host)) == 0) return (0); request_init(&request, RQ_CLIENT_SIN, &sin, 0); sock_methods(&request); #ifndef INET6 memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; #endif #ifdef INET6 for (res = hp, count = 0; res; res = res->ai_next, count++) { memcpy(&sin, res->ai_addr, res->ai_addrlen); #else for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) { memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr)); #endif /* * Force host name and address conversions. Use the request structure * as a cache. Detect hostname lookup problems. Any name/name or * name/address conflicts will be reported while eval_hostname() does * its job. */ request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0); if (STR_EQ(eval_hostname(request.client), unknown)) tcpd_warn("host address %s->name lookup failed", eval_hostaddr(request.client)); } #ifdef INET6 freeaddrinfo(hp); #else free((char *) hp); #endif return (count); } /* dummy function to intercept the real shell_cmd() */ /* ARGSUSED */ void shell_cmd(command) char *command; { if (hosts_access_verbose) printf("command: %s", command); } /* dummy function to intercept the real clean_exit() */ /* ARGSUSED */ void clean_exit(request) struct request_info *request; { exit(0); } -/* dummy function to intercept the real rfc931() */ - -/* ARGSUSED */ - -void rfc931(request) -struct request_info *request; -{ - strcpy(request->user, unknown); -} - /* check_path - examine accessibility */ int check_path(path, st) char *path; struct stat *st; { struct stat stbuf; char buf[BUFSIZ]; if (stat(path, st) < 0) return (-1); #ifdef notdef if (st->st_uid != 0) tcpd_warn("%s: not owned by root", path); if (st->st_mode & 020) tcpd_warn("%s: group writable", path); #endif if (st->st_mode & 002) tcpd_warn("%s: world writable", path); if (path[0] == '/' && path[1] != 0) { strrchr(strcpy(buf, path), '/')[0] = 0; (void) check_path(buf[0] ? buf : "/", &stbuf); } return (0); } Index: stable/9/contrib/tcp_wrappers/shell_cmd.c =================================================================== --- stable/9/contrib/tcp_wrappers/shell_cmd.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/shell_cmd.c (revision 311816) @@ -1,92 +1,95 @@ /* * shell_cmd() takes a shell command after % substitutions. The * command is executed by a /bin/sh child process, with standard input, * standard output and standard error connected to /dev/null. * * Diagnostics are reported through syslog(3). * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. */ #ifndef lint static char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44"; #endif /* System libraries. */ #include #include +#include #include #include #include #include +#include +#include extern void exit(); /* Local stuff. */ #include "tcpd.h" /* Forward declarations. */ static void do_child(); /* shell_cmd - execute shell command */ void shell_cmd(command) char *command; { int child_pid; int wait_pid; /* * Most of the work is done within the child process, to minimize the * risk of damage to the parent. */ switch (child_pid = fork()) { case -1: /* error */ tcpd_warn("cannot fork: %m"); break; case 00: /* child */ do_child(command); /* NOTREACHED */ default: /* parent */ while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid) /* void */ ; } } /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */ static void do_child(command) char *command; { char *error; int tmp_fd; /* * Systems with POSIX sessions may send a SIGHUP to grandchildren if the * child exits first. This is sick, sessions were invented for terminals. */ signal(SIGHUP, SIG_IGN); /* Set up new stdin, stdout, stderr, and exec the shell command. */ for (tmp_fd = 0; tmp_fd < 3; tmp_fd++) (void) close(tmp_fd); if (open("/dev/null", 2) != 0) { error = "open /dev/null: %m"; } else if (dup(0) != 1 || dup(0) != 2) { error = "dup: %m"; } else { (void) execl("/bin/sh", "sh", "-c", command, (char *) 0); error = "execl /bin/sh: %m"; } /* Something went wrong. We MUST terminate the child process. */ tcpd_warn(error); _exit(0); } Index: stable/9/contrib/tcp_wrappers/tcpd.h =================================================================== --- stable/9/contrib/tcp_wrappers/tcpd.h (revision 311815) +++ stable/9/contrib/tcp_wrappers/tcpd.h (revision 311816) @@ -1,226 +1,224 @@ /* * @(#) tcpd.h 1.5 96/03/19 16:22:24 * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * $FreeBSD$ */ +#ifdef INET6 +#define TCPD_SOCKADDR struct sockaddr +#else +#define TCPD_SOCKADDR struct sockaddr_in +#endif + +#ifndef _STDFILE_DECLARED +#define _STDFILE_DECLARED +typedef struct __sFILE FILE; +#endif + /* Structure to describe one communications endpoint. */ #define STRING_LENGTH 128 /* hosts, users, processes */ struct host_info { char name[STRING_LENGTH]; /* access via eval_hostname(host) */ char addr[STRING_LENGTH]; /* access via eval_hostaddr(host) */ -#ifdef INET6 - struct sockaddr *sin; /* socket address or 0 */ -#else - struct sockaddr_in *sin; /* socket address or 0 */ -#endif + TCPD_SOCKADDR *sin; /* socket address or 0 */ struct t_unitdata *unit; /* TLI transport address or 0 */ struct request_info *request; /* for shared information */ }; /* Structure to describe what we know about a service request. */ struct request_info { int fd; /* socket handle */ char user[STRING_LENGTH]; /* access via eval_user(request) */ char daemon[STRING_LENGTH]; /* access via eval_daemon(request) */ char pid[10]; /* access via eval_pid(request) */ struct host_info client[1]; /* client endpoint info */ struct host_info server[1]; /* server endpoint info */ void (*sink) (int); /* datagram sink function or 0 */ void (*hostname) (struct host_info *); /* address to printable hostname */ void (*hostaddr) (struct host_info *); /* address to printable address */ void (*cleanup) (struct request_info *); /* cleanup function or 0 */ struct netconfig *config; /* netdir handle */ }; /* Common string operations. Less clutter should be more readable. */ #define STRN_CPY(d,s,l) { strncpy((d),(s),(l)); (d)[(l)-1] = 0; } #define STRN_EQ(x,y,l) (strncasecmp((x),(y),(l)) == 0) #define STRN_NE(x,y,l) (strncasecmp((x),(y),(l)) != 0) #define STR_EQ(x,y) (strcasecmp((x),(y)) == 0) #define STR_NE(x,y) (strcasecmp((x),(y)) != 0) /* * Initially, all above strings have the empty value. Information that * cannot be determined at runtime is set to "unknown", so that we can * distinguish between `unavailable' and `not yet looked up'. A hostname * that we do not believe in is set to "paranoid". */ #define STRING_UNKNOWN "unknown" /* lookup failed */ #define STRING_PARANOID "paranoid" /* hostname conflict */ extern char unknown[]; extern char paranoid[]; #define HOSTNAME_KNOWN(s) (STR_NE((s),unknown) && STR_NE((s),paranoid)) #define NOT_INADDR(s) (s[strspn(s,"01234567890./")] != 0) /* Global functions. */ #if defined(TLI) || defined(PTX) || defined(TLI_SEQUENT) -extern void fromhost(); /* get/validate client host info */ +void fromhost(struct request_info *); /* get/validate client host info */ #else #define fromhost sock_host /* no TLI support needed */ #endif -extern int hosts_access(); /* access control */ -extern int hosts_ctl(); /* wrapper around request_init() */ -extern void shell_cmd(); /* execute shell command */ -extern char *percent_x(); /* do % expansion */ -extern void rfc931(); /* client name from RFC 931 daemon */ -extern void clean_exit(); /* clean up and exit */ -extern void refuse(); /* clean up and exit */ -extern char *xgets(); /* fgets() on steroids */ -extern char *split_at(); /* strchr() and split */ -extern unsigned long dot_quad_addr(); /* restricted inet_addr() */ +int hosts_access(struct request_info *); /* access control */ +int hosts_ctl(char *, char *, char *, char *); /* wrapper around request_init() */ +void shell_cmd(char *); /* execute shell command */ +char *percent_x(char *, int, char *, struct request_info *); /* do % expansion */ +void rfc931(TCPD_SOCKADDR *, TCPD_SOCKADDR *, char *); /* client name from RFC 931 daemon */ +void clean_exit(struct request_info *); /* clean up and exit */ +void refuse(struct request_info *); /* clean up and exit */ +char *xgets(char *, int, FILE *); /* fgets() on steroids */ +char *split_at(char *, int); /* strchr() and split */ +unsigned long dot_quad_addr(char *); /* restricted inet_addr() */ + /* Global variables. */ extern int allow_severity; /* for connection logging */ extern int deny_severity; /* for connection logging */ extern char *hosts_allow_table; /* for verification mode redirection */ extern char *hosts_deny_table; /* for verification mode redirection */ extern int hosts_access_verbose; /* for verbose matching mode */ extern int rfc931_timeout; /* user lookup timeout */ extern int resident; /* > 0 if resident process */ /* * Routines for controlled initialization and update of request structure * attributes. Each attribute has its own key. */ -#ifdef __STDC__ -extern struct request_info *request_init(struct request_info *,...); -extern struct request_info *request_set(struct request_info *,...); -#else -extern struct request_info *request_init(); /* initialize request */ -extern struct request_info *request_set(); /* update request structure */ -#endif +struct request_info *request_init(struct request_info *,...); /* initialize request */ +struct request_info *request_set(struct request_info *,...); /* update request structure */ #define RQ_FILE 1 /* file descriptor */ #define RQ_DAEMON 2 /* server process (argv[0]) */ #define RQ_USER 3 /* client user name */ #define RQ_CLIENT_NAME 4 /* client host name */ #define RQ_CLIENT_ADDR 5 /* client host address */ #define RQ_CLIENT_SIN 6 /* client endpoint (internal) */ #define RQ_SERVER_NAME 7 /* server host name */ #define RQ_SERVER_ADDR 8 /* server host address */ #define RQ_SERVER_SIN 9 /* server endpoint (internal) */ /* * Routines for delayed evaluation of request attributes. Each attribute * type has its own access method. The trivial ones are implemented by * macros. The other ones are wrappers around the transport-specific host * name, address, and client user lookup methods. The request_info and * host_info structures serve as caches for the lookup results. */ -extern char *eval_user(); /* client user */ -extern char *eval_hostname(); /* printable hostname */ -extern char *eval_hostaddr(); /* printable host address */ -extern char *eval_hostinfo(); /* host name or address */ -extern char *eval_client(); /* whatever is available */ -extern char *eval_server(); /* whatever is available */ +char *eval_user(struct request_info *); /* client user */ +char *eval_hostname(struct host_info *); /* printable hostname */ +char *eval_hostaddr(struct host_info *); /* printable host address */ +char *eval_hostinfo(struct host_info *); /* host name or address */ +char *eval_client(struct request_info *); /* whatever is available */ +char *eval_server(struct request_info *); /* whatever is available */ #define eval_daemon(r) ((r)->daemon) /* daemon process name */ #define eval_pid(r) ((r)->pid) /* process id */ /* Socket-specific methods, including DNS hostname lookups. */ -extern void sock_host(); /* look up endpoint addresses */ -extern void sock_hostname(); /* translate address to hostname */ -extern void sock_hostaddr(); /* address to printable address */ +void sock_host(struct request_info *); /* look up endpoint addresses */ +void sock_hostname(struct host_info *); /* translate address to hostname */ +void sock_hostaddr(struct host_info *); /* address to printable address */ #define sock_methods(r) \ { (r)->hostname = sock_hostname; (r)->hostaddr = sock_hostaddr; } /* The System V Transport-Level Interface (TLI) interface. */ #if defined(TLI) || defined(PTX) || defined(TLI_SEQUENT) -extern void tli_host(); /* look up endpoint addresses etc. */ +void tli_host(struct request_info *); /* look up endpoint addresses etc. */ #endif /* * Problem reporting interface. Additional file/line context is reported * when available. The jump buffer (tcpd_buf) is not declared here, or * everyone would have to include . */ -#ifdef __STDC__ -extern void tcpd_warn(char *, ...); /* report problem and proceed */ -extern void tcpd_jump(char *, ...); /* report problem and jump */ -#else -extern void tcpd_warn(); -extern void tcpd_jump(); -#endif +void tcpd_warn(char *, ...); /* report problem and proceed */ +void tcpd_jump(char *, ...); /* report problem and jump */ struct tcpd_context { char *file; /* current file */ int line; /* current line */ }; extern struct tcpd_context tcpd_context; /* * While processing access control rules, error conditions are handled by * jumping back into the hosts_access() routine. This is cleaner than * checking the return value of each and every silly little function. The * (-1) returns are here because zero is already taken by longjmp(). */ #define AC_PERMIT 1 /* permit access */ #define AC_DENY (-1) /* deny_access */ #define AC_ERROR AC_DENY /* XXX */ /* * In verification mode an option function should just say what it would do, * instead of really doing it. An option function that would not return * should clear the dry_run flag to inform the caller of this unusual * behavior. */ -extern void process_options(); /* execute options */ -extern int dry_run; /* verification flag */ +void process_options(char *, struct request_info *); /* execute options */ +extern int dry_run; /* verification flag */ /* Bug workarounds. */ #ifdef INET_ADDR_BUG /* inet_addr() returns struct */ #define inet_addr fix_inet_addr -extern long fix_inet_addr(); +long fix_inet_addr(char *); #endif #ifdef BROKEN_FGETS /* partial reads from sockets */ #define fgets fix_fgets -extern char *fix_fgets(); +char *fix_fgets(char *, int, FILE *); #endif #ifdef RECVFROM_BUG /* no address family info */ #define recvfrom fix_recvfrom -extern int fix_recvfrom(); +int fix_recvfrom(int, char *, int, int, struct sockaddr *, int *); #endif #ifdef GETPEERNAME_BUG /* claims success with UDP */ #define getpeername fix_getpeername -extern int fix_getpeername(); +int fix_getpeername(int, struct sockaddr *, int *); #endif #ifdef SOLARIS_24_GETHOSTBYNAME_BUG /* lists addresses as aliases */ #define gethostbyname fix_gethostbyname -extern struct hostent *fix_gethostbyname(); +struct hostent *fix_gethostbyname(char *); #endif #ifdef USE_STRSEP /* libc calls strtok() */ #define strtok fix_strtok -extern char *fix_strtok(); +char *fix_strtok(char *, char *); #endif #ifdef LIBC_CALLS_STRTOK /* libc calls strtok() */ #define strtok my_strtok -extern char *my_strtok(); +char *my_strtok(char *, char *); #endif Index: stable/9/contrib/tcp_wrappers/update.c =================================================================== --- stable/9/contrib/tcp_wrappers/update.c (revision 311815) +++ stable/9/contrib/tcp_wrappers/update.c (revision 311816) @@ -1,129 +1,130 @@ /* * Routines for controlled update/initialization of request structures. * * request_init() initializes its argument. Pointers and string-valued members * are initialized to zero, to indicate that no lookup has been attempted. * * request_set() adds information to an already initialized request structure. * * Both functions take a variable-length name-value list. * * Diagnostics are reported through syslog(3). * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * $FreeBSD$ */ #ifndef lint static char sccsid[] = "@(#) update.c 1.1 94/12/28 17:42:56"; #endif /* System libraries */ #include #include #include +#include /* Local stuff. */ #include "mystdarg.h" #include "tcpd.h" /* request_fill - request update engine */ static struct request_info *request_fill(request, ap) struct request_info *request; va_list ap; { int key; char *ptr; while ((key = va_arg(ap, int)) > 0) { switch (key) { default: tcpd_warn("request_fill: invalid key: %d", key); return (request); case RQ_FILE: request->fd = va_arg(ap, int); continue; case RQ_CLIENT_SIN: #ifdef INET6 request->client->sin = va_arg(ap, struct sockaddr *); #else request->client->sin = va_arg(ap, struct sockaddr_in *); #endif continue; case RQ_SERVER_SIN: #ifdef INET6 request->server->sin = va_arg(ap, struct sockaddr *); #else request->server->sin = va_arg(ap, struct sockaddr_in *); #endif continue; /* * All other fields are strings with the same maximal length. */ case RQ_DAEMON: ptr = request->daemon; break; case RQ_USER: ptr = request->user; break; case RQ_CLIENT_NAME: ptr = request->client->name; break; case RQ_CLIENT_ADDR: ptr = request->client->addr; break; case RQ_SERVER_NAME: ptr = request->server->name; break; case RQ_SERVER_ADDR: ptr = request->server->addr; break; } STRN_CPY(ptr, va_arg(ap, char *), STRING_LENGTH); } return (request); } /* request_init - initialize request structure */ struct request_info *VARARGS(request_init, struct request_info *, request) { static struct request_info default_info; struct request_info *r; va_list ap; /* * Initialize data members. We do not assign default function pointer * members, to avoid pulling in the whole socket module when it is not * really needed. */ VASTART(ap, struct request_info *, request); *request = default_info; request->fd = -1; strcpy(request->daemon, unknown); sprintf(request->pid, "%d", getpid()); request->client->request = request; request->server->request = request; r = request_fill(request, ap); VAEND(ap); return (r); } /* request_set - update request structure */ struct request_info *VARARGS(request_set, struct request_info *, request) { struct request_info *r; va_list ap; VASTART(ap, struct request_info *, request); r = request_fill(request, ap); VAEND(ap); return (r); } Index: stable/9/contrib =================================================================== --- stable/9/contrib (revision 311815) +++ stable/9/contrib (revision 311816) Property changes on: stable/9/contrib ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/contrib:r257398,257404-257406,272949-272950,311459,311461,311556 Index: stable/9 =================================================================== --- stable/9 (revision 311815) +++ stable/9 (revision 311816) Property changes on: stable/9 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r257398,257404-257406,272949-272950,311459,311461,311556