inetd.c revision 77518
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1991, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3529602Scharnierstatic const char copyright[] = 361553Srgrimes"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 371553Srgrimes The Regents of the University of California. All rights reserved.\n"; 381553Srgrimes#endif /* not lint */ 391553Srgrimes 401553Srgrimes#ifndef lint 4129602Scharnier#if 0 4229602Scharnierstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 4329602Scharnier#endif 4429602Scharnierstatic const char rcsid[] = 4550479Speter "$FreeBSD: head/usr.sbin/inetd/inetd.c 77518 2001-05-31 10:09:36Z ume $"; 461553Srgrimes#endif /* not lint */ 471553Srgrimes 481553Srgrimes/* 491553Srgrimes * Inetd - Internet super-server 501553Srgrimes * 511553Srgrimes * This program invokes all internet services as needed. Connection-oriented 521553Srgrimes * services are invoked each time a connection is made, by creating a process. 531553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 541553Srgrimes * to do a getpeername to find out the source host and port. 551553Srgrimes * 561553Srgrimes * Datagram oriented services are invoked when a datagram 571553Srgrimes * arrives; a process is created and passed a pending message 581553Srgrimes * on file descriptor 0. Datagram servers may either connect 591553Srgrimes * to their peer, freeing up the original socket for inetd 601553Srgrimes * to receive further messages on, or ``take over the socket'', 611553Srgrimes * processing all arriving datagrams and, eventually, timing 621553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 638857Srgrimes * the second type of server ``single-threaded''. 641553Srgrimes * 651553Srgrimes * Inetd uses a configuration file which is read at startup 661553Srgrimes * and, possibly, at some later time in response to a hangup signal. 671553Srgrimes * The configuration file is ``free format'' with fields given in the 6867514Sdwmalone * order shown below. Continuation lines for an entry must begin with 691553Srgrimes * a space or tab. All fields must be present in each entry. 701553Srgrimes * 711553Srgrimes * service name must be in /etc/services or must 721553Srgrimes * name a tcpmux service 731553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 7471398Sdwmalone * protocol tcp[4][6][/faith,ttcp], udp[4][6] 751553Srgrimes * wait/nowait single-threaded/multi-threaded 761553Srgrimes * user user to run daemon as 771553Srgrimes * server program full path name 781553Srgrimes * server program arguments maximum of MAXARGS (20) 791553Srgrimes * 801553Srgrimes * TCP services without official port numbers are handled with the 811553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 821553Srgrimes * requests. When a connection is made from a foreign host, the service 831553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 841553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 851553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 861553Srgrimes * server is expected to return the positive reply if the service type in 871553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 881553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 891553Srgrimes * process; this is for compatibility with older server code, and also 901553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 911553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 921553Srgrimes * because they do not have a well-known port and hence cannot listen 931553Srgrimes * for new requests. 941553Srgrimes * 952657Scsgr * For RPC services 962657Scsgr * service name/version must be in /etc/rpc 972657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 9871398Sdwmalone * protocol rpc/tcp, rpc/udp 992657Scsgr * wait/nowait single-threaded/multi-threaded 1002657Scsgr * user user to run daemon as 1012657Scsgr * server program full path name 1022657Scsgr * server program arguments maximum of MAXARGS 1032657Scsgr * 1041553Srgrimes * Comment lines are indicated by a `#' in column 1. 10556590Sshin * 10656590Sshin * #ifdef IPSEC 10756590Sshin * Comment lines that start with "#@" denote IPsec policy string, as described 10856590Sshin * in ipsec_set_policy(3). This will affect all the following items in 10956590Sshin * inetd.conf(8). To reset the policy, just use "#@" line. By default, 11056590Sshin * there's no IPsec policy. 11156590Sshin * #endif 1121553Srgrimes */ 1131553Srgrimes#include <sys/param.h> 1141553Srgrimes#include <sys/ioctl.h> 1151553Srgrimes#include <sys/wait.h> 1161553Srgrimes#include <sys/time.h> 1171553Srgrimes#include <sys/resource.h> 1181553Srgrimes 1191553Srgrimes#include <netinet/in.h> 12036042Sguido#include <netinet/tcp.h> 1211553Srgrimes#include <arpa/inet.h> 1222657Scsgr#include <rpc/rpc.h> 12319617Sjulian#include <rpc/pmap_clnt.h> 1241553Srgrimes 1251553Srgrimes#include <errno.h> 12629602Scharnier#include <err.h> 1271553Srgrimes#include <fcntl.h> 12830807Sache#include <grp.h> 1291553Srgrimes#include <netdb.h> 1301553Srgrimes#include <pwd.h> 1311553Srgrimes#include <signal.h> 1321553Srgrimes#include <stdio.h> 1331553Srgrimes#include <stdlib.h> 1341553Srgrimes#include <string.h> 1351553Srgrimes#include <syslog.h> 13648279Ssheldonh#include <tcpd.h> 1371553Srgrimes#include <unistd.h> 13813142Speter#include <libutil.h> 13919617Sjulian#include <sysexits.h> 14056590Sshin#include <ctype.h> 1411553Srgrimes 14248981Ssheldonh#include "inetd.h" 14348981Ssheldonh#include "pathnames.h" 14448981Ssheldonh 14556590Sshin#ifdef IPSEC 14656590Sshin#include <netinet6/ipsec.h> 14756590Sshin#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 14856590Sshin#undef IPSEC 14956590Sshin#endif 15056590Sshin#endif 15156590Sshin 15256590Sshin/* wrapper for KAME-special getnameinfo() */ 15356590Sshin#ifndef NI_WITHSCOPEID 15456590Sshin#define NI_WITHSCOPEID 0 15556590Sshin#endif 15656590Sshin 15745089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 15845089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 15945089Smarkm#endif 16045089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 16145089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 16245089Smarkm#endif 16345089Smarkm#ifndef LIBWRAP_DENY_FACILITY 16445089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 16545089Smarkm#endif 16645089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 16745089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 16845089Smarkm#endif 16945089Smarkm 17048382Ssheldonh#define ISWRAP(sep) \ 17148697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 17248382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17348382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 17448382Ssheldonh 17521640Speter#ifdef LOGIN_CAP 17621640Speter#include <login_cap.h> 17730792Sache 17830792Sache/* see init.c */ 17930792Sache#define RESOURCE_RC "daemon" 18030792Sache 18121640Speter#endif 18221640Speter 18333794Spst#ifndef MAXCHILD 18433794Spst#define MAXCHILD -1 /* maximum number of this service 18533794Spst < 0 = no limit */ 18633794Spst#endif 18733794Spst 18833794Spst#ifndef MAXCPM 18933794Spst#define MAXCPM -1 /* rate limit invocations from a 19033794Spst single remote address, 19133794Spst < 0 = no limit */ 19233794Spst#endif 19333794Spst 19464197Sdwmalone#ifndef TOOMANY 1952659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 19664197Sdwmalone#endif 1971553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 1981553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 19919618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 2001553Srgrimes 2011553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2021553Srgrimes 20348279Ssheldonhint allow_severity; 20448279Ssheldonhint deny_severity; 20548697Ssheldonhint wrap_ex = 0; 20648279Ssheldonhint wrap_bi = 0; 2071553Srgrimesint debug = 0; 2082659Scsgrint log = 0; 20948988Ssheldonhint maxsock; /* highest-numbered descriptor */ 2101553Srgrimesfd_set allsock; 2111553Srgrimesint options; 2121553Srgrimesint timingout; 2131553Srgrimesint toomany = TOOMANY; 21448069Ssheldonhint maxchild = MAXCHILD; 21548069Ssheldonhint maxcpm = MAXCPM; 2161553Srgrimesstruct servent *sp; 2172657Scsgrstruct rpcent *rpc; 21856590Sshinchar *hostname = NULL; 21956590Sshinstruct sockaddr_in *bind_sa4; 22056590Sshinint no_v4bind = 1; 22156590Sshin#ifdef INET6 22256590Sshinstruct sockaddr_in6 *bind_sa6; 22356590Sshinint no_v6bind = 1; 22456590Sshin#endif 22542122Sdesint signalpipe[2]; 22648991Ssheldonh#ifdef SANITY_CHECK 22748991Ssheldonhint nsock; 22848991Ssheldonh#endif 2291553Srgrimes 23048981Ssheldonhstruct servtab *servtab; 2311553Srgrimes 23248981Ssheldonhextern struct biltin biltins[]; 2331553Srgrimes 2341553Srgrimes#define NUMINT (sizeof(intab) / sizeof(struct inent)) 2351553Srgrimeschar *CONFIG = _PATH_INETDCONF; 23617482Sjulianchar *pid_file = _PATH_INETDPID; 23713142Speter 23813142Speter#ifdef OLD_SETPROCTITLE 2391553Srgrimeschar **Argv; 2401553Srgrimeschar *LastArg; 24113142Speter#endif 2421553Srgrimes 2431553Srgrimesint 24433794Spstgetvalue(arg, value, whine) 24533794Spst char *arg, *whine; 24633794Spst int *value; 24733794Spst{ 24833794Spst int tmp; 24933794Spst char *p; 25033794Spst 25133794Spst tmp = strtol(arg, &p, 0); 25264197Sdwmalone if (tmp < 0 || *p) { 25333794Spst syslog(LOG_ERR, whine, arg); 25433794Spst return 1; /* failure */ 25533794Spst } 25633794Spst *value = tmp; 25733794Spst return 0; /* success */ 25833794Spst} 25933794Spst 26033794Spstint 2611553Srgrimesmain(argc, argv, envp) 2621553Srgrimes int argc; 2631553Srgrimes char *argv[], *envp[]; 2641553Srgrimes{ 2651553Srgrimes struct servtab *sep; 2661553Srgrimes struct passwd *pwd; 26730807Sache struct group *grp; 26848962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 2691553Srgrimes int tmpint, ch, dofork; 2701553Srgrimes pid_t pid; 2711553Srgrimes char buf[50]; 27221640Speter#ifdef LOGIN_CAP 27321640Speter login_cap_t *lc = NULL; 27421640Speter#endif 27545089Smarkm struct request_info req; 27645089Smarkm int denied; 27745089Smarkm char *service = NULL; 27856590Sshin union { 27956590Sshin struct sockaddr peer_un; 28056590Sshin struct sockaddr_in peer_un4; 28156590Sshin struct sockaddr_in6 peer_un6; 28256590Sshin struct sockaddr_storage peer_max; 28356590Sshin } p_un; 28456590Sshin#define peer p_un.peer_un 28556590Sshin#define peer4 p_un.peer_un4 28656590Sshin#define peer6 p_un.peer_un6 28756590Sshin#define peermax p_un.peer_max 28847972Ssheldonh int i; 28956590Sshin struct addrinfo hints, *res; 29056590Sshin char *servname; 29156590Sshin int error; 2921553Srgrimes 29313142Speter 29413142Speter#ifdef OLD_SETPROCTITLE 2951553Srgrimes Argv = argv; 2961553Srgrimes if (envp == 0 || *envp == 0) 2971553Srgrimes envp = argv; 2981553Srgrimes while (*envp) 2991553Srgrimes envp++; 3001553Srgrimes LastArg = envp[-1] + strlen(envp[-1]); 30113142Speter#endif 3021553Srgrimes 3031553Srgrimes openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 3041553Srgrimes 30548697Ssheldonh while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1) 3061553Srgrimes switch(ch) { 3071553Srgrimes case 'd': 3081553Srgrimes debug = 1; 3091553Srgrimes options |= SO_DEBUG; 3101553Srgrimes break; 3112659Scsgr case 'l': 3122659Scsgr log = 1; 3132659Scsgr break; 31433794Spst case 'R': 31533794Spst getvalue(optarg, &toomany, 31633794Spst "-R %s: bad value for service invocation rate"); 3171553Srgrimes break; 31833794Spst case 'c': 31933794Spst getvalue(optarg, &maxchild, 32033794Spst "-c %s: bad value for maximum children"); 32133794Spst break; 32233794Spst case 'C': 32333794Spst getvalue(optarg, &maxcpm, 32433794Spst "-C %s: bad value for maximum children/minute"); 32533794Spst break; 32617482Sjulian case 'a': 32756590Sshin hostname = optarg; 32817482Sjulian break; 32917482Sjulian case 'p': 33017482Sjulian pid_file = optarg; 33117482Sjulian break; 33248279Ssheldonh case 'w': 33348697Ssheldonh wrap_ex++; 33448279Ssheldonh break; 33548697Ssheldonh case 'W': 33648697Ssheldonh wrap_bi++; 33748697Ssheldonh break; 3381553Srgrimes case '?': 3391553Srgrimes default: 3401553Srgrimes syslog(LOG_ERR, 34148697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 34233794Spst " [-c maximum] [-C rate]" 34317482Sjulian " [-p pidfile] [conf-file]"); 34419617Sjulian exit(EX_USAGE); 3451553Srgrimes } 34656590Sshin /* 34756590Sshin * Initialize Bind Addrs. 34856590Sshin * When hostname is NULL, wild card bind addrs are obtained from 34956590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 35056590Sshin * hostname or servname is non NULL. 35156590Sshin * So when hostname is NULL, set dummy value to servname. 35256590Sshin */ 35356590Sshin servname = (hostname == NULL) ? "discard" /* dummy */ : NULL; 35456590Sshin 35556590Sshin bzero(&hints, sizeof(struct addrinfo)); 35656590Sshin hints.ai_flags = AI_PASSIVE; 35756590Sshin hints.ai_family = AF_UNSPEC; 35856590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 35956590Sshin if (error != 0) { 36056590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 36156590Sshin if (error == EAI_SYSTEM) 36256590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 36356590Sshin exit(EX_USAGE); 36456590Sshin } 36556590Sshin do { 36656590Sshin if (res->ai_addr == NULL) { 36756590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 36856590Sshin exit(EX_USAGE); 36956590Sshin } 37056590Sshin switch (res->ai_addr->sa_family) { 37156590Sshin case AF_INET: 37256590Sshin if (no_v4bind == 0) 37356590Sshin continue; 37456590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 37556590Sshin /* init port num in case servname is dummy */ 37656590Sshin bind_sa4->sin_port = 0; 37756590Sshin no_v4bind = 0; 37856590Sshin continue; 37956590Sshin#ifdef INET6 38056590Sshin case AF_INET6: 38156590Sshin if (no_v6bind == 0) 38256590Sshin continue; 38356590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 38456590Sshin /* init port num in case servname is dummy */ 38556590Sshin bind_sa6->sin6_port = 0; 38656590Sshin no_v6bind = 0; 38756590Sshin continue; 38856590Sshin#endif 38956590Sshin } 39056590Sshin if (no_v4bind == 0 39156590Sshin#ifdef INET6 39256590Sshin && no_v6bind == 0 39356590Sshin#endif 39456590Sshin ) 39556590Sshin break; 39656590Sshin } while ((res = res->ai_next) != NULL); 39756590Sshin if (no_v4bind != 0 39856590Sshin#ifdef INET6 39956590Sshin && no_v6bind != 0 40056590Sshin#endif 40156590Sshin ) { 40256590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 40356590Sshin exit(EX_USAGE); 40456590Sshin } 40556590Sshin 4061553Srgrimes argc -= optind; 4071553Srgrimes argv += optind; 4081553Srgrimes 4091553Srgrimes if (argc > 0) 4101553Srgrimes CONFIG = argv[0]; 4111553Srgrimes if (debug == 0) { 41211447Swollman FILE *fp; 41312024Speter if (daemon(0, 0) < 0) { 41412024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 41512024Speter } 41612024Speter /* 41712024Speter * In case somebody has started inetd manually, we need to 41812024Speter * clear the logname, so that old servers run as root do not 41912024Speter * get the user's logname.. 42012024Speter */ 42112024Speter if (setlogin("") < 0) { 42212024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 42312024Speter /* no big deal if it fails.. */ 42412024Speter } 42511447Swollman pid = getpid(); 42617482Sjulian fp = fopen(pid_file, "w"); 42711447Swollman if (fp) { 42811447Swollman fprintf(fp, "%ld\n", (long)pid); 42911447Swollman fclose(fp); 43011447Swollman } else { 43117482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 43211447Swollman } 4331553Srgrimes } 43435948Sbde sa.sa_flags = 0; 43535948Sbde sigemptyset(&sa.sa_mask); 43635948Sbde sigaddset(&sa.sa_mask, SIGALRM); 43735948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 43835948Sbde sigaddset(&sa.sa_mask, SIGHUP); 43942122Sdes sa.sa_handler = flag_retry; 44048962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 44142122Sdes config(); 44242122Sdes sa.sa_handler = flag_config; 44348962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 44442122Sdes sa.sa_handler = flag_reapchild; 44548962Ssheldonh sigaction(SIGCHLD, &sa, &sachld); 44635848Sguido sa.sa_handler = SIG_IGN; 44735948Sbde sigaction(SIGPIPE, &sa, &sapipe); 4481553Srgrimes 4491553Srgrimes { 4501553Srgrimes /* space for daemons to overwrite environment for ps */ 4511553Srgrimes#define DUMMYSIZE 100 4521553Srgrimes char dummy[DUMMYSIZE]; 4531553Srgrimes 45419298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 4551553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 4561553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 4571553Srgrimes } 4581553Srgrimes 45942250Sdes if (pipe(signalpipe) != 0) { 46052219Scharnier syslog(LOG_ERR, "pipe: %m"); 46142250Sdes exit(EX_OSERR); 46242122Sdes } 46342122Sdes FD_SET(signalpipe[0], &allsock); 46448991Ssheldonh#ifdef SANITY_CHECK 46547015Sdes nsock++; 46648991Ssheldonh#endif 46748989Ssheldonh if (signalpipe[0] > maxsock) 46848989Ssheldonh maxsock = signalpipe[0]; 46948989Ssheldonh if (signalpipe[1] > maxsock) 47048989Ssheldonh maxsock = signalpipe[1]; 47141685Sdillon 4721553Srgrimes for (;;) { 4731553Srgrimes int n, ctrl; 4741553Srgrimes fd_set readable; 4751553Srgrimes 47648991Ssheldonh#ifdef SANITY_CHECK 4771553Srgrimes if (nsock == 0) { 47847015Sdes syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 47947015Sdes exit(EX_SOFTWARE); 4801553Srgrimes } 48148991Ssheldonh#endif 4821553Srgrimes readable = allsock; 48342122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 48442122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 48542122Sdes if (n < 0 && errno != EINTR) { 4861553Srgrimes syslog(LOG_WARNING, "select: %m"); 48728907Simp sleep(1); 48828907Simp } 4891553Srgrimes continue; 4901553Srgrimes } 49142122Sdes /* handle any queued signal flags */ 49242250Sdes if (FD_ISSET(signalpipe[0], &readable)) { 49371399Sdwmalone int nsig; 49471399Sdwmalone if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 49542122Sdes syslog(LOG_ERR, "ioctl: %m"); 49642122Sdes exit(EX_OSERR); 49742122Sdes } 49871399Sdwmalone while (--nsig >= 0) { 49942250Sdes char c; 50042250Sdes if (read(signalpipe[0], &c, 1) != 1) { 50142250Sdes syslog(LOG_ERR, "read: %m"); 50242250Sdes exit(EX_OSERR); 50342250Sdes } 50442250Sdes if (debug) 50556482Scharnier warnx("handling signal flag %c", c); 50642250Sdes switch(c) { 50742250Sdes case 'A': /* sigalrm */ 50842250Sdes retry(); 50942250Sdes break; 51042250Sdes case 'C': /* sigchld */ 51142250Sdes reapchild(); 51242250Sdes break; 51342250Sdes case 'H': /* sighup */ 51442250Sdes config(); 51542250Sdes break; 51642250Sdes } 51742250Sdes } 51842122Sdes } 5191553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 5201553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 5211553Srgrimes n--; 5221553Srgrimes if (debug) 52329602Scharnier warnx("someone wants %s", sep->se_service); 52419618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 52553256Speter i = 1; 52653256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 52753256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 5281553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 52971399Sdwmalone (socklen_t *)0); 5301553Srgrimes if (debug) 53129602Scharnier warnx("accept, ctrl %d", ctrl); 5321553Srgrimes if (ctrl < 0) { 5331553Srgrimes if (errno != EINTR) 5341553Srgrimes syslog(LOG_WARNING, 5351553Srgrimes "accept (for %s): %m", 53637844Sphk sep->se_service); 53737816Sphk if (sep->se_accept && 53837816Sphk sep->se_socktype == SOCK_STREAM) 53937816Sphk close(ctrl); 5401553Srgrimes continue; 5411553Srgrimes } 54253256Speter i = 0; 54353256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 54453256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 54553256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 54653256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 54730847Sdima if (cpmip(sep, ctrl) < 0) { 54830847Sdima close(ctrl); 54930847Sdima continue; 55030847Sdima } 5511553Srgrimes } else 5521553Srgrimes ctrl = sep->se_fd; 55348382Ssheldonh if (log && !ISWRAP(sep)) { 55471399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 55571399Sdwmalone socklen_t sl; 55671399Sdwmalone sl = sizeof peermax; 55748382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 55871399Sdwmalone &peermax, &sl)) { 55971399Sdwmalone sl = sizeof peermax; 56048382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 56148382Ssheldonh MSG_PEEK, 56256590Sshin (struct sockaddr *)&peermax, 56371399Sdwmalone &sl) >= 0) { 56456590Sshin getnameinfo((struct sockaddr *)&peermax, 56557383Sshin peer.sa_len, 56656590Sshin pname, sizeof(pname), 56756590Sshin NULL, 0, 56856590Sshin NI_NUMERICHOST| 56956590Sshin NI_WITHSCOPEID); 57056590Sshin } 57156590Sshin } else { 57256590Sshin getnameinfo((struct sockaddr *)&peermax, 57357383Sshin peer.sa_len, 57456590Sshin pname, sizeof(pname), 57556590Sshin NULL, 0, 57656590Sshin NI_NUMERICHOST| 57756590Sshin NI_WITHSCOPEID); 57848382Ssheldonh } 57971399Sdwmalone syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 58048382Ssheldonh } 58142122Sdes (void) sigblock(SIGBLOCK); 5821553Srgrimes pid = 0; 58347972Ssheldonh /* 58448958Ssheldonh * Fork for all external services, builtins which need to 58548958Ssheldonh * fork and anything we're wrapping (as wrapping might 58648958Ssheldonh * block or use hosts_options(5) twist). 58747972Ssheldonh */ 58848382Ssheldonh dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 5891553Srgrimes if (dofork) { 5901553Srgrimes if (sep->se_count++ == 0) 59137856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 59264197Sdwmalone else if (toomany > 0 && sep->se_count >= toomany) { 5931553Srgrimes struct timeval now; 5941553Srgrimes 59537856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 5961553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 5971553Srgrimes CNT_INTVL) { 5981553Srgrimes sep->se_time = now; 5991553Srgrimes sep->se_count = 1; 6001553Srgrimes } else { 6011553Srgrimes syslog(LOG_ERR, 6021553Srgrimes "%s/%s server failing (looping), service terminated", 6031553Srgrimes sep->se_service, sep->se_proto); 60467415Sdwmalone if (sep->se_accept && 60567415Sdwmalone sep->se_socktype == SOCK_STREAM) 60667415Sdwmalone close(ctrl); 6071553Srgrimes close_sep(sep); 60842122Sdes sigsetmask(0L); 6091553Srgrimes if (!timingout) { 6101553Srgrimes timingout = 1; 6111553Srgrimes alarm(RETRYTIME); 6121553Srgrimes } 6131553Srgrimes continue; 6141553Srgrimes } 6151553Srgrimes } 6161553Srgrimes pid = fork(); 6171553Srgrimes } 6181553Srgrimes if (pid < 0) { 6191553Srgrimes syslog(LOG_ERR, "fork: %m"); 62019618Sjulian if (sep->se_accept && 6211553Srgrimes sep->se_socktype == SOCK_STREAM) 6221553Srgrimes close(ctrl); 62342122Sdes sigsetmask(0L); 6241553Srgrimes sleep(1); 6251553Srgrimes continue; 6261553Srgrimes } 62719618Sjulian if (pid) 62819618Sjulian addchild(sep, pid); 62942122Sdes sigsetmask(0L); 6301553Srgrimes if (pid == 0) { 6311553Srgrimes if (dofork) { 6321553Srgrimes if (debug) 63329602Scharnier warnx("+ closing from %d", maxsock); 6341553Srgrimes for (tmpint = maxsock; tmpint > 2; tmpint--) 6351553Srgrimes if (tmpint != ctrl) 63619617Sjulian (void) close(tmpint); 63748962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 63848962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 63948962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 64048962Ssheldonh /* SIGPIPE reset before exec */ 6411553Srgrimes } 64235829Sguido /* 64335829Sguido * Call tcpmux to find the real service to exec. 64435829Sguido */ 64535829Sguido if (sep->se_bi && 64635829Sguido sep->se_bi->bi_fn == (void (*)()) tcpmux) { 64735829Sguido sep = tcpmux(ctrl); 64835829Sguido if (sep == NULL) { 64935829Sguido close(ctrl); 65035829Sguido _exit(0); 65135829Sguido } 65235829Sguido } 65348382Ssheldonh if (ISWRAP(sep)) { 65448698Ssheldonh inetd_setproctitle("wrapping", ctrl); 65547972Ssheldonh service = sep->se_server_name ? 65647972Ssheldonh sep->se_server_name : sep->se_service; 65747972Ssheldonh request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL); 65845089Smarkm fromhost(&req); 65947972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 66047972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 66145089Smarkm denied = !hosts_access(&req); 66245089Smarkm if (denied) { 66345089Smarkm syslog(deny_severity, 66445089Smarkm "refused connection from %.500s, service %s (%s)", 66545089Smarkm eval_client(&req), service, sep->se_proto); 66648382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 66748382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 66864059Sdwmalone if (dofork) { 66964059Sdwmalone sleep(1); 67048382Ssheldonh _exit(0); 67164059Sdwmalone } 67245089Smarkm } 67345089Smarkm if (log) { 67445089Smarkm syslog(allow_severity, 67545089Smarkm "connection from %.500s, service %s (%s)", 67645089Smarkm eval_client(&req), service, sep->se_proto); 67745089Smarkm } 67845089Smarkm } 67919617Sjulian if (sep->se_bi) { 6801553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 68119617Sjulian } else { 6821553Srgrimes if (debug) 68329602Scharnier warnx("%d execl %s", 68429602Scharnier getpid(), sep->se_server); 6851553Srgrimes dup2(ctrl, 0); 6861553Srgrimes close(ctrl); 6871553Srgrimes dup2(0, 1); 6881553Srgrimes dup2(0, 2); 6891553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 6901553Srgrimes syslog(LOG_ERR, 69156482Scharnier "%s/%s: %s: no such user", 6921553Srgrimes sep->se_service, sep->se_proto, 6931553Srgrimes sep->se_user); 6941553Srgrimes if (sep->se_socktype != SOCK_STREAM) 6951553Srgrimes recv(0, buf, sizeof (buf), 0); 69619617Sjulian _exit(EX_NOUSER); 6971553Srgrimes } 69830807Sache grp = NULL; 69930807Sache if ( sep->se_group != NULL 70030807Sache && (grp = getgrnam(sep->se_group)) == NULL 70130807Sache ) { 70230807Sache syslog(LOG_ERR, 70356482Scharnier "%s/%s: %s: no such group", 70430807Sache sep->se_service, sep->se_proto, 70530807Sache sep->se_group); 70630807Sache if (sep->se_socktype != SOCK_STREAM) 70730807Sache recv(0, buf, sizeof (buf), 0); 70830807Sache _exit(EX_NOUSER); 70930807Sache } 71030807Sache if (grp != NULL) 71130807Sache pwd->pw_gid = grp->gr_gid; 71221640Speter#ifdef LOGIN_CAP 71330792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 71430792Sache /* error syslogged by getclass */ 71530792Sache syslog(LOG_ERR, 71630792Sache "%s/%s: %s: login class error", 71737850Sache sep->se_service, sep->se_proto, 71837850Sache sep->se_class); 71930792Sache if (sep->se_socktype != SOCK_STREAM) 72030792Sache recv(0, buf, sizeof (buf), 0); 72130792Sache _exit(EX_NOUSER); 72230792Sache } 72321640Speter#endif 72412024Speter if (setsid() < 0) { 72512024Speter syslog(LOG_ERR, 72612024Speter "%s: can't setsid(): %m", 72712024Speter sep->se_service); 72819617Sjulian /* _exit(EX_OSERR); not fatal yet */ 72912024Speter } 73021640Speter#ifdef LOGIN_CAP 73121640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 73221640Speter LOGIN_SETALL) != 0) { 73321640Speter syslog(LOG_ERR, 73421640Speter "%s: can't setusercontext(..%s..): %m", 73521640Speter sep->se_service, sep->se_user); 73621640Speter _exit(EX_OSERR); 73721640Speter } 73821640Speter#else 7391553Srgrimes if (pwd->pw_uid) { 74012024Speter if (setlogin(sep->se_user) < 0) { 74112024Speter syslog(LOG_ERR, 74212024Speter "%s: can't setlogin(%s): %m", 74312024Speter sep->se_service, sep->se_user); 74419617Sjulian /* _exit(EX_OSERR); not yet */ 74512024Speter } 7461553Srgrimes if (setgid(pwd->pw_gid) < 0) { 7471553Srgrimes syslog(LOG_ERR, 7488857Srgrimes "%s: can't set gid %d: %m", 7491553Srgrimes sep->se_service, pwd->pw_gid); 75019617Sjulian _exit(EX_OSERR); 7511553Srgrimes } 7521553Srgrimes (void) initgroups(pwd->pw_name, 7531553Srgrimes pwd->pw_gid); 7541553Srgrimes if (setuid(pwd->pw_uid) < 0) { 7551553Srgrimes syslog(LOG_ERR, 7568857Srgrimes "%s: can't set uid %d: %m", 7571553Srgrimes sep->se_service, pwd->pw_uid); 75819617Sjulian _exit(EX_OSERR); 7591553Srgrimes } 7601553Srgrimes } 76121640Speter#endif 76235948Sbde sigaction(SIGPIPE, &sapipe, 76335948Sbde (struct sigaction *)0); 7641553Srgrimes execv(sep->se_server, sep->se_argv); 76545089Smarkm syslog(LOG_ERR, 76645089Smarkm "cannot execute %s: %m", sep->se_server); 7671553Srgrimes if (sep->se_socktype != SOCK_STREAM) 7681553Srgrimes recv(0, buf, sizeof (buf), 0); 7691553Srgrimes } 77047972Ssheldonh if (dofork) 77147972Ssheldonh _exit(0); 7721553Srgrimes } 77319618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 7741553Srgrimes close(ctrl); 7751553Srgrimes } 7761553Srgrimes } 7771553Srgrimes} 7781553Srgrimes 77919618Sjulian/* 78042122Sdes * Add a signal flag to the signal flag queue for later handling 78142122Sdes */ 78242122Sdes 78342122Sdesvoid flag_signal(c) 78469546Sdwmalone int c; 78542122Sdes{ 78669546Sdwmalone char ch = c; 78769546Sdwmalone 78869546Sdwmalone if (write(signalpipe[1], &ch, 1) != 1) { 78942250Sdes syslog(LOG_ERR, "write: %m"); 79048985Ssheldonh _exit(EX_OSERR); 79142250Sdes } 79242122Sdes} 79342122Sdes 79442122Sdes/* 79519618Sjulian * Record a new child pid for this service. If we've reached the 79619618Sjulian * limit on children, then stop accepting incoming requests. 79719618Sjulian */ 79819618Sjulian 7991553Srgrimesvoid 80019618Sjulianaddchild(struct servtab *sep, pid_t pid) 80119618Sjulian{ 80264197Sdwmalone if (sep->se_maxchild <= 0) 80364197Sdwmalone return; 80419618Sjulian#ifdef SANITY_CHECK 80519618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 80619618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 80719618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 80819618Sjulian exit(EX_SOFTWARE); 80919618Sjulian } 81019618Sjulian#endif 81119618Sjulian sep->se_pids[sep->se_numchild++] = pid; 81219618Sjulian if (sep->se_numchild == sep->se_maxchild) 81319618Sjulian disable(sep); 81419618Sjulian} 81519618Sjulian 81619618Sjulian/* 81719618Sjulian * Some child process has exited. See if it's on somebody's list. 81819618Sjulian */ 81919618Sjulian 82019618Sjulianvoid 82142122Sdesflag_reapchild(signo) 8221553Srgrimes int signo; 8231553Srgrimes{ 82442250Sdes flag_signal('C'); 82542122Sdes} 82642122Sdes 82742122Sdesvoid 82842122Sdesreapchild() 82942122Sdes{ 83019618Sjulian int k, status; 8311553Srgrimes pid_t pid; 8321553Srgrimes struct servtab *sep; 8331553Srgrimes 8341553Srgrimes for (;;) { 8351553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 8361553Srgrimes if (pid <= 0) 8371553Srgrimes break; 8381553Srgrimes if (debug) 83929602Scharnier warnx("%d reaped, status %#x", pid, status); 84019618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 84119618Sjulian for (k = 0; k < sep->se_numchild; k++) 84219618Sjulian if (sep->se_pids[k] == pid) 84319618Sjulian break; 84419618Sjulian if (k == sep->se_numchild) 84519618Sjulian continue; 84619618Sjulian if (sep->se_numchild == sep->se_maxchild) 84719618Sjulian enable(sep); 84819618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 84919618Sjulian if (status) 85019618Sjulian syslog(LOG_WARNING, 85119618Sjulian "%s[%d]: exit status 0x%x", 85219618Sjulian sep->se_server, pid, status); 85319618Sjulian break; 85419618Sjulian } 8551553Srgrimes } 8561553Srgrimes} 8571553Srgrimes 8581553Srgrimesvoid 85942122Sdesflag_config(signo) 8601553Srgrimes int signo; 8611553Srgrimes{ 86242250Sdes flag_signal('H'); 86342122Sdes} 86442122Sdes 86542122Sdesvoid config() 86642122Sdes{ 86719618Sjulian struct servtab *sep, *new, **sepp; 86842122Sdes long omask; 8691553Srgrimes 8701553Srgrimes if (!setconfig()) { 8711553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 8721553Srgrimes return; 8731553Srgrimes } 8741553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 8751553Srgrimes sep->se_checked = 0; 87619618Sjulian while ((new = getconfigent())) { 87730807Sache if (getpwnam(new->se_user) == NULL) { 8781553Srgrimes syslog(LOG_ERR, 87956482Scharnier "%s/%s: no such user '%s', service ignored", 88019618Sjulian new->se_service, new->se_proto, new->se_user); 8811553Srgrimes continue; 8821553Srgrimes } 88330807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 88430807Sache syslog(LOG_ERR, 88556482Scharnier "%s/%s: no such group '%s', service ignored", 88630807Sache new->se_service, new->se_proto, new->se_group); 88730807Sache continue; 88830807Sache } 88930792Sache#ifdef LOGIN_CAP 89030792Sache if (login_getclass(new->se_class) == NULL) { 89130792Sache /* error syslogged by getclass */ 89230792Sache syslog(LOG_ERR, 89337850Sache "%s/%s: %s: login class error, service ignored", 89437850Sache new->se_service, new->se_proto, new->se_class); 89530792Sache continue; 89630792Sache } 89730792Sache#endif 8981553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 89919618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 90056590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 90156590Sshin sep->se_family == new->se_family) 9021553Srgrimes break; 9031553Srgrimes if (sep != 0) { 9041553Srgrimes int i; 9051553Srgrimes 90619618Sjulian#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 90742122Sdes omask = sigblock(SIGBLOCK); 90856590Sshin if (sep->se_nomapped != new->se_nomapped) { 90956590Sshin sep->se_nomapped = new->se_nomapped; 91056590Sshin sep->se_reset = 1; 91156590Sshin } 91219618Sjulian /* copy over outstanding child pids */ 91364197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 91419618Sjulian new->se_numchild = sep->se_numchild; 91519618Sjulian if (new->se_numchild > new->se_maxchild) 91619618Sjulian new->se_numchild = new->se_maxchild; 91719618Sjulian memcpy(new->se_pids, sep->se_pids, 91819618Sjulian new->se_numchild * sizeof(*new->se_pids)); 91919618Sjulian } 92019618Sjulian SWAP(sep->se_pids, new->se_pids); 92119618Sjulian sep->se_maxchild = new->se_maxchild; 92219618Sjulian sep->se_numchild = new->se_numchild; 92330847Sdima sep->se_maxcpm = new->se_maxcpm; 92466544Sdwmalone sep->se_bi = new->se_bi; 92519618Sjulian /* might need to turn on or off service now */ 92619618Sjulian if (sep->se_fd >= 0) { 92764197Sdwmalone if (sep->se_maxchild > 0 92819618Sjulian && sep->se_numchild == sep->se_maxchild) { 92919618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 93019618Sjulian disable(sep); 93119618Sjulian } else { 93219618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 93319618Sjulian enable(sep); 93419618Sjulian } 93519618Sjulian } 93619618Sjulian sep->se_accept = new->se_accept; 93730807Sache SWAP(sep->se_user, new->se_user); 93830807Sache SWAP(sep->se_group, new->se_group); 93930792Sache#ifdef LOGIN_CAP 94030807Sache SWAP(sep->se_class, new->se_class); 94130792Sache#endif 94230807Sache SWAP(sep->se_server, new->se_server); 94347972Ssheldonh SWAP(sep->se_server_name, new->se_server_name); 9441553Srgrimes for (i = 0; i < MAXARGV; i++) 94519618Sjulian SWAP(sep->se_argv[i], new->se_argv[i]); 94656590Sshin#ifdef IPSEC 94756590Sshin SWAP(sep->se_policy, new->se_policy); 94856590Sshin ipsecsetup(sep); 94956590Sshin#endif 95042122Sdes sigsetmask(omask); 95119618Sjulian freeconfig(new); 9521553Srgrimes if (debug) 9531553Srgrimes print_service("REDO", sep); 9541553Srgrimes } else { 95519618Sjulian sep = enter(new); 9561553Srgrimes if (debug) 9571553Srgrimes print_service("ADD ", sep); 9581553Srgrimes } 9591553Srgrimes sep->se_checked = 1; 9601553Srgrimes if (ISMUX(sep)) { 9611553Srgrimes sep->se_fd = -1; 9621553Srgrimes continue; 9631553Srgrimes } 96456590Sshin switch (sep->se_family) { 96556590Sshin case AF_INET: 96656590Sshin if (no_v4bind != 0) { 96756590Sshin sep->se_fd = -1; 96856590Sshin continue; 96956590Sshin } 97056590Sshin break; 97156590Sshin#ifdef INET6 97256590Sshin case AF_INET6: 97356590Sshin if (no_v6bind != 0) { 97456590Sshin sep->se_fd = -1; 97556590Sshin continue; 97656590Sshin } 97756590Sshin break; 97856590Sshin#endif 97956590Sshin } 9802657Scsgr if (!sep->se_rpc) { 9812657Scsgr sp = getservbyname(sep->se_service, sep->se_proto); 9822657Scsgr if (sp == 0) { 9832657Scsgr syslog(LOG_ERR, "%s/%s: unknown service", 98456590Sshin sep->se_service, sep->se_proto); 9852657Scsgr sep->se_checked = 0; 9862657Scsgr continue; 9872657Scsgr } 98856590Sshin switch (sep->se_family) { 98956590Sshin case AF_INET: 99056590Sshin if (sep->se_ctladdrinitok == 0) { 99156590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 99256590Sshin sizeof(sep->se_ctrladdr4)); 99356590Sshin sep->se_ctrladdr_size = 99456590Sshin sizeof(sep->se_ctrladdr4); 99556590Sshin } 99656590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 99756590Sshin sep->se_ctrladdr4.sin_port = 99856590Sshin sp->s_port; 99956590Sshin sep->se_reset = 1; 100056590Sshin } 100156590Sshin break; 100256590Sshin#ifdef INET6 100356590Sshin case AF_INET6: 100456590Sshin if (sep->se_ctladdrinitok == 0) { 100556590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 100656590Sshin sizeof(sep->se_ctrladdr6)); 100756590Sshin sep->se_ctrladdr_size = 100856590Sshin sizeof(sep->se_ctrladdr6); 100956590Sshin } 101056590Sshin if (sp->s_port != 101156590Sshin sep->se_ctrladdr6.sin6_port) { 101256590Sshin sep->se_ctrladdr6.sin6_port = 101356590Sshin sp->s_port; 101456590Sshin sep->se_reset = 1; 101556590Sshin } 101656590Sshin break; 101756590Sshin#endif 10182657Scsgr } 101956590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 102056590Sshin close_sep(sep); 10212657Scsgr } else { 10222657Scsgr rpc = getrpcbyname(sep->se_service); 10232657Scsgr if (rpc == 0) { 102452219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 10252657Scsgr sep->se_service, sep->se_proto); 10262657Scsgr if (sep->se_fd != -1) 10272657Scsgr (void) close(sep->se_fd); 10282657Scsgr sep->se_fd = -1; 10292657Scsgr continue; 10302657Scsgr } 10312657Scsgr if (rpc->r_number != sep->se_rpc_prog) { 10322657Scsgr if (sep->se_rpc_prog) 10332657Scsgr unregisterrpc(sep); 10342657Scsgr sep->se_rpc_prog = rpc->r_number; 10352657Scsgr if (sep->se_fd != -1) 10362657Scsgr (void) close(sep->se_fd); 10372657Scsgr sep->se_fd = -1; 10382657Scsgr } 10391553Srgrimes } 10401553Srgrimes if (sep->se_fd == -1) 10411553Srgrimes setup(sep); 10421553Srgrimes } 10431553Srgrimes endconfig(); 10441553Srgrimes /* 10451553Srgrimes * Purge anything not looked at above. 10461553Srgrimes */ 104742122Sdes omask = sigblock(SIGBLOCK); 10481553Srgrimes sepp = &servtab; 104919617Sjulian while ((sep = *sepp)) { 10501553Srgrimes if (sep->se_checked) { 10511553Srgrimes sepp = &sep->se_next; 10521553Srgrimes continue; 10531553Srgrimes } 10541553Srgrimes *sepp = sep->se_next; 10551553Srgrimes if (sep->se_fd >= 0) 10561553Srgrimes close_sep(sep); 10571553Srgrimes if (debug) 10581553Srgrimes print_service("FREE", sep); 10592657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 10602657Scsgr unregisterrpc(sep); 10611553Srgrimes freeconfig(sep); 106271399Sdwmalone free(sep); 10631553Srgrimes } 106442122Sdes (void) sigsetmask(omask); 10651553Srgrimes} 10661553Srgrimes 10671553Srgrimesvoid 10682657Scsgrunregisterrpc(sep) 10692657Scsgr struct servtab *sep; 10702657Scsgr{ 10712657Scsgr int i; 10722657Scsgr struct servtab *sepp; 107342122Sdes long omask; 10742657Scsgr 107542122Sdes omask = sigblock(SIGBLOCK); 10762657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 10772657Scsgr if (sepp == sep) 10782657Scsgr continue; 10792657Scsgr if (sep->se_checked == 0 || 10802657Scsgr !sepp->se_rpc || 10812657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 10822657Scsgr continue; 10832657Scsgr return; 10842657Scsgr } 10852657Scsgr if (debug) 10862657Scsgr print_service("UNREG", sep); 10872657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 10882657Scsgr pmap_unset(sep->se_rpc_prog, i); 10892657Scsgr if (sep->se_fd != -1) 10902657Scsgr (void) close(sep->se_fd); 10912657Scsgr sep->se_fd = -1; 109242122Sdes (void) sigsetmask(omask); 10932657Scsgr} 10942657Scsgr 10952657Scsgrvoid 109642122Sdesflag_retry(signo) 10971553Srgrimes int signo; 10981553Srgrimes{ 109942250Sdes flag_signal('A'); 110042122Sdes} 110142122Sdes 110242122Sdesvoid 110342122Sdesretry() 110442122Sdes{ 11051553Srgrimes struct servtab *sep; 11061553Srgrimes 11071553Srgrimes timingout = 0; 11081553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 110919617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 11101553Srgrimes setup(sep); 11111553Srgrimes} 11121553Srgrimes 11131553Srgrimesvoid 11141553Srgrimessetup(sep) 11151553Srgrimes struct servtab *sep; 11161553Srgrimes{ 11171553Srgrimes int on = 1; 11181553Srgrimes 111956590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 11201553Srgrimes if (debug) 112129602Scharnier warn("socket failed on %s/%s", 112229602Scharnier sep->se_service, sep->se_proto); 11231553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 11241553Srgrimes sep->se_service, sep->se_proto); 11251553Srgrimes return; 11261553Srgrimes } 11271553Srgrimes#define turnon(fd, opt) \ 11281553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 11291553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 11301553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 11311553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 11321553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 11331553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 113425253Swollman#ifdef SO_PRIVSTATE 113513956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 113613956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 113725253Swollman#endif 113856590Sshin /* tftpd opens a new connection then needs more infos */ 113956590Sshin if ((sep->se_family == AF_INET6) && 114056590Sshin (strcmp(sep->se_proto, "udp") == 0) && 114156590Sshin (sep->se_accept == 0) && 114256590Sshin (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO, 114356590Sshin (char *)&on, sizeof (on)) < 0)) 114456590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 114556590Sshin#ifdef IPV6_BINDV6ONLY 114658935Sume if (sep->se_family == AF_INET6) { 114758935Sume int flag = sep->se_nomapped ? 1 : 0; 114858935Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, 114958935Sume (char *)&flag, sizeof (flag)) < 0) 115058935Sume syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m"); 115158935Sume } 115256590Sshin#endif /* IPV6_BINDV6ONLY */ 11531553Srgrimes#undef turnon 115436042Sguido if (sep->se_type == TTCP_TYPE) 115536042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 115636042Sguido (char *)&on, sizeof (on)) < 0) 115736042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 115856590Sshin#ifdef IPV6_FAITH 115956590Sshin if (sep->se_type == FAITH_TYPE) { 116056590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 116156590Sshin sizeof(on)) < 0) { 116256590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 116356590Sshin } 116456590Sshin } 116556590Sshin#endif 116656590Sshin#ifdef IPSEC 116756590Sshin ipsecsetup(sep); 116856590Sshin#endif 11691553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 117056590Sshin sep->se_ctrladdr_size) < 0) { 11711553Srgrimes if (debug) 117229602Scharnier warn("bind failed on %s/%s", 117329602Scharnier sep->se_service, sep->se_proto); 11741553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 11751553Srgrimes sep->se_service, sep->se_proto); 11761553Srgrimes (void) close(sep->se_fd); 11771553Srgrimes sep->se_fd = -1; 11781553Srgrimes if (!timingout) { 11791553Srgrimes timingout = 1; 11801553Srgrimes alarm(RETRYTIME); 11811553Srgrimes } 11821553Srgrimes return; 11831553Srgrimes } 11842657Scsgr if (sep->se_rpc) { 118571399Sdwmalone int i; 118671399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 11872657Scsgr 118856590Sshin if (sep->se_family != AF_INET) { 118956590Sshin syslog(LOG_ERR, 119056590Sshin "%s/%s: unsupported address family for rpc", 119156590Sshin sep->se_service, sep->se_proto); 119256590Sshin (void) close(sep->se_fd); 119356590Sshin sep->se_fd = -1; 119456590Sshin return; 119556590Sshin } 11968857Srgrimes if (getsockname(sep->se_fd, 11972657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 11982657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 11992657Scsgr sep->se_service, sep->se_proto); 12002657Scsgr (void) close(sep->se_fd); 12012657Scsgr sep->se_fd = -1; 12028857Srgrimes return; 12032657Scsgr } 12042657Scsgr if (debug) 12052657Scsgr print_service("REG ", sep); 12062657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 12072657Scsgr pmap_unset(sep->se_rpc_prog, i); 12082657Scsgr pmap_set(sep->se_rpc_prog, i, 12092657Scsgr (sep->se_socktype == SOCK_DGRAM) 12102657Scsgr ? IPPROTO_UDP : IPPROTO_TCP, 121156590Sshin ntohs(sep->se_ctrladdr4.sin_port)); 12122657Scsgr } 12132657Scsgr } 12141553Srgrimes if (sep->se_socktype == SOCK_STREAM) 121517197Sdg listen(sep->se_fd, 64); 121619618Sjulian enable(sep); 12171553Srgrimes if (debug) { 121829602Scharnier warnx("registered %s on %d", 12191553Srgrimes sep->se_server, sep->se_fd); 12201553Srgrimes } 12211553Srgrimes} 12221553Srgrimes 122356590Sshin#ifdef IPSEC 122456590Sshinvoid 122556590Sshinipsecsetup(sep) 122656590Sshin struct servtab *sep; 122756590Sshin{ 122856590Sshin char *buf; 122956590Sshin char *policy_in = NULL; 123056590Sshin char *policy_out = NULL; 123156590Sshin int level; 123256590Sshin int opt; 123356590Sshin 123456590Sshin switch (sep->se_family) { 123556590Sshin case AF_INET: 123656590Sshin level = IPPROTO_IP; 123756590Sshin opt = IP_IPSEC_POLICY; 123856590Sshin break; 123956590Sshin#ifdef INET6 124056590Sshin case AF_INET6: 124156590Sshin level = IPPROTO_IPV6; 124256590Sshin opt = IPV6_IPSEC_POLICY; 124356590Sshin break; 124456590Sshin#endif 124556590Sshin default: 124656590Sshin return; 124756590Sshin } 124856590Sshin 124956590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 125056590Sshin policy_in = "in entrust"; 125156590Sshin policy_out = "out entrust"; 125256590Sshin } else { 125356590Sshin if (!strncmp("in", sep->se_policy, 2)) 125456590Sshin policy_in = sep->se_policy; 125556590Sshin else if (!strncmp("out", sep->se_policy, 3)) 125656590Sshin policy_out = sep->se_policy; 125756590Sshin else { 125856590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 125956590Sshin sep->se_policy); 126056590Sshin return; 126156590Sshin } 126256590Sshin } 126356590Sshin 126456590Sshin if (policy_in != NULL) { 126556590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 126656590Sshin if (buf != NULL) { 126756590Sshin if (setsockopt(sep->se_fd, level, opt, 126856675Sshin buf, ipsec_get_policylen(buf)) < 0 && 126956759Sshin debug != 0) 127056759Sshin warnx("%s/%s: ipsec initialization failed; %s", 127156759Sshin sep->se_service, sep->se_proto, 127256759Sshin policy_in); 127356590Sshin free(buf); 127456590Sshin } else 127556590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 127656590Sshin policy_in); 127756590Sshin } 127856590Sshin if (policy_out != NULL) { 127956590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 128056590Sshin if (buf != NULL) { 128156590Sshin if (setsockopt(sep->se_fd, level, opt, 128256675Sshin buf, ipsec_get_policylen(buf)) < 0 && 128356759Sshin debug != 0) 128456759Sshin warnx("%s/%s: ipsec initialization failed; %s", 128556759Sshin sep->se_service, sep->se_proto, 128656759Sshin policy_out); 128756590Sshin free(buf); 128856590Sshin } else 128956590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 129056590Sshin policy_out); 129156590Sshin } 129256590Sshin} 129356590Sshin#endif 129456590Sshin 12951553Srgrimes/* 12961553Srgrimes * Finish with a service and its socket. 12971553Srgrimes */ 12981553Srgrimesvoid 12991553Srgrimesclose_sep(sep) 13001553Srgrimes struct servtab *sep; 13011553Srgrimes{ 13021553Srgrimes if (sep->se_fd >= 0) { 130319618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 130419618Sjulian disable(sep); 13051553Srgrimes (void) close(sep->se_fd); 13061553Srgrimes sep->se_fd = -1; 13071553Srgrimes } 13081553Srgrimes sep->se_count = 0; 130919618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 13101553Srgrimes} 13111553Srgrimes 131248467Ssheldonhint 131348467Ssheldonhmatchservent(name1, name2, proto) 131448467Ssheldonh char *name1, *name2, *proto; 131548467Ssheldonh{ 131648467Ssheldonh char **alias; 131748467Ssheldonh struct servent *se; 131848467Ssheldonh 131949026Sdes if (strcmp(name1, name2) == 0) 132049026Sdes return(1); 132148467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 132248467Ssheldonh if (strcmp(name2, se->s_name) == 0) 132348467Ssheldonh return(1); 132448467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 132548467Ssheldonh if (strcmp(name2, *alias) == 0) 132648467Ssheldonh return(1); 132748467Ssheldonh } 132848467Ssheldonh return(0); 132948467Ssheldonh} 133048467Ssheldonh 13311553Srgrimesstruct servtab * 13321553Srgrimesenter(cp) 13331553Srgrimes struct servtab *cp; 13341553Srgrimes{ 13351553Srgrimes struct servtab *sep; 133642122Sdes long omask; 13371553Srgrimes 13381553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 13391553Srgrimes if (sep == (struct servtab *)0) { 134049102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 134119617Sjulian exit(EX_OSERR); 13421553Srgrimes } 13431553Srgrimes *sep = *cp; 13441553Srgrimes sep->se_fd = -1; 134542122Sdes omask = sigblock(SIGBLOCK); 13461553Srgrimes sep->se_next = servtab; 13471553Srgrimes servtab = sep; 134842122Sdes sigsetmask(omask); 13491553Srgrimes return (sep); 13501553Srgrimes} 13511553Srgrimes 135219618Sjulianvoid 135369546Sdwmaloneenable(sep) 135469546Sdwmalone struct servtab *sep; 135519618Sjulian{ 135619618Sjulian if (debug) 135729602Scharnier warnx( 135819618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 135919618Sjulian#ifdef SANITY_CHECK 136019618Sjulian if (sep->se_fd < 0) { 136119618Sjulian syslog(LOG_ERR, 136219618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 136319618Sjulian exit(EX_SOFTWARE); 136419618Sjulian } 136519618Sjulian if (ISMUX(sep)) { 136619618Sjulian syslog(LOG_ERR, 136719618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 136819618Sjulian exit(EX_SOFTWARE); 136919618Sjulian } 137019618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 137119618Sjulian syslog(LOG_ERR, 137219618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 137319618Sjulian exit(EX_SOFTWARE); 137419618Sjulian } 137548991Ssheldonh nsock++; 137619618Sjulian#endif 137719618Sjulian FD_SET(sep->se_fd, &allsock); 137819618Sjulian if (sep->se_fd > maxsock) 137919618Sjulian maxsock = sep->se_fd; 138019618Sjulian} 138119618Sjulian 138219618Sjulianvoid 138369546Sdwmalonedisable(sep) 138469546Sdwmalone struct servtab *sep; 138519618Sjulian{ 138619618Sjulian if (debug) 138729602Scharnier warnx( 138819618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 138919618Sjulian#ifdef SANITY_CHECK 139019618Sjulian if (sep->se_fd < 0) { 139119618Sjulian syslog(LOG_ERR, 139219618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 139319618Sjulian exit(EX_SOFTWARE); 139419618Sjulian } 139519618Sjulian if (ISMUX(sep)) { 139619618Sjulian syslog(LOG_ERR, 139719618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 139819618Sjulian exit(EX_SOFTWARE); 139919618Sjulian } 140019618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 140119618Sjulian syslog(LOG_ERR, 140219618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 140319618Sjulian exit(EX_SOFTWARE); 140419618Sjulian } 140519618Sjulian if (nsock == 0) { 140619618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 140719618Sjulian exit(EX_SOFTWARE); 140819618Sjulian } 140948991Ssheldonh nsock--; 141019618Sjulian#endif 141119618Sjulian FD_CLR(sep->se_fd, &allsock); 141219618Sjulian if (sep->se_fd == maxsock) 141319618Sjulian maxsock--; 141419618Sjulian} 141519618Sjulian 14161553SrgrimesFILE *fconfig = NULL; 14171553Srgrimesstruct servtab serv; 14181553Srgrimeschar line[LINE_MAX]; 14191553Srgrimes 14201553Srgrimesint 14211553Srgrimessetconfig() 14221553Srgrimes{ 14231553Srgrimes 14241553Srgrimes if (fconfig != NULL) { 14251553Srgrimes fseek(fconfig, 0L, SEEK_SET); 14261553Srgrimes return (1); 14271553Srgrimes } 14281553Srgrimes fconfig = fopen(CONFIG, "r"); 14291553Srgrimes return (fconfig != NULL); 14301553Srgrimes} 14311553Srgrimes 14321553Srgrimesvoid 14331553Srgrimesendconfig() 14341553Srgrimes{ 14351553Srgrimes if (fconfig) { 14361553Srgrimes (void) fclose(fconfig); 14371553Srgrimes fconfig = NULL; 14381553Srgrimes } 14391553Srgrimes} 14401553Srgrimes 14411553Srgrimesstruct servtab * 14421553Srgrimesgetconfigent() 14431553Srgrimes{ 14441553Srgrimes struct servtab *sep = &serv; 14451553Srgrimes int argc; 144619618Sjulian char *cp, *arg, *s; 14472657Scsgr char *versp; 14481553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 14491553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 145056590Sshin#ifdef IPSEC 145156590Sshin char *policy = NULL; 145256590Sshin#endif 145356590Sshin int v4bind = 0; 145456590Sshin#ifdef INET6 145556590Sshin int v6bind = 0; 145656590Sshin#endif 14571553Srgrimes 14581553Srgrimesmore: 145956590Sshin while ((cp = nextline(fconfig)) != NULL) { 146056590Sshin#ifdef IPSEC 146156590Sshin /* lines starting with #@ is not a comment, but the policy */ 146256590Sshin if (cp[0] == '#' && cp[1] == '@') { 146356590Sshin char *p; 146456590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 146556590Sshin ; 146656590Sshin if (*p == '\0') { 146756590Sshin if (policy) 146856590Sshin free(policy); 146956590Sshin policy = NULL; 147056590Sshin } else if (ipsec_get_policylen(p) >= 0) { 147156590Sshin if (policy) 147256590Sshin free(policy); 147356590Sshin policy = newstr(p); 147456590Sshin } else { 147556590Sshin syslog(LOG_ERR, 147656590Sshin "%s: invalid ipsec policy \"%s\"", 147756590Sshin CONFIG, p); 147856590Sshin exit(EX_CONFIG); 147956590Sshin } 148056590Sshin } 148156590Sshin#endif 148256590Sshin if (*cp == '#' || *cp == '\0') 148356590Sshin continue; 148456590Sshin break; 148556590Sshin } 14861553Srgrimes if (cp == NULL) 14871553Srgrimes return ((struct servtab *)0); 14881553Srgrimes /* 14891553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 14901553Srgrimes * for example) don't get initialized here. 14911553Srgrimes */ 149271399Sdwmalone memset(sep, 0, sizeof *sep); 14931553Srgrimes arg = skip(&cp); 14941553Srgrimes if (cp == NULL) { 14951553Srgrimes /* got an empty line containing just blanks/tabs. */ 14961553Srgrimes goto more; 14971553Srgrimes } 14981553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 14991553Srgrimes char *c = arg + MUX_LEN; 15001553Srgrimes if (*c == '+') { 15011553Srgrimes sep->se_type = MUXPLUS_TYPE; 15021553Srgrimes c++; 15031553Srgrimes } else 15041553Srgrimes sep->se_type = MUX_TYPE; 15051553Srgrimes sep->se_service = newstr(c); 15061553Srgrimes } else { 15071553Srgrimes sep->se_service = newstr(arg); 15081553Srgrimes sep->se_type = NORM_TYPE; 15091553Srgrimes } 15101553Srgrimes arg = sskip(&cp); 15111553Srgrimes if (strcmp(arg, "stream") == 0) 15121553Srgrimes sep->se_socktype = SOCK_STREAM; 15131553Srgrimes else if (strcmp(arg, "dgram") == 0) 15141553Srgrimes sep->se_socktype = SOCK_DGRAM; 15151553Srgrimes else if (strcmp(arg, "rdm") == 0) 15161553Srgrimes sep->se_socktype = SOCK_RDM; 15171553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 15181553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 15191553Srgrimes else if (strcmp(arg, "raw") == 0) 15201553Srgrimes sep->se_socktype = SOCK_RAW; 15211553Srgrimes else 15221553Srgrimes sep->se_socktype = -1; 152336042Sguido 152436042Sguido arg = sskip(&cp); 152556590Sshin if (strncmp(arg, "tcp", 3) == 0) { 152656590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 152756590Sshin if (arg != NULL) { 152856590Sshin if (strcmp(arg, "ttcp") == 0) 152956590Sshin sep->se_type = TTCP_TYPE; 153056590Sshin else if (strcmp(arg, "faith") == 0) 153156590Sshin sep->se_type = FAITH_TYPE; 153256590Sshin } 153377518Sume } else { 153477518Sume if (sep->se_type == NORM_TYPE && 153577518Sume strncmp(arg, "faith/", 6) == 0) { 153677518Sume arg += 6; 153777518Sume sep->se_type = FAITH_TYPE; 153877518Sume } 153936042Sguido sep->se_proto = newstr(arg); 154077518Sume } 15412657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 154256973Sshin if (no_v4bind != 0) { 154356973Sshin syslog(LOG_INFO, "IPv4 bind is ignored for %s", 154456973Sshin sep->se_service); 154556590Sshin freeconfig(sep); 154656590Sshin goto more; 154756590Sshin } 154819237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 154919237Sjoerg strlen(sep->se_proto) + 1 - 4); 15502657Scsgr sep->se_rpc = 1; 15512657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 15522657Scsgr sep->se_rpc_lowvers = 0; 155356590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 155456590Sshin sizeof(sep->se_ctrladdr4)); 15552657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 15562657Scsgr *versp++ = '\0'; 15572657Scsgr switch (sscanf(versp, "%d-%d", 15582657Scsgr &sep->se_rpc_lowvers, 15592657Scsgr &sep->se_rpc_highvers)) { 15602657Scsgr case 2: 15612657Scsgr break; 15622657Scsgr case 1: 15632657Scsgr sep->se_rpc_highvers = 15642657Scsgr sep->se_rpc_lowvers; 15652657Scsgr break; 15662657Scsgr default: 15678857Srgrimes syslog(LOG_ERR, 156852219Scharnier "bad RPC version specifier; %s", 15692657Scsgr sep->se_service); 15702657Scsgr freeconfig(sep); 15712657Scsgr goto more; 15722657Scsgr } 15732657Scsgr } 15742657Scsgr else { 15752657Scsgr sep->se_rpc_lowvers = 15762657Scsgr sep->se_rpc_highvers = 1; 15772657Scsgr } 15782657Scsgr } 157956590Sshin sep->se_nomapped = 0; 158056590Sshin while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 158156590Sshin#ifdef INET6 158256590Sshin if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 158356590Sshin if (no_v6bind != 0) { 158456590Sshin syslog(LOG_INFO, "IPv6 bind is ignored for %s", 158556590Sshin sep->se_service); 158656590Sshin freeconfig(sep); 158756590Sshin goto more; 158856590Sshin } 158956590Sshin sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 159056590Sshin v6bind = 1; 159156590Sshin continue; 159256590Sshin } 159356590Sshin#endif 159456590Sshin if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 159556590Sshin sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 159656590Sshin v4bind = 1; 159756590Sshin continue; 159856590Sshin } 159956590Sshin /* illegal version num */ 160056590Sshin syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 160156590Sshin freeconfig(sep); 160256590Sshin goto more; 160356590Sshin } 160456590Sshin#ifdef INET6 160556590Sshin if (v6bind != 0) { 160656590Sshin sep->se_family = AF_INET6; 160756590Sshin if (v4bind == 0 || no_v4bind != 0) 160856590Sshin sep->se_nomapped = 1; 160957906Sshin } else 161056590Sshin#endif 161157906Sshin { /* default to v4 bind if not v6 bind */ 161256590Sshin if (no_v4bind != 0) { 161356590Sshin syslog(LOG_INFO, "IPv4 bind is ignored for %s", 161456590Sshin sep->se_service); 161556590Sshin freeconfig(sep); 161656590Sshin goto more; 161756590Sshin } 161856590Sshin sep->se_family = AF_INET; 161956590Sshin } 162056590Sshin /* init ctladdr */ 162156590Sshin switch(sep->se_family) { 162256590Sshin case AF_INET: 162356590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 162456590Sshin sizeof(sep->se_ctrladdr4)); 162556590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 162656590Sshin sep->se_ctladdrinitok = 1; 162756590Sshin break; 162856590Sshin#ifdef INET6 162956590Sshin case AF_INET6: 163056590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 163156590Sshin sizeof(sep->se_ctrladdr6)); 163256590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 163356590Sshin sep->se_ctladdrinitok = 1; 163456590Sshin break; 163556590Sshin#endif 163656590Sshin } 16371553Srgrimes arg = sskip(&cp); 163819618Sjulian if (!strncmp(arg, "wait", 4)) 163919618Sjulian sep->se_accept = 0; 164019618Sjulian else if (!strncmp(arg, "nowait", 6)) 164119618Sjulian sep->se_accept = 1; 164219618Sjulian else { 164319618Sjulian syslog(LOG_ERR, 164419618Sjulian "%s: bad wait/nowait for service %s", 164519618Sjulian CONFIG, sep->se_service); 164619618Sjulian goto more; 164719618Sjulian } 164848069Ssheldonh sep->se_maxchild = -1; 164948069Ssheldonh sep->se_maxcpm = -1; 165019618Sjulian if ((s = strchr(arg, '/')) != NULL) { 165119618Sjulian char *eptr; 165219618Sjulian u_long val; 165319618Sjulian 165419618Sjulian val = strtoul(s + 1, &eptr, 10); 165530847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 165619618Sjulian syslog(LOG_ERR, 165719618Sjulian "%s: bad max-child for service %s", 165819618Sjulian CONFIG, sep->se_service); 165919618Sjulian goto more; 166019618Sjulian } 166148069Ssheldonh if (debug) 166248069Ssheldonh if (!sep->se_accept && val != 1) 166348069Ssheldonh warnx("maxchild=%lu for wait service %s" 166448069Ssheldonh " not recommended", val, sep->se_service); 166519618Sjulian sep->se_maxchild = val; 166630847Sdima if (*eptr == '/') 166730847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 166830847Sdima /* 166930847Sdima * explicitly do not check for \0 for future expansion / 167030847Sdima * backwards compatibility 167130847Sdima */ 167219618Sjulian } 16731553Srgrimes if (ISMUX(sep)) { 16741553Srgrimes /* 167519618Sjulian * Silently enforce "nowait" mode for TCPMUX services 167619618Sjulian * since they don't have an assigned port to listen on. 16771553Srgrimes */ 167819618Sjulian sep->se_accept = 1; 16791553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 16808857Srgrimes syslog(LOG_ERR, 16811553Srgrimes "%s: bad protocol for tcpmux service %s", 16821553Srgrimes CONFIG, sep->se_service); 16831553Srgrimes goto more; 16841553Srgrimes } 16851553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 16868857Srgrimes syslog(LOG_ERR, 16871553Srgrimes "%s: bad socket type for tcpmux service %s", 16881553Srgrimes CONFIG, sep->se_service); 16891553Srgrimes goto more; 16901553Srgrimes } 16911553Srgrimes } 16921553Srgrimes sep->se_user = newstr(sskip(&cp)); 169330792Sache#ifdef LOGIN_CAP 169430792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 169530792Sache *s = '\0'; 169630792Sache sep->se_class = newstr(s + 1); 169730792Sache } else 169830792Sache sep->se_class = newstr(RESOURCE_RC); 169930792Sache#endif 170030807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 170130807Sache *s = '\0'; 170230807Sache sep->se_group = newstr(s + 1); 170330807Sache } else 170430807Sache sep->se_group = NULL; 17051553Srgrimes sep->se_server = newstr(sskip(&cp)); 170645588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 170745588Smarkm sep->se_server_name++; 17081553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 17091553Srgrimes struct biltin *bi; 17101553Srgrimes 17111553Srgrimes for (bi = biltins; bi->bi_service; bi++) 171249026Sdes if (bi->bi_socktype == sep->se_socktype && 171348467Ssheldonh matchservent(bi->bi_service, sep->se_service, 171448467Ssheldonh sep->se_proto)) 17151553Srgrimes break; 17161553Srgrimes if (bi->bi_service == 0) { 17171553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 17181553Srgrimes sep->se_service); 17191553Srgrimes goto more; 17201553Srgrimes } 172119618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 17221553Srgrimes sep->se_bi = bi; 17231553Srgrimes } else 17241553Srgrimes sep->se_bi = NULL; 172548069Ssheldonh if (sep->se_maxcpm < 0) 172648069Ssheldonh sep->se_maxcpm = maxcpm; 172745588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 172848069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 172919618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 173048069Ssheldonh else if (sep->se_accept) 173148069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 173219618Sjulian else 173348069Ssheldonh sep->se_maxchild = 1; 173445588Smarkm } 173564197Sdwmalone if (sep->se_maxchild > 0) { 173619618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 173719618Sjulian if (sep->se_pids == NULL) { 173849102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 173919618Sjulian exit(EX_OSERR); 174019618Sjulian } 174119618Sjulian } 17421553Srgrimes argc = 0; 17431553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 174419618Sjulian if (argc < MAXARGV) { 17451553Srgrimes sep->se_argv[argc++] = newstr(arg); 174619618Sjulian } else { 174719618Sjulian syslog(LOG_ERR, 174819618Sjulian "%s: too many arguments for service %s", 174919618Sjulian CONFIG, sep->se_service); 175019618Sjulian goto more; 175119618Sjulian } 17521553Srgrimes while (argc <= MAXARGV) 17531553Srgrimes sep->se_argv[argc++] = NULL; 175456590Sshin#ifdef IPSEC 175556590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 175656590Sshin#endif 17571553Srgrimes return (sep); 17581553Srgrimes} 17591553Srgrimes 17601553Srgrimesvoid 17611553Srgrimesfreeconfig(cp) 17621553Srgrimes struct servtab *cp; 17631553Srgrimes{ 17641553Srgrimes int i; 17651553Srgrimes 17661553Srgrimes if (cp->se_service) 17671553Srgrimes free(cp->se_service); 17681553Srgrimes if (cp->se_proto) 17691553Srgrimes free(cp->se_proto); 17701553Srgrimes if (cp->se_user) 17711553Srgrimes free(cp->se_user); 177230807Sache if (cp->se_group) 177330807Sache free(cp->se_group); 177430792Sache#ifdef LOGIN_CAP 177530792Sache if (cp->se_class) 177630792Sache free(cp->se_class); 177730792Sache#endif 17781553Srgrimes if (cp->se_server) 17791553Srgrimes free(cp->se_server); 178019618Sjulian if (cp->se_pids) 178119618Sjulian free(cp->se_pids); 17821553Srgrimes for (i = 0; i < MAXARGV; i++) 17831553Srgrimes if (cp->se_argv[i]) 17841553Srgrimes free(cp->se_argv[i]); 178556590Sshin#ifdef IPSEC 178656590Sshin if (cp->se_policy) 178756590Sshin free(cp->se_policy); 178856590Sshin#endif 17891553Srgrimes} 17901553Srgrimes 17911553Srgrimes 17921553Srgrimes/* 17931553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 17941553Srgrimes * configuration file and exit. 17951553Srgrimes */ 17961553Srgrimeschar * 17971553Srgrimessskip(cpp) 17981553Srgrimes char **cpp; 17991553Srgrimes{ 18001553Srgrimes char *cp; 18011553Srgrimes 18021553Srgrimes cp = skip(cpp); 18031553Srgrimes if (cp == NULL) { 18041553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 180519617Sjulian exit(EX_DATAERR); 18061553Srgrimes } 18071553Srgrimes return (cp); 18081553Srgrimes} 18091553Srgrimes 18101553Srgrimeschar * 18111553Srgrimesskip(cpp) 18121553Srgrimes char **cpp; 18131553Srgrimes{ 18141553Srgrimes char *cp = *cpp; 18151553Srgrimes char *start; 181611933Sadam char quote = '\0'; 18171553Srgrimes 18181553Srgrimesagain: 18191553Srgrimes while (*cp == ' ' || *cp == '\t') 18201553Srgrimes cp++; 18211553Srgrimes if (*cp == '\0') { 18221553Srgrimes int c; 18231553Srgrimes 18241553Srgrimes c = getc(fconfig); 18251553Srgrimes (void) ungetc(c, fconfig); 18261553Srgrimes if (c == ' ' || c == '\t') 182719617Sjulian if ((cp = nextline(fconfig))) 18281553Srgrimes goto again; 18291553Srgrimes *cpp = (char *)0; 18301553Srgrimes return ((char *)0); 18311553Srgrimes } 183211933Sadam if (*cp == '"' || *cp == '\'') 183311933Sadam quote = *cp++; 18341553Srgrimes start = cp; 183511933Sadam if (quote) 183611933Sadam while (*cp && *cp != quote) 183711933Sadam cp++; 183811933Sadam else 183911933Sadam while (*cp && *cp != ' ' && *cp != '\t') 184011933Sadam cp++; 18411553Srgrimes if (*cp != '\0') 18421553Srgrimes *cp++ = '\0'; 18431553Srgrimes *cpp = cp; 18441553Srgrimes return (start); 18451553Srgrimes} 18461553Srgrimes 18471553Srgrimeschar * 18481553Srgrimesnextline(fd) 18491553Srgrimes FILE *fd; 18501553Srgrimes{ 18511553Srgrimes char *cp; 18521553Srgrimes 18531553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 18541553Srgrimes return ((char *)0); 18551553Srgrimes cp = strchr(line, '\n'); 18561553Srgrimes if (cp) 18571553Srgrimes *cp = '\0'; 18581553Srgrimes return (line); 18591553Srgrimes} 18601553Srgrimes 18611553Srgrimeschar * 18621553Srgrimesnewstr(cp) 18631553Srgrimes char *cp; 18641553Srgrimes{ 186519617Sjulian if ((cp = strdup(cp ? cp : ""))) 18661553Srgrimes return (cp); 18671553Srgrimes syslog(LOG_ERR, "strdup: %m"); 186819617Sjulian exit(EX_OSERR); 18691553Srgrimes} 18701553Srgrimes 187113142Speter#ifdef OLD_SETPROCTITLE 18721553Srgrimesvoid 187313142Speterinetd_setproctitle(a, s) 18741553Srgrimes char *a; 18751553Srgrimes int s; 18761553Srgrimes{ 18771553Srgrimes int size; 18781553Srgrimes char *cp; 187956590Sshin struct sockaddr_storage ss; 188056590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 18811553Srgrimes 18821553Srgrimes cp = Argv[0]; 188356590Sshin size = sizeof(ss); 188456590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 188556590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 188656590Sshin NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 188756590Sshin (void) sprintf(buf, "-%s [%s]", a, pbuf); 188856590Sshin } else 18898857Srgrimes (void) sprintf(buf, "-%s", a); 18901553Srgrimes strncpy(cp, buf, LastArg - cp); 18911553Srgrimes cp += strlen(cp); 18921553Srgrimes while (cp < LastArg) 18931553Srgrimes *cp++ = ' '; 18941553Srgrimes} 189513142Speter#else 189613142Spetervoid 189713142Speterinetd_setproctitle(a, s) 189813142Speter char *a; 189913142Speter int s; 190013142Speter{ 190171399Sdwmalone socklen_t size; 190256590Sshin struct sockaddr_storage ss; 190356590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 19041553Srgrimes 190556590Sshin size = sizeof(ss); 190656590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 190756590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 190856590Sshin NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 190956590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 191056590Sshin } else 191113142Speter (void) sprintf(buf, "%s", a); 191213142Speter setproctitle("%s", buf); 191313142Speter} 191413142Speter#endif 191513142Speter 191613142Speter 19171553Srgrimes/* 19181553Srgrimes * Internet services provided internally by inetd: 19191553Srgrimes */ 19201553Srgrimes 192156590Sshinint check_loop(sa, sep) 192256590Sshin struct sockaddr *sa; 19235182Swollman struct servtab *sep; 19245182Swollman{ 19255182Swollman struct servtab *se2; 192656590Sshin char pname[INET6_ADDRSTRLEN]; 19275182Swollman 19285182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 19295182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 19305182Swollman continue; 19315182Swollman 193256590Sshin switch (se2->se_family) { 193356590Sshin case AF_INET: 193456590Sshin if (((struct sockaddr_in *)sa)->sin_port == 193556590Sshin se2->se_ctrladdr4.sin_port) 193656590Sshin goto isloop; 193756590Sshin continue; 193856590Sshin#ifdef INET6 193956590Sshin case AF_INET6: 194056590Sshin if (((struct sockaddr_in *)sa)->sin_port == 194156590Sshin se2->se_ctrladdr4.sin_port) 194256590Sshin goto isloop; 194356590Sshin continue; 194456590Sshin#endif 194556590Sshin default: 194656590Sshin continue; 19475182Swollman } 194856590Sshin isloop: 194956590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 195056590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 195156590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 195256590Sshin sep->se_service, sep->se_proto, 195356590Sshin se2->se_service, se2->se_proto, 195456590Sshin pname); 195556590Sshin return 1; 19565182Swollman } 19575182Swollman return 0; 19585182Swollman} 19595182Swollman 19601553Srgrimes/* 19611553Srgrimes * print_service: 19621553Srgrimes * Dump relevant information to stderr 19631553Srgrimes */ 19641553Srgrimesvoid 19651553Srgrimesprint_service(action, sep) 19661553Srgrimes char *action; 19671553Srgrimes struct servtab *sep; 19681553Srgrimes{ 196919617Sjulian fprintf(stderr, 197056590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 197130792Sache#ifdef LOGIN_CAP 197256590Sshin "class=%s" 197330792Sache#endif 197456590Sshin " builtin=%p server=%s" 197556590Sshin#ifdef IPSEC 197656590Sshin " policy=\"%s\"" 197756590Sshin#endif 197856590Sshin "\n", 197919617Sjulian action, sep->se_service, sep->se_proto, 198030807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 198130792Sache#ifdef LOGIN_CAP 198230792Sache sep->se_class, 198330792Sache#endif 198456590Sshin (void *) sep->se_bi, sep->se_server 198556590Sshin#ifdef IPSEC 198656590Sshin , (sep->se_policy ? sep->se_policy : "") 198756590Sshin#endif 198856590Sshin ); 19891553Srgrimes} 19901553Srgrimes 199130847Sdima#define CPMHSIZE 256 199230847Sdima#define CPMHMASK (CPMHSIZE-1) 199330847Sdima#define CHTGRAN 10 199430847Sdima#define CHTSIZE 6 199530847Sdima 199630847Sdimatypedef struct CTime { 199730847Sdima unsigned long ct_Ticks; 199830847Sdima int ct_Count; 199930847Sdima} CTime; 200030847Sdima 200130847Sdimatypedef struct CHash { 200256590Sshin union { 200356590Sshin struct in_addr c4_Addr; 200456590Sshin struct in6_addr c6_Addr; 200556590Sshin } cu_Addr; 200656590Sshin#define ch_Addr4 cu_Addr.c4_Addr 200756590Sshin#define ch_Addr6 cu_Addr.c6_Addr 200856590Sshin int ch_Family; 200930847Sdima time_t ch_LTime; 201030847Sdima char *ch_Service; 201130847Sdima CTime ch_Times[CHTSIZE]; 201230847Sdima} CHash; 201330847Sdima 201430847SdimaCHash CHashAry[CPMHSIZE]; 201530847Sdima 201630847Sdimaint 201730847Sdimacpmip(sep, ctrl) 201830847Sdima struct servtab *sep; 201930847Sdima int ctrl; 202030847Sdima{ 202156590Sshin struct sockaddr_storage rss; 202271399Sdwmalone socklen_t rssLen = sizeof(rss); 202330847Sdima int r = 0; 202430847Sdima 202530847Sdima /* 202630847Sdima * If getpeername() fails, just let it through (if logging is 202730847Sdima * enabled the condition is caught elsewhere) 202830847Sdima */ 202930847Sdima 203030847Sdima if (sep->se_maxcpm > 0 && 203156590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 203230847Sdima time_t t = time(NULL); 203330847Sdima int hv = 0xABC3D20F; 203430847Sdima int i; 203530847Sdima int cnt = 0; 203630847Sdima CHash *chBest = NULL; 203730847Sdima unsigned int ticks = t / CHTGRAN; 203856590Sshin struct sockaddr_in *sin; 203956590Sshin#ifdef INET6 204056590Sshin struct sockaddr_in6 *sin6; 204156590Sshin#endif 204230847Sdima 204356590Sshin sin = (struct sockaddr_in *)&rss; 204456590Sshin#ifdef INET6 204556590Sshin sin6 = (struct sockaddr_in6 *)&rss; 204656590Sshin#endif 204730847Sdima { 204830847Sdima char *p; 204956590Sshin int i, addrlen; 205030847Sdima 205156590Sshin switch (rss.ss_family) { 205256590Sshin case AF_INET: 205356590Sshin p = (char *)&sin->sin_addr; 205456590Sshin addrlen = sizeof(struct in_addr); 205556590Sshin break; 205656590Sshin#ifdef INET6 205756590Sshin case AF_INET6: 205856590Sshin p = (char *)&sin6->sin6_addr; 205956590Sshin addrlen = sizeof(struct in6_addr); 206056590Sshin break; 206156590Sshin#endif 206256590Sshin default: 206356590Sshin /* should not happen */ 206456590Sshin return -1; 206556590Sshin } 206656590Sshin 206756590Sshin for (i = 0; i < addrlen; ++i, ++p) { 206830847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 206930847Sdima } 207030847Sdima hv = (hv ^ (hv >> 16)); 207130847Sdima } 207230847Sdima for (i = 0; i < 5; ++i) { 207330847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 207430847Sdima 207556590Sshin if (rss.ss_family == AF_INET && 207656590Sshin ch->ch_Family == AF_INET && 207756590Sshin sin->sin_addr.s_addr == ch->ch_Addr4.s_addr && 207830847Sdima ch->ch_Service && strcmp(sep->se_service, 207930847Sdima ch->ch_Service) == 0) { 208030847Sdima chBest = ch; 208130847Sdima break; 208230847Sdima } 208356590Sshin#ifdef INET6 208456590Sshin if (rss.ss_family == AF_INET6 && 208556590Sshin ch->ch_Family == AF_INET6 && 208656590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 208756590Sshin &ch->ch_Addr6) != 0 && 208856590Sshin ch->ch_Service && strcmp(sep->se_service, 208956590Sshin ch->ch_Service) == 0) { 209056590Sshin chBest = ch; 209156590Sshin break; 209256590Sshin } 209356590Sshin#endif 209430847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 209530847Sdima ch->ch_LTime < chBest->ch_LTime) { 209630847Sdima chBest = ch; 209730847Sdima } 209830847Sdima } 209956590Sshin if ((rss.ss_family == AF_INET && 210056590Sshin (chBest->ch_Family != AF_INET || 210156590Sshin sin->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 210230847Sdima chBest->ch_Service == NULL || 210330847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 210456590Sshin chBest->ch_Family = sin->sin_family; 210556590Sshin chBest->ch_Addr4 = sin->sin_addr; 210630847Sdima if (chBest->ch_Service) 210730847Sdima free(chBest->ch_Service); 210830847Sdima chBest->ch_Service = strdup(sep->se_service); 210930847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 211030847Sdima } 211156590Sshin#ifdef INET6 211256590Sshin if ((rss.ss_family == AF_INET6 && 211356590Sshin (chBest->ch_Family != AF_INET6 || 211456590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 211556590Sshin &chBest->ch_Addr6) == 0)) || 211656590Sshin chBest->ch_Service == NULL || 211756590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 211856590Sshin chBest->ch_Family = sin6->sin6_family; 211956590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 212056590Sshin if (chBest->ch_Service) 212156590Sshin free(chBest->ch_Service); 212256590Sshin chBest->ch_Service = strdup(sep->se_service); 212356590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 212456590Sshin } 212556590Sshin#endif 212630847Sdima chBest->ch_LTime = t; 212730847Sdima { 212830847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 212930847Sdima if (ct->ct_Ticks != ticks) { 213030847Sdima ct->ct_Ticks = ticks; 213130847Sdima ct->ct_Count = 0; 213230847Sdima } 213330847Sdima ++ct->ct_Count; 213430847Sdima } 213530847Sdima for (i = 0; i < CHTSIZE; ++i) { 213630847Sdima CTime *ct = &chBest->ch_Times[i]; 213730847Sdima if (ct->ct_Ticks <= ticks && 213830847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 213930847Sdima cnt += ct->ct_Count; 214030847Sdima } 214130847Sdima } 214230847Sdima if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 214356590Sshin char pname[INET6_ADDRSTRLEN]; 214456590Sshin 214556590Sshin getnameinfo((struct sockaddr *)&rss, 214656590Sshin ((struct sockaddr *)&rss)->sa_len, 214756590Sshin pname, sizeof(pname), NULL, 0, 214856590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 214930847Sdima r = -1; 215030847Sdima syslog(LOG_ERR, 215133794Spst "%s from %s exceeded counts/min (limit %d/min)", 215256590Sshin sep->se_service, pname, 215333794Spst sep->se_maxcpm); 215430847Sdima } 215530847Sdima } 215630847Sdima return(r); 215730847Sdima} 2158