inetd.c revision 127865
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 441553Srgrimes#endif /* not lint */ 451553Srgrimes 4698563Sjmallett#include <sys/cdefs.h> 4798563Sjmallett__FBSDID("$FreeBSD: head/usr.sbin/inetd/inetd.c 127865 2004-04-04 21:32:23Z dwmalone $"); 4898563Sjmallett 491553Srgrimes/* 501553Srgrimes * Inetd - Internet super-server 511553Srgrimes * 521553Srgrimes * This program invokes all internet services as needed. Connection-oriented 531553Srgrimes * services are invoked each time a connection is made, by creating a process. 541553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 551553Srgrimes * to do a getpeername to find out the source host and port. 561553Srgrimes * 571553Srgrimes * Datagram oriented services are invoked when a datagram 581553Srgrimes * arrives; a process is created and passed a pending message 591553Srgrimes * on file descriptor 0. Datagram servers may either connect 601553Srgrimes * to their peer, freeing up the original socket for inetd 611553Srgrimes * to receive further messages on, or ``take over the socket'', 621553Srgrimes * processing all arriving datagrams and, eventually, timing 631553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 648857Srgrimes * the second type of server ``single-threaded''. 651553Srgrimes * 661553Srgrimes * Inetd uses a configuration file which is read at startup 671553Srgrimes * and, possibly, at some later time in response to a hangup signal. 681553Srgrimes * The configuration file is ``free format'' with fields given in the 6967514Sdwmalone * order shown below. Continuation lines for an entry must begin with 701553Srgrimes * a space or tab. All fields must be present in each entry. 711553Srgrimes * 7278356Sdwmalone * service name must be in /etc/services 7378356Sdwmalone * or name a tcpmux service 7478356Sdwmalone * or specify a unix domain socket 751553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 7678356Sdwmalone * protocol tcp[4][6][/faith,ttcp], udp[4][6], unix 771553Srgrimes * wait/nowait single-threaded/multi-threaded 781553Srgrimes * user user to run daemon as 791553Srgrimes * server program full path name 801553Srgrimes * server program arguments maximum of MAXARGS (20) 811553Srgrimes * 821553Srgrimes * TCP services without official port numbers are handled with the 831553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 841553Srgrimes * requests. When a connection is made from a foreign host, the service 851553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 861553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 871553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 881553Srgrimes * server is expected to return the positive reply if the service type in 891553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 901553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 911553Srgrimes * process; this is for compatibility with older server code, and also 921553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 931553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 941553Srgrimes * because they do not have a well-known port and hence cannot listen 951553Srgrimes * for new requests. 961553Srgrimes * 972657Scsgr * For RPC services 982657Scsgr * service name/version must be in /etc/rpc 992657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 100100127Salfred * protocol rpc/tcp[4][6], rpc/udp[4][6] 1012657Scsgr * wait/nowait single-threaded/multi-threaded 1022657Scsgr * user user to run daemon as 1032657Scsgr * server program full path name 1042657Scsgr * server program arguments maximum of MAXARGS 1052657Scsgr * 1061553Srgrimes * Comment lines are indicated by a `#' in column 1. 10756590Sshin * 10856590Sshin * #ifdef IPSEC 10956590Sshin * Comment lines that start with "#@" denote IPsec policy string, as described 11056590Sshin * in ipsec_set_policy(3). This will affect all the following items in 11156590Sshin * inetd.conf(8). To reset the policy, just use "#@" line. By default, 11256590Sshin * there's no IPsec policy. 11356590Sshin * #endif 1141553Srgrimes */ 1151553Srgrimes#include <sys/param.h> 1161553Srgrimes#include <sys/ioctl.h> 1171553Srgrimes#include <sys/wait.h> 1181553Srgrimes#include <sys/time.h> 1191553Srgrimes#include <sys/resource.h> 12078356Sdwmalone#include <sys/stat.h> 12178356Sdwmalone#include <sys/un.h> 1221553Srgrimes 1231553Srgrimes#include <netinet/in.h> 12436042Sguido#include <netinet/tcp.h> 1251553Srgrimes#include <arpa/inet.h> 1262657Scsgr#include <rpc/rpc.h> 12719617Sjulian#include <rpc/pmap_clnt.h> 1281553Srgrimes 129106054Swollman#include <ctype.h> 1301553Srgrimes#include <errno.h> 13129602Scharnier#include <err.h> 1321553Srgrimes#include <fcntl.h> 13330807Sache#include <grp.h> 134106054Swollman#include <libutil.h> 135106054Swollman#include <limits.h> 1361553Srgrimes#include <netdb.h> 1371553Srgrimes#include <pwd.h> 1381553Srgrimes#include <signal.h> 1391553Srgrimes#include <stdio.h> 1401553Srgrimes#include <stdlib.h> 1411553Srgrimes#include <string.h> 142106054Swollman#include <sysexits.h> 1431553Srgrimes#include <syslog.h> 14448279Ssheldonh#include <tcpd.h> 1451553Srgrimes#include <unistd.h> 1461553Srgrimes 14748981Ssheldonh#include "inetd.h" 14848981Ssheldonh#include "pathnames.h" 14948981Ssheldonh 15056590Sshin#ifdef IPSEC 15156590Sshin#include <netinet6/ipsec.h> 15256590Sshin#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 15356590Sshin#undef IPSEC 15456590Sshin#endif 15556590Sshin#endif 15656590Sshin 15756590Sshin/* wrapper for KAME-special getnameinfo() */ 15856590Sshin#ifndef NI_WITHSCOPEID 15956590Sshin#define NI_WITHSCOPEID 0 16056590Sshin#endif 16156590Sshin 16245089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 16345089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 16445089Smarkm#endif 16545089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 16645089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 16745089Smarkm#endif 16845089Smarkm#ifndef LIBWRAP_DENY_FACILITY 16945089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 17045089Smarkm#endif 17145089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 17245089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 17345089Smarkm#endif 17445089Smarkm 17548382Ssheldonh#define ISWRAP(sep) \ 17648697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 17778356Sdwmalone && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 17848382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17948382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 18048382Ssheldonh 18121640Speter#ifdef LOGIN_CAP 18221640Speter#include <login_cap.h> 18330792Sache 18430792Sache/* see init.c */ 18530792Sache#define RESOURCE_RC "daemon" 18630792Sache 18721640Speter#endif 18821640Speter 18933794Spst#ifndef MAXCHILD 19033794Spst#define MAXCHILD -1 /* maximum number of this service 19133794Spst < 0 = no limit */ 19233794Spst#endif 19333794Spst 19433794Spst#ifndef MAXCPM 19533794Spst#define MAXCPM -1 /* rate limit invocations from a 19633794Spst single remote address, 19733794Spst < 0 = no limit */ 19833794Spst#endif 19933794Spst 200101474Sume#ifndef MAXPERIP 201101474Sume#define MAXPERIP -1 /* maximum number of this service 202101474Sume from a single remote address, 203101474Sume < 0 = no limit */ 204101474Sume#endif 205101474Sume 20664197Sdwmalone#ifndef TOOMANY 2072659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 20864197Sdwmalone#endif 2091553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 2101553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 21119618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 2121553Srgrimes 2131553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2141553Srgrimes 21598562Sjmallettvoid close_sep(struct servtab *); 21698562Sjmallettvoid flag_signal(int); 21798562Sjmallettvoid flag_config(int); 21898562Sjmallettvoid config(void); 21998562Sjmallettint cpmip(const struct servtab *, int); 22098562Sjmallettvoid endconfig(void); 22198562Sjmallettstruct servtab *enter(struct servtab *); 22298562Sjmallettvoid freeconfig(struct servtab *); 22398562Sjmallettstruct servtab *getconfigent(void); 22498562Sjmallettint matchservent(const char *, const char *, const char *); 22598562Sjmallettchar *nextline(FILE *); 22698562Sjmallettvoid addchild(struct servtab *, int); 22798562Sjmallettvoid flag_reapchild(int); 22898562Sjmallettvoid reapchild(void); 22998562Sjmallettvoid enable(struct servtab *); 23098562Sjmallettvoid disable(struct servtab *); 23198562Sjmallettvoid flag_retry(int); 23298562Sjmallettvoid retry(void); 23398562Sjmallettint setconfig(void); 23498562Sjmallettvoid setup(struct servtab *); 23578694Sdwmalone#ifdef IPSEC 23698562Sjmallettvoid ipsecsetup(struct servtab *); 23778694Sdwmalone#endif 23898562Sjmallettvoid unregisterrpc(register struct servtab *sep); 239101474Sumestatic struct conninfo *search_conn(struct servtab *sep, int ctrl); 240101474Sumestatic int room_conn(struct servtab *sep, struct conninfo *conn); 241101474Sumestatic void addchild_conn(struct conninfo *conn, pid_t pid); 242101474Sumestatic void reapchild_conn(pid_t pid); 243101474Sumestatic void free_conn(struct conninfo *conn); 244101474Sumestatic void resize_conn(struct servtab *sep, int maxperip); 245101474Sumestatic void free_connlist(struct servtab *sep); 246101474Sumestatic void free_proc(struct procinfo *); 247101474Sumestatic struct procinfo *search_proc(pid_t pid, int add); 248101474Sumestatic int hashval(char *p, int len); 24978694Sdwmalone 25048279Ssheldonhint allow_severity; 25148279Ssheldonhint deny_severity; 25248697Ssheldonhint wrap_ex = 0; 25348279Ssheldonhint wrap_bi = 0; 2541553Srgrimesint debug = 0; 255121766Speterint dolog = 0; 25648988Ssheldonhint maxsock; /* highest-numbered descriptor */ 2571553Srgrimesfd_set allsock; 2581553Srgrimesint options; 2591553Srgrimesint timingout; 2601553Srgrimesint toomany = TOOMANY; 26148069Ssheldonhint maxchild = MAXCHILD; 26248069Ssheldonhint maxcpm = MAXCPM; 263101474Sumeint maxperip = MAXPERIP; 2641553Srgrimesstruct servent *sp; 2652657Scsgrstruct rpcent *rpc; 26656590Sshinchar *hostname = NULL; 26756590Sshinstruct sockaddr_in *bind_sa4; 268102938Sdwmaloneint v4bind_ok = 0; 26956590Sshin#ifdef INET6 27056590Sshinstruct sockaddr_in6 *bind_sa6; 271102938Sdwmaloneint v6bind_ok = 0; 27256590Sshin#endif 27342122Sdesint signalpipe[2]; 27448991Ssheldonh#ifdef SANITY_CHECK 27548991Ssheldonhint nsock; 27648991Ssheldonh#endif 27778356Sdwmaloneuid_t euid; 27878356Sdwmalonegid_t egid; 27978356Sdwmalonemode_t mask; 2801553Srgrimes 28148981Ssheldonhstruct servtab *servtab; 2821553Srgrimes 28348981Ssheldonhextern struct biltin biltins[]; 2841553Srgrimes 28578694Sdwmaloneconst char *CONFIG = _PATH_INETDCONF; 28678694Sdwmaloneconst char *pid_file = _PATH_INETDPID; 28713142Speter 288100127Salfredstruct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 289100127Salfred 290101474Sumestatic LIST_HEAD(, procinfo) proctable[PERIPSIZE]; 291101474Sume 2921553Srgrimesint 29398558Sjmallettgetvalue(const char *arg, int *value, const char *whine) 29433794Spst{ 29533794Spst int tmp; 29633794Spst char *p; 29733794Spst 29833794Spst tmp = strtol(arg, &p, 0); 29964197Sdwmalone if (tmp < 0 || *p) { 30033794Spst syslog(LOG_ERR, whine, arg); 30133794Spst return 1; /* failure */ 30233794Spst } 30333794Spst *value = tmp; 30433794Spst return 0; /* success */ 30533794Spst} 30633794Spst 307110802Sumestatic sa_family_t 308110802Sumewhichaf(struct request_info *req) 309110802Sume{ 310110802Sume struct sockaddr *sa; 311110802Sume 312110802Sume sa = (struct sockaddr *)req->client->sin; 313110802Sume if (sa == NULL) 314110802Sume return AF_UNSPEC; 315110802Sume if (sa->sa_family == AF_INET6 && 316110802Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) 317110802Sume return AF_INET; 318110802Sume return sa->sa_family; 319110802Sume} 320110802Sume 32133794Spstint 32298558Sjmallettmain(int argc, char **argv) 3231553Srgrimes{ 3241553Srgrimes struct servtab *sep; 3251553Srgrimes struct passwd *pwd; 32630807Sache struct group *grp; 32748962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 328121555Speter int ch, dofork; 3291553Srgrimes pid_t pid; 3301553Srgrimes char buf[50]; 33121640Speter#ifdef LOGIN_CAP 33221640Speter login_cap_t *lc = NULL; 33321640Speter#endif 33445089Smarkm struct request_info req; 33545089Smarkm int denied; 33645089Smarkm char *service = NULL; 33756590Sshin union { 33856590Sshin struct sockaddr peer_un; 33956590Sshin struct sockaddr_in peer_un4; 34056590Sshin struct sockaddr_in6 peer_un6; 34156590Sshin struct sockaddr_storage peer_max; 34256590Sshin } p_un; 34356590Sshin#define peer p_un.peer_un 34456590Sshin#define peer4 p_un.peer_un4 34556590Sshin#define peer6 p_un.peer_un6 34656590Sshin#define peermax p_un.peer_max 34747972Ssheldonh int i; 34856590Sshin struct addrinfo hints, *res; 34978694Sdwmalone const char *servname; 35056590Sshin int error; 351101474Sume struct conninfo *conn; 3521553Srgrimes 35397293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 3541553Srgrimes 355101474Sume while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1) 3561553Srgrimes switch(ch) { 3571553Srgrimes case 'd': 3581553Srgrimes debug = 1; 3591553Srgrimes options |= SO_DEBUG; 3601553Srgrimes break; 3612659Scsgr case 'l': 362121766Speter dolog = 1; 3632659Scsgr break; 36433794Spst case 'R': 36533794Spst getvalue(optarg, &toomany, 36633794Spst "-R %s: bad value for service invocation rate"); 3671553Srgrimes break; 36833794Spst case 'c': 36933794Spst getvalue(optarg, &maxchild, 37033794Spst "-c %s: bad value for maximum children"); 37133794Spst break; 37233794Spst case 'C': 37333794Spst getvalue(optarg, &maxcpm, 37433794Spst "-C %s: bad value for maximum children/minute"); 37533794Spst break; 37617482Sjulian case 'a': 37756590Sshin hostname = optarg; 37817482Sjulian break; 37917482Sjulian case 'p': 38017482Sjulian pid_file = optarg; 38117482Sjulian break; 382101474Sume case 's': 383101474Sume getvalue(optarg, &maxperip, 384101474Sume "-s %s: bad value for maximum children per source address"); 385101474Sume break; 38648279Ssheldonh case 'w': 38748697Ssheldonh wrap_ex++; 38848279Ssheldonh break; 38948697Ssheldonh case 'W': 39048697Ssheldonh wrap_bi++; 39148697Ssheldonh break; 3921553Srgrimes case '?': 3931553Srgrimes default: 3941553Srgrimes syslog(LOG_ERR, 39548697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 39633794Spst " [-c maximum] [-C rate]" 39717482Sjulian " [-p pidfile] [conf-file]"); 39819617Sjulian exit(EX_USAGE); 3991553Srgrimes } 40056590Sshin /* 40156590Sshin * Initialize Bind Addrs. 40256590Sshin * When hostname is NULL, wild card bind addrs are obtained from 40356590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 40456590Sshin * hostname or servname is non NULL. 40556590Sshin * So when hostname is NULL, set dummy value to servname. 40656590Sshin */ 40756590Sshin servname = (hostname == NULL) ? "discard" /* dummy */ : NULL; 40856590Sshin 40956590Sshin bzero(&hints, sizeof(struct addrinfo)); 41056590Sshin hints.ai_flags = AI_PASSIVE; 41156590Sshin hints.ai_family = AF_UNSPEC; 41256590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 41356590Sshin if (error != 0) { 41456590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 41556590Sshin if (error == EAI_SYSTEM) 41656590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 41756590Sshin exit(EX_USAGE); 41856590Sshin } 41956590Sshin do { 42056590Sshin if (res->ai_addr == NULL) { 42156590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 42256590Sshin exit(EX_USAGE); 42356590Sshin } 42456590Sshin switch (res->ai_addr->sa_family) { 42556590Sshin case AF_INET: 426102938Sdwmalone if (v4bind_ok) 42756590Sshin continue; 42856590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 42956590Sshin /* init port num in case servname is dummy */ 43056590Sshin bind_sa4->sin_port = 0; 431102938Sdwmalone v4bind_ok = 1; 43256590Sshin continue; 43356590Sshin#ifdef INET6 43456590Sshin case AF_INET6: 435102938Sdwmalone if (v6bind_ok) 43656590Sshin continue; 43756590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 43856590Sshin /* init port num in case servname is dummy */ 43956590Sshin bind_sa6->sin6_port = 0; 440102938Sdwmalone v6bind_ok = 1; 44156590Sshin continue; 44256590Sshin#endif 44356590Sshin } 444102938Sdwmalone if (v4bind_ok 44556590Sshin#ifdef INET6 446102938Sdwmalone && v6bind_ok 44756590Sshin#endif 44856590Sshin ) 44956590Sshin break; 45056590Sshin } while ((res = res->ai_next) != NULL); 451102938Sdwmalone if (!v4bind_ok 45256590Sshin#ifdef INET6 453102938Sdwmalone && !v6bind_ok 45456590Sshin#endif 45556590Sshin ) { 45656590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 45756590Sshin exit(EX_USAGE); 45856590Sshin } 45956590Sshin 46078356Sdwmalone euid = geteuid(); 46178356Sdwmalone egid = getegid(); 46278356Sdwmalone umask(mask = umask(0777)); 46378356Sdwmalone 4641553Srgrimes argc -= optind; 4651553Srgrimes argv += optind; 4661553Srgrimes 4671553Srgrimes if (argc > 0) 4681553Srgrimes CONFIG = argv[0]; 469127301Sdwmalone if (access(CONFIG, R_OK) < 0) 470127301Sdwmalone syslog(LOG_ERR, "Accessing %s: %m, continuing anyway.", CONFIG); 4711553Srgrimes if (debug == 0) { 47211447Swollman FILE *fp; 47312024Speter if (daemon(0, 0) < 0) { 47412024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 47512024Speter } 47697293Sjwd /* From now on we don't want syslog messages going to stderr. */ 47797293Sjwd closelog(); 47897293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 47912024Speter /* 48012024Speter * In case somebody has started inetd manually, we need to 48112024Speter * clear the logname, so that old servers run as root do not 48212024Speter * get the user's logname.. 48312024Speter */ 48412024Speter if (setlogin("") < 0) { 48512024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 48612024Speter /* no big deal if it fails.. */ 48712024Speter } 48811447Swollman pid = getpid(); 48917482Sjulian fp = fopen(pid_file, "w"); 49011447Swollman if (fp) { 49111447Swollman fprintf(fp, "%ld\n", (long)pid); 49211447Swollman fclose(fp); 49311447Swollman } else { 49417482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 49511447Swollman } 4961553Srgrimes } 497100127Salfred 498101474Sume for (i = 0; i < PERIPSIZE; ++i) 499101474Sume LIST_INIT(&proctable[i]); 500101474Sume 501102938Sdwmalone if (v4bind_ok) { 502100127Salfred udpconf = getnetconfigent("udp"); 503100127Salfred tcpconf = getnetconfigent("tcp"); 504100127Salfred if (udpconf == NULL || tcpconf == NULL) { 505102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 506100127Salfred exit(EX_USAGE); 507100127Salfred } 508100127Salfred } 509100127Salfred#ifdef INET6 510102938Sdwmalone if (v6bind_ok) { 511100127Salfred udp6conf = getnetconfigent("udp6"); 512100127Salfred tcp6conf = getnetconfigent("tcp6"); 513100127Salfred if (udp6conf == NULL || tcp6conf == NULL) { 514102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 515100127Salfred exit(EX_USAGE); 516100127Salfred } 517100127Salfred } 518100127Salfred#endif 519100127Salfred 52035948Sbde sa.sa_flags = 0; 52135948Sbde sigemptyset(&sa.sa_mask); 52235948Sbde sigaddset(&sa.sa_mask, SIGALRM); 52335948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 52435948Sbde sigaddset(&sa.sa_mask, SIGHUP); 52542122Sdes sa.sa_handler = flag_retry; 52648962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 52742122Sdes config(); 52842122Sdes sa.sa_handler = flag_config; 52948962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 53042122Sdes sa.sa_handler = flag_reapchild; 53148962Ssheldonh sigaction(SIGCHLD, &sa, &sachld); 53235848Sguido sa.sa_handler = SIG_IGN; 53335948Sbde sigaction(SIGPIPE, &sa, &sapipe); 5341553Srgrimes 5351553Srgrimes { 5361553Srgrimes /* space for daemons to overwrite environment for ps */ 5371553Srgrimes#define DUMMYSIZE 100 5381553Srgrimes char dummy[DUMMYSIZE]; 5391553Srgrimes 54019298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 5411553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 5421553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 5431553Srgrimes } 5441553Srgrimes 54542250Sdes if (pipe(signalpipe) != 0) { 54652219Scharnier syslog(LOG_ERR, "pipe: %m"); 54742250Sdes exit(EX_OSERR); 54842122Sdes } 549111324Sdwmalone if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 || 550111324Sdwmalone fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) { 551111324Sdwmalone syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m"); 552111324Sdwmalone exit(EX_OSERR); 553111324Sdwmalone } 55442122Sdes FD_SET(signalpipe[0], &allsock); 55548991Ssheldonh#ifdef SANITY_CHECK 55647015Sdes nsock++; 55748991Ssheldonh#endif 55848989Ssheldonh if (signalpipe[0] > maxsock) 55948989Ssheldonh maxsock = signalpipe[0]; 56048989Ssheldonh if (signalpipe[1] > maxsock) 56148989Ssheldonh maxsock = signalpipe[1]; 56241685Sdillon 5631553Srgrimes for (;;) { 5641553Srgrimes int n, ctrl; 5651553Srgrimes fd_set readable; 5661553Srgrimes 56748991Ssheldonh#ifdef SANITY_CHECK 5681553Srgrimes if (nsock == 0) { 56947015Sdes syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 57047015Sdes exit(EX_SOFTWARE); 5711553Srgrimes } 57248991Ssheldonh#endif 5731553Srgrimes readable = allsock; 57442122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 57542122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 57642122Sdes if (n < 0 && errno != EINTR) { 5771553Srgrimes syslog(LOG_WARNING, "select: %m"); 57828907Simp sleep(1); 57928907Simp } 5801553Srgrimes continue; 5811553Srgrimes } 58242122Sdes /* handle any queued signal flags */ 58342250Sdes if (FD_ISSET(signalpipe[0], &readable)) { 58471399Sdwmalone int nsig; 58571399Sdwmalone if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 58642122Sdes syslog(LOG_ERR, "ioctl: %m"); 58742122Sdes exit(EX_OSERR); 58842122Sdes } 58971399Sdwmalone while (--nsig >= 0) { 59042250Sdes char c; 59142250Sdes if (read(signalpipe[0], &c, 1) != 1) { 59242250Sdes syslog(LOG_ERR, "read: %m"); 59342250Sdes exit(EX_OSERR); 59442250Sdes } 59542250Sdes if (debug) 59656482Scharnier warnx("handling signal flag %c", c); 59742250Sdes switch(c) { 59842250Sdes case 'A': /* sigalrm */ 59942250Sdes retry(); 60042250Sdes break; 60142250Sdes case 'C': /* sigchld */ 60242250Sdes reapchild(); 60342250Sdes break; 60442250Sdes case 'H': /* sighup */ 60542250Sdes config(); 60642250Sdes break; 60742250Sdes } 60842250Sdes } 60942122Sdes } 6101553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 6111553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 6121553Srgrimes n--; 6131553Srgrimes if (debug) 61429602Scharnier warnx("someone wants %s", sep->se_service); 615101474Sume dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 616101474Sume conn = NULL; 61719618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 61853256Speter i = 1; 61953256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 62053256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 6211553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62271399Sdwmalone (socklen_t *)0); 6231553Srgrimes if (debug) 62429602Scharnier warnx("accept, ctrl %d", ctrl); 6251553Srgrimes if (ctrl < 0) { 6261553Srgrimes if (errno != EINTR) 6271553Srgrimes syslog(LOG_WARNING, 6281553Srgrimes "accept (for %s): %m", 62937844Sphk sep->se_service); 63037816Sphk if (sep->se_accept && 63137816Sphk sep->se_socktype == SOCK_STREAM) 63237816Sphk close(ctrl); 6331553Srgrimes continue; 6341553Srgrimes } 63553256Speter i = 0; 63653256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 63753256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 63853256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 63953256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 64030847Sdima if (cpmip(sep, ctrl) < 0) { 64130847Sdima close(ctrl); 64230847Sdima continue; 64330847Sdima } 644101474Sume if (dofork && 645101474Sume (conn = search_conn(sep, ctrl)) != NULL && 646101474Sume !room_conn(sep, conn)) { 647101474Sume close(ctrl); 648101474Sume continue; 649101474Sume } 6501553Srgrimes } else 6511553Srgrimes ctrl = sep->se_fd; 652121766Speter if (dolog && !ISWRAP(sep)) { 65371399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 65471399Sdwmalone socklen_t sl; 65571399Sdwmalone sl = sizeof peermax; 65648382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 65771399Sdwmalone &peermax, &sl)) { 65871399Sdwmalone sl = sizeof peermax; 65948382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 66048382Ssheldonh MSG_PEEK, 66156590Sshin (struct sockaddr *)&peermax, 66271399Sdwmalone &sl) >= 0) { 66356590Sshin getnameinfo((struct sockaddr *)&peermax, 66457383Sshin peer.sa_len, 66556590Sshin pname, sizeof(pname), 66656590Sshin NULL, 0, 66756590Sshin NI_NUMERICHOST| 66856590Sshin NI_WITHSCOPEID); 66956590Sshin } 67056590Sshin } else { 67156590Sshin getnameinfo((struct sockaddr *)&peermax, 67257383Sshin peer.sa_len, 67356590Sshin pname, sizeof(pname), 67456590Sshin NULL, 0, 67556590Sshin NI_NUMERICHOST| 67656590Sshin NI_WITHSCOPEID); 67748382Ssheldonh } 67871399Sdwmalone syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 67948382Ssheldonh } 68042122Sdes (void) sigblock(SIGBLOCK); 6811553Srgrimes pid = 0; 68247972Ssheldonh /* 68348958Ssheldonh * Fork for all external services, builtins which need to 68448958Ssheldonh * fork and anything we're wrapping (as wrapping might 68548958Ssheldonh * block or use hosts_options(5) twist). 68647972Ssheldonh */ 6871553Srgrimes if (dofork) { 6881553Srgrimes if (sep->se_count++ == 0) 68937856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 69064197Sdwmalone else if (toomany > 0 && sep->se_count >= toomany) { 6911553Srgrimes struct timeval now; 6921553Srgrimes 69337856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 6941553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 6951553Srgrimes CNT_INTVL) { 6961553Srgrimes sep->se_time = now; 6971553Srgrimes sep->se_count = 1; 6981553Srgrimes } else { 6991553Srgrimes syslog(LOG_ERR, 7001553Srgrimes "%s/%s server failing (looping), service terminated", 7011553Srgrimes sep->se_service, sep->se_proto); 70267415Sdwmalone if (sep->se_accept && 70367415Sdwmalone sep->se_socktype == SOCK_STREAM) 70467415Sdwmalone close(ctrl); 7051553Srgrimes close_sep(sep); 706101474Sume free_conn(conn); 70742122Sdes sigsetmask(0L); 7081553Srgrimes if (!timingout) { 7091553Srgrimes timingout = 1; 7101553Srgrimes alarm(RETRYTIME); 7111553Srgrimes } 7121553Srgrimes continue; 7131553Srgrimes } 7141553Srgrimes } 7151553Srgrimes pid = fork(); 7161553Srgrimes } 7171553Srgrimes if (pid < 0) { 7181553Srgrimes syslog(LOG_ERR, "fork: %m"); 71919618Sjulian if (sep->se_accept && 7201553Srgrimes sep->se_socktype == SOCK_STREAM) 7211553Srgrimes close(ctrl); 722101474Sume free_conn(conn); 72342122Sdes sigsetmask(0L); 7241553Srgrimes sleep(1); 7251553Srgrimes continue; 7261553Srgrimes } 727101474Sume if (pid) { 728101474Sume addchild_conn(conn, pid); 72919618Sjulian addchild(sep, pid); 730101474Sume } 73142122Sdes sigsetmask(0L); 7321553Srgrimes if (pid == 0) { 7331553Srgrimes if (dofork) { 73448962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73548962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 73648962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 73748962Ssheldonh /* SIGPIPE reset before exec */ 7381553Srgrimes } 73935829Sguido /* 74035829Sguido * Call tcpmux to find the real service to exec. 74135829Sguido */ 74235829Sguido if (sep->se_bi && 74378694Sdwmalone sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 74435829Sguido sep = tcpmux(ctrl); 74535829Sguido if (sep == NULL) { 74635829Sguido close(ctrl); 74735829Sguido _exit(0); 74835829Sguido } 74935829Sguido } 75048382Ssheldonh if (ISWRAP(sep)) { 75148698Ssheldonh inetd_setproctitle("wrapping", ctrl); 75247972Ssheldonh service = sep->se_server_name ? 75347972Ssheldonh sep->se_server_name : sep->se_service; 754127865Sdwmalone request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, 0); 75545089Smarkm fromhost(&req); 75647972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 75747972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 75845089Smarkm denied = !hosts_access(&req); 75945089Smarkm if (denied) { 76045089Smarkm syslog(deny_severity, 76196224Sume "refused connection from %.500s, service %s (%s%s)", 76296224Sume eval_client(&req), service, sep->se_proto, 763110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 76448382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 76548382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 76664059Sdwmalone if (dofork) { 76764059Sdwmalone sleep(1); 76848382Ssheldonh _exit(0); 76964059Sdwmalone } 77045089Smarkm } 771121766Speter if (dolog) { 77245089Smarkm syslog(allow_severity, 77396224Sume "connection from %.500s, service %s (%s%s)", 77496224Sume eval_client(&req), service, sep->se_proto, 775110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 77645089Smarkm } 77745089Smarkm } 77819617Sjulian if (sep->se_bi) { 7791553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 78019617Sjulian } else { 7811553Srgrimes if (debug) 78229602Scharnier warnx("%d execl %s", 78329602Scharnier getpid(), sep->se_server); 784111324Sdwmalone /* Clear close-on-exec. */ 785111324Sdwmalone if (fcntl(ctrl, F_SETFD, 0) < 0) { 786111324Sdwmalone syslog(LOG_ERR, 787111324Sdwmalone "%s/%s: fcntl (F_SETFD, 0): %m", 788111324Sdwmalone sep->se_service, sep->se_proto); 789111324Sdwmalone _exit(EX_OSERR); 790111324Sdwmalone } 791111324Sdwmalone if (ctrl != 0) { 792111324Sdwmalone dup2(ctrl, 0); 793111324Sdwmalone close(ctrl); 794111324Sdwmalone } 7951553Srgrimes dup2(0, 1); 7961553Srgrimes dup2(0, 2); 7971553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 7981553Srgrimes syslog(LOG_ERR, 79956482Scharnier "%s/%s: %s: no such user", 8001553Srgrimes sep->se_service, sep->se_proto, 8011553Srgrimes sep->se_user); 8021553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8031553Srgrimes recv(0, buf, sizeof (buf), 0); 80419617Sjulian _exit(EX_NOUSER); 8051553Srgrimes } 80630807Sache grp = NULL; 80730807Sache if ( sep->se_group != NULL 80830807Sache && (grp = getgrnam(sep->se_group)) == NULL 80930807Sache ) { 81030807Sache syslog(LOG_ERR, 81156482Scharnier "%s/%s: %s: no such group", 81230807Sache sep->se_service, sep->se_proto, 81330807Sache sep->se_group); 81430807Sache if (sep->se_socktype != SOCK_STREAM) 81530807Sache recv(0, buf, sizeof (buf), 0); 81630807Sache _exit(EX_NOUSER); 81730807Sache } 81830807Sache if (grp != NULL) 81930807Sache pwd->pw_gid = grp->gr_gid; 82021640Speter#ifdef LOGIN_CAP 82130792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 82230792Sache /* error syslogged by getclass */ 82330792Sache syslog(LOG_ERR, 82430792Sache "%s/%s: %s: login class error", 82537850Sache sep->se_service, sep->se_proto, 82637850Sache sep->se_class); 82730792Sache if (sep->se_socktype != SOCK_STREAM) 82830792Sache recv(0, buf, sizeof (buf), 0); 82930792Sache _exit(EX_NOUSER); 83030792Sache } 83121640Speter#endif 83212024Speter if (setsid() < 0) { 83312024Speter syslog(LOG_ERR, 83412024Speter "%s: can't setsid(): %m", 83512024Speter sep->se_service); 83619617Sjulian /* _exit(EX_OSERR); not fatal yet */ 83712024Speter } 83821640Speter#ifdef LOGIN_CAP 83921640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 840109349Srwatson LOGIN_SETALL & ~LOGIN_SETMAC) 841108951Srwatson != 0) { 84221640Speter syslog(LOG_ERR, 84321640Speter "%s: can't setusercontext(..%s..): %m", 84421640Speter sep->se_service, sep->se_user); 84521640Speter _exit(EX_OSERR); 84621640Speter } 847111323Sdwmalone login_close(lc); 84821640Speter#else 8491553Srgrimes if (pwd->pw_uid) { 85012024Speter if (setlogin(sep->se_user) < 0) { 85112024Speter syslog(LOG_ERR, 85212024Speter "%s: can't setlogin(%s): %m", 85312024Speter sep->se_service, sep->se_user); 85419617Sjulian /* _exit(EX_OSERR); not yet */ 85512024Speter } 8561553Srgrimes if (setgid(pwd->pw_gid) < 0) { 8571553Srgrimes syslog(LOG_ERR, 8588857Srgrimes "%s: can't set gid %d: %m", 8591553Srgrimes sep->se_service, pwd->pw_gid); 86019617Sjulian _exit(EX_OSERR); 8611553Srgrimes } 8621553Srgrimes (void) initgroups(pwd->pw_name, 8631553Srgrimes pwd->pw_gid); 8641553Srgrimes if (setuid(pwd->pw_uid) < 0) { 8651553Srgrimes syslog(LOG_ERR, 8668857Srgrimes "%s: can't set uid %d: %m", 8671553Srgrimes sep->se_service, pwd->pw_uid); 86819617Sjulian _exit(EX_OSERR); 8691553Srgrimes } 8701553Srgrimes } 87121640Speter#endif 87235948Sbde sigaction(SIGPIPE, &sapipe, 87335948Sbde (struct sigaction *)0); 8741553Srgrimes execv(sep->se_server, sep->se_argv); 87545089Smarkm syslog(LOG_ERR, 87645089Smarkm "cannot execute %s: %m", sep->se_server); 8771553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8781553Srgrimes recv(0, buf, sizeof (buf), 0); 8791553Srgrimes } 88047972Ssheldonh if (dofork) 88147972Ssheldonh _exit(0); 8821553Srgrimes } 88319618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 8841553Srgrimes close(ctrl); 8851553Srgrimes } 8861553Srgrimes } 8871553Srgrimes} 8881553Srgrimes 88919618Sjulian/* 89042122Sdes * Add a signal flag to the signal flag queue for later handling 89142122Sdes */ 89242122Sdes 89378694Sdwmalonevoid 89498558Sjmallettflag_signal(int c) 89542122Sdes{ 89669546Sdwmalone char ch = c; 89769546Sdwmalone 89869546Sdwmalone if (write(signalpipe[1], &ch, 1) != 1) { 89942250Sdes syslog(LOG_ERR, "write: %m"); 90048985Ssheldonh _exit(EX_OSERR); 90142250Sdes } 90242122Sdes} 90342122Sdes 90442122Sdes/* 90519618Sjulian * Record a new child pid for this service. If we've reached the 90619618Sjulian * limit on children, then stop accepting incoming requests. 90719618Sjulian */ 90819618Sjulian 9091553Srgrimesvoid 91019618Sjulianaddchild(struct servtab *sep, pid_t pid) 91119618Sjulian{ 91264197Sdwmalone if (sep->se_maxchild <= 0) 91364197Sdwmalone return; 91419618Sjulian#ifdef SANITY_CHECK 91519618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 91619618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 91719618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 91819618Sjulian exit(EX_SOFTWARE); 91919618Sjulian } 92019618Sjulian#endif 92119618Sjulian sep->se_pids[sep->se_numchild++] = pid; 92219618Sjulian if (sep->se_numchild == sep->se_maxchild) 92319618Sjulian disable(sep); 92419618Sjulian} 92519618Sjulian 92619618Sjulian/* 92719618Sjulian * Some child process has exited. See if it's on somebody's list. 92819618Sjulian */ 92919618Sjulian 93019618Sjulianvoid 93198561Sjmallettflag_reapchild(int signo __unused) 9321553Srgrimes{ 93342250Sdes flag_signal('C'); 93442122Sdes} 93542122Sdes 93642122Sdesvoid 93798558Sjmallettreapchild(void) 93842122Sdes{ 93919618Sjulian int k, status; 9401553Srgrimes pid_t pid; 9411553Srgrimes struct servtab *sep; 9421553Srgrimes 9431553Srgrimes for (;;) { 9441553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 9451553Srgrimes if (pid <= 0) 9461553Srgrimes break; 9471553Srgrimes if (debug) 948102939Sdwmalone warnx("%d reaped, %s %u", pid, 949102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 950102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 951102939Sdwmalone : WTERMSIG(status)); 95219618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 95319618Sjulian for (k = 0; k < sep->se_numchild; k++) 95419618Sjulian if (sep->se_pids[k] == pid) 95519618Sjulian break; 95619618Sjulian if (k == sep->se_numchild) 95719618Sjulian continue; 95819618Sjulian if (sep->se_numchild == sep->se_maxchild) 95919618Sjulian enable(sep); 96019618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 961102939Sdwmalone if (WIFSIGNALED(status) || WEXITSTATUS(status)) 96219618Sjulian syslog(LOG_WARNING, 963102939Sdwmalone "%s[%d]: exited, %s %u", 964102939Sdwmalone sep->se_server, pid, 965102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 966102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 967102939Sdwmalone : WTERMSIG(status)); 96819618Sjulian break; 96919618Sjulian } 970101474Sume reapchild_conn(pid); 9711553Srgrimes } 9721553Srgrimes} 9731553Srgrimes 9741553Srgrimesvoid 97598561Sjmallettflag_config(int signo __unused) 9761553Srgrimes{ 97742250Sdes flag_signal('H'); 97842122Sdes} 97942122Sdes 98078694Sdwmalonevoid 98198558Sjmallettconfig(void) 98242122Sdes{ 98319618Sjulian struct servtab *sep, *new, **sepp; 98442122Sdes long omask; 985100127Salfred int new_nomapped; 986111323Sdwmalone#ifdef LOGIN_CAP 987111323Sdwmalone login_cap_t *lc = NULL; 988111323Sdwmalone#endif 9891553Srgrimes 9901553Srgrimes if (!setconfig()) { 9911553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 9921553Srgrimes return; 9931553Srgrimes } 9941553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 9951553Srgrimes sep->se_checked = 0; 99619618Sjulian while ((new = getconfigent())) { 99730807Sache if (getpwnam(new->se_user) == NULL) { 9981553Srgrimes syslog(LOG_ERR, 99956482Scharnier "%s/%s: no such user '%s', service ignored", 100019618Sjulian new->se_service, new->se_proto, new->se_user); 10011553Srgrimes continue; 10021553Srgrimes } 100330807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 100430807Sache syslog(LOG_ERR, 100556482Scharnier "%s/%s: no such group '%s', service ignored", 100630807Sache new->se_service, new->se_proto, new->se_group); 100730807Sache continue; 100830807Sache } 100930792Sache#ifdef LOGIN_CAP 1010111323Sdwmalone if ((lc = login_getclass(new->se_class)) == NULL) { 101130792Sache /* error syslogged by getclass */ 101230792Sache syslog(LOG_ERR, 101337850Sache "%s/%s: %s: login class error, service ignored", 101437850Sache new->se_service, new->se_proto, new->se_class); 101530792Sache continue; 101630792Sache } 1017111323Sdwmalone login_close(lc); 101830792Sache#endif 1019100127Salfred new_nomapped = new->se_nomapped; 10201553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 102119618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 102256590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 1023100127Salfred sep->se_rpc == new->se_rpc && 102478356Sdwmalone sep->se_socktype == new->se_socktype && 102556590Sshin sep->se_family == new->se_family) 10261553Srgrimes break; 10271553Srgrimes if (sep != 0) { 10281553Srgrimes int i; 10291553Srgrimes 103098611Sjmallett#define SWAP(t,a, b) { t c = a; a = b; b = c; } 103142122Sdes omask = sigblock(SIGBLOCK); 103256590Sshin if (sep->se_nomapped != new->se_nomapped) { 1033100127Salfred /* for rpc keep old nommaped till unregister */ 1034100127Salfred if (!sep->se_rpc) 1035100127Salfred sep->se_nomapped = new->se_nomapped; 103656590Sshin sep->se_reset = 1; 103756590Sshin } 103819618Sjulian /* copy over outstanding child pids */ 103964197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 104019618Sjulian new->se_numchild = sep->se_numchild; 104119618Sjulian if (new->se_numchild > new->se_maxchild) 104219618Sjulian new->se_numchild = new->se_maxchild; 104319618Sjulian memcpy(new->se_pids, sep->se_pids, 104419618Sjulian new->se_numchild * sizeof(*new->se_pids)); 104519618Sjulian } 104698611Sjmallett SWAP(pid_t *, sep->se_pids, new->se_pids); 104719618Sjulian sep->se_maxchild = new->se_maxchild; 104819618Sjulian sep->se_numchild = new->se_numchild; 104930847Sdima sep->se_maxcpm = new->se_maxcpm; 1050101474Sume resize_conn(sep, new->se_maxperip); 1051101474Sume sep->se_maxperip = new->se_maxperip; 105266544Sdwmalone sep->se_bi = new->se_bi; 105319618Sjulian /* might need to turn on or off service now */ 105419618Sjulian if (sep->se_fd >= 0) { 105564197Sdwmalone if (sep->se_maxchild > 0 105619618Sjulian && sep->se_numchild == sep->se_maxchild) { 105719618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 105819618Sjulian disable(sep); 105919618Sjulian } else { 106019618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 106119618Sjulian enable(sep); 106219618Sjulian } 106319618Sjulian } 106419618Sjulian sep->se_accept = new->se_accept; 106598611Sjmallett SWAP(char *, sep->se_user, new->se_user); 106698611Sjmallett SWAP(char *, sep->se_group, new->se_group); 106730792Sache#ifdef LOGIN_CAP 106898611Sjmallett SWAP(char *, sep->se_class, new->se_class); 106930792Sache#endif 107098611Sjmallett SWAP(char *, sep->se_server, new->se_server); 107198611Sjmallett SWAP(char *, sep->se_server_name, new->se_server_name); 10721553Srgrimes for (i = 0; i < MAXARGV; i++) 107398611Sjmallett SWAP(char *, sep->se_argv[i], new->se_argv[i]); 107456590Sshin#ifdef IPSEC 107598611Sjmallett SWAP(char *, sep->se_policy, new->se_policy); 107656590Sshin ipsecsetup(sep); 107756590Sshin#endif 107842122Sdes sigsetmask(omask); 107919618Sjulian freeconfig(new); 10801553Srgrimes if (debug) 10811553Srgrimes print_service("REDO", sep); 10821553Srgrimes } else { 108319618Sjulian sep = enter(new); 10841553Srgrimes if (debug) 10851553Srgrimes print_service("ADD ", sep); 10861553Srgrimes } 10871553Srgrimes sep->se_checked = 1; 10881553Srgrimes if (ISMUX(sep)) { 10891553Srgrimes sep->se_fd = -1; 10901553Srgrimes continue; 10911553Srgrimes } 109256590Sshin switch (sep->se_family) { 109356590Sshin case AF_INET: 1094102938Sdwmalone if (!v4bind_ok) { 109556590Sshin sep->se_fd = -1; 109656590Sshin continue; 109756590Sshin } 109856590Sshin break; 109956590Sshin#ifdef INET6 110056590Sshin case AF_INET6: 1101102938Sdwmalone if (!v6bind_ok) { 110256590Sshin sep->se_fd = -1; 110356590Sshin continue; 110456590Sshin } 110556590Sshin break; 110656590Sshin#endif 110756590Sshin } 11082657Scsgr if (!sep->se_rpc) { 110978356Sdwmalone if (sep->se_family != AF_UNIX) { 111078356Sdwmalone sp = getservbyname(sep->se_service, sep->se_proto); 111178356Sdwmalone if (sp == 0) { 111278356Sdwmalone syslog(LOG_ERR, "%s/%s: unknown service", 111378356Sdwmalone sep->se_service, sep->se_proto); 111478356Sdwmalone sep->se_checked = 0; 111578356Sdwmalone continue; 111678356Sdwmalone } 11172657Scsgr } 111856590Sshin switch (sep->se_family) { 111956590Sshin case AF_INET: 112056590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 112156590Sshin sep->se_ctrladdr4.sin_port = 112256590Sshin sp->s_port; 112356590Sshin sep->se_reset = 1; 112456590Sshin } 112556590Sshin break; 112656590Sshin#ifdef INET6 112756590Sshin case AF_INET6: 112856590Sshin if (sp->s_port != 112956590Sshin sep->se_ctrladdr6.sin6_port) { 113056590Sshin sep->se_ctrladdr6.sin6_port = 113156590Sshin sp->s_port; 113256590Sshin sep->se_reset = 1; 113356590Sshin } 113456590Sshin break; 113556590Sshin#endif 11362657Scsgr } 113756590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 113856590Sshin close_sep(sep); 11392657Scsgr } else { 11402657Scsgr rpc = getrpcbyname(sep->se_service); 11412657Scsgr if (rpc == 0) { 114252219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 11432657Scsgr sep->se_service, sep->se_proto); 11442657Scsgr if (sep->se_fd != -1) 11452657Scsgr (void) close(sep->se_fd); 11462657Scsgr sep->se_fd = -1; 11472657Scsgr continue; 11482657Scsgr } 1149100127Salfred if (sep->se_reset != 0 || 1150100127Salfred rpc->r_number != sep->se_rpc_prog) { 11512657Scsgr if (sep->se_rpc_prog) 11522657Scsgr unregisterrpc(sep); 11532657Scsgr sep->se_rpc_prog = rpc->r_number; 11542657Scsgr if (sep->se_fd != -1) 11552657Scsgr (void) close(sep->se_fd); 11562657Scsgr sep->se_fd = -1; 11572657Scsgr } 1158100127Salfred sep->se_nomapped = new_nomapped; 11591553Srgrimes } 1160100127Salfred sep->se_reset = 0; 11611553Srgrimes if (sep->se_fd == -1) 11621553Srgrimes setup(sep); 11631553Srgrimes } 11641553Srgrimes endconfig(); 11651553Srgrimes /* 11661553Srgrimes * Purge anything not looked at above. 11671553Srgrimes */ 116842122Sdes omask = sigblock(SIGBLOCK); 11691553Srgrimes sepp = &servtab; 117019617Sjulian while ((sep = *sepp)) { 11711553Srgrimes if (sep->se_checked) { 11721553Srgrimes sepp = &sep->se_next; 11731553Srgrimes continue; 11741553Srgrimes } 11751553Srgrimes *sepp = sep->se_next; 11761553Srgrimes if (sep->se_fd >= 0) 11771553Srgrimes close_sep(sep); 11781553Srgrimes if (debug) 11791553Srgrimes print_service("FREE", sep); 11802657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 11812657Scsgr unregisterrpc(sep); 11821553Srgrimes freeconfig(sep); 118371399Sdwmalone free(sep); 11841553Srgrimes } 118542122Sdes (void) sigsetmask(omask); 11861553Srgrimes} 11871553Srgrimes 11881553Srgrimesvoid 118998558Sjmallettunregisterrpc(struct servtab *sep) 11902657Scsgr{ 119178694Sdwmalone u_int i; 11922657Scsgr struct servtab *sepp; 119342122Sdes long omask; 1194100127Salfred struct netconfig *netid4, *netid6; 11952657Scsgr 119642122Sdes omask = sigblock(SIGBLOCK); 1197100127Salfred netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1198100127Salfred netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1199100127Salfred if (sep->se_family == AF_INET) 1200100127Salfred netid6 = NULL; 1201100127Salfred else if (sep->se_nomapped) 1202100127Salfred netid4 = NULL; 1203100127Salfred /* 1204100127Salfred * Conflict if same prog and protocol - In that case one should look 1205100127Salfred * to versions, but it is not interesting: having separate servers for 1206100127Salfred * different versions does not work well. 1207100127Salfred * Therefore one do not unregister if there is a conflict. 1208100127Salfred * There is also transport conflict if destroying INET when INET46 1209100127Salfred * exists, or destroying INET46 when INET exists 1210100127Salfred */ 12112657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 12122657Scsgr if (sepp == sep) 12132657Scsgr continue; 1214100127Salfred if (sepp->se_checked == 0 || 12152657Scsgr !sepp->se_rpc || 1216100127Salfred strcmp(sep->se_proto, sepp->se_proto) != 0 || 12172657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 12182657Scsgr continue; 1219100127Salfred if (sepp->se_family == AF_INET) 1220100127Salfred netid4 = NULL; 1221100127Salfred if (sepp->se_family == AF_INET6) { 1222100127Salfred netid6 = NULL; 1223100127Salfred if (!sep->se_nomapped) 1224100127Salfred netid4 = NULL; 1225100127Salfred } 1226100127Salfred if (netid4 == NULL && netid6 == NULL) 1227100127Salfred return; 12282657Scsgr } 12292657Scsgr if (debug) 12302657Scsgr print_service("UNREG", sep); 1231100127Salfred for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1232100127Salfred if (netid4) 1233100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid4); 1234100127Salfred if (netid6) 1235100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid6); 1236100127Salfred } 12372657Scsgr if (sep->se_fd != -1) 12382657Scsgr (void) close(sep->se_fd); 12392657Scsgr sep->se_fd = -1; 124042122Sdes (void) sigsetmask(omask); 12412657Scsgr} 12422657Scsgr 12432657Scsgrvoid 124498561Sjmallettflag_retry(int signo __unused) 12451553Srgrimes{ 124642250Sdes flag_signal('A'); 124742122Sdes} 124842122Sdes 124942122Sdesvoid 125098558Sjmallettretry(void) 125142122Sdes{ 12521553Srgrimes struct servtab *sep; 12531553Srgrimes 12541553Srgrimes timingout = 0; 12551553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 125619617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 12571553Srgrimes setup(sep); 12581553Srgrimes} 12591553Srgrimes 12601553Srgrimesvoid 126198558Sjmallettsetup(struct servtab *sep) 12621553Srgrimes{ 12631553Srgrimes int on = 1; 12641553Srgrimes 126556590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 12661553Srgrimes if (debug) 126729602Scharnier warn("socket failed on %s/%s", 126829602Scharnier sep->se_service, sep->se_proto); 12691553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 12701553Srgrimes sep->se_service, sep->se_proto); 12711553Srgrimes return; 12721553Srgrimes } 1273111324Sdwmalone /* Set all listening sockets to close-on-exec. */ 1274111324Sdwmalone if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) { 1275111324Sdwmalone syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m", 1276111324Sdwmalone sep->se_service, sep->se_proto); 1277111324Sdwmalone close(sep->se_fd); 1278111324Sdwmalone return; 1279111324Sdwmalone } 12801553Srgrimes#define turnon(fd, opt) \ 12811553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 12821553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 12831553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 12841553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 12851553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 12861553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 128725253Swollman#ifdef SO_PRIVSTATE 128813956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 128913956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 129025253Swollman#endif 129156590Sshin /* tftpd opens a new connection then needs more infos */ 129256590Sshin if ((sep->se_family == AF_INET6) && 129356590Sshin (strcmp(sep->se_proto, "udp") == 0) && 129456590Sshin (sep->se_accept == 0) && 1295121559Sume (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 129656590Sshin (char *)&on, sizeof (on)) < 0)) 129756590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 129858935Sume if (sep->se_family == AF_INET6) { 129958935Sume int flag = sep->se_nomapped ? 1 : 0; 1300100505Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 130158935Sume (char *)&flag, sizeof (flag)) < 0) 1302100505Sume syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 130358935Sume } 13041553Srgrimes#undef turnon 130536042Sguido if (sep->se_type == TTCP_TYPE) 130636042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 130736042Sguido (char *)&on, sizeof (on)) < 0) 130836042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 130956590Sshin#ifdef IPV6_FAITH 131056590Sshin if (sep->se_type == FAITH_TYPE) { 131156590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 131256590Sshin sizeof(on)) < 0) { 131356590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 131456590Sshin } 131556590Sshin } 131656590Sshin#endif 131756590Sshin#ifdef IPSEC 131856590Sshin ipsecsetup(sep); 131956590Sshin#endif 132078356Sdwmalone if (sep->se_family == AF_UNIX) { 132178356Sdwmalone (void) unlink(sep->se_ctrladdr_un.sun_path); 132278356Sdwmalone umask(0777); /* Make socket with conservative permissions */ 132378356Sdwmalone } 13241553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 132556590Sshin sep->se_ctrladdr_size) < 0) { 13261553Srgrimes if (debug) 132729602Scharnier warn("bind failed on %s/%s", 132829602Scharnier sep->se_service, sep->se_proto); 13291553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 13301553Srgrimes sep->se_service, sep->se_proto); 13311553Srgrimes (void) close(sep->se_fd); 13321553Srgrimes sep->se_fd = -1; 13331553Srgrimes if (!timingout) { 13341553Srgrimes timingout = 1; 13351553Srgrimes alarm(RETRYTIME); 13361553Srgrimes } 133778356Sdwmalone if (sep->se_family == AF_UNIX) 133878356Sdwmalone umask(mask); 13391553Srgrimes return; 13401553Srgrimes } 134178356Sdwmalone if (sep->se_family == AF_UNIX) { 134278356Sdwmalone /* Ick - fch{own,mod} don't work on Unix domain sockets */ 134378356Sdwmalone if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 134478356Sdwmalone syslog(LOG_ERR, "chown socket: %m"); 134578356Sdwmalone if (chmod(sep->se_service, sep->se_sockmode) < 0) 134678356Sdwmalone syslog(LOG_ERR, "chmod socket: %m"); 134778356Sdwmalone umask(mask); 134878356Sdwmalone } 13492657Scsgr if (sep->se_rpc) { 135078694Sdwmalone u_int i; 135171399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 1352100127Salfred struct netconfig *netid, *netid2 = NULL; 1353100127Salfred struct sockaddr_in sock; 1354100127Salfred struct netbuf nbuf, nbuf2; 13552657Scsgr 13568857Srgrimes if (getsockname(sep->se_fd, 13572657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 13582657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 13592657Scsgr sep->se_service, sep->se_proto); 13602657Scsgr (void) close(sep->se_fd); 13612657Scsgr sep->se_fd = -1; 13628857Srgrimes return; 13632657Scsgr } 1364100127Salfred nbuf.buf = &sep->se_ctrladdr; 1365100127Salfred nbuf.len = sep->se_ctrladdr.sa_len; 1366100127Salfred if (sep->se_family == AF_INET) 1367100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1368100127Salfred else { 1369100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1370100127Salfred if (!sep->se_nomapped) { /* INET and INET6 */ 1371100127Salfred netid2 = netid==udp6conf? udpconf:tcpconf; 1372100127Salfred memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1373100127Salfred nbuf2.buf = &sock; 1374100127Salfred nbuf2.len = sock.sin_len = sizeof sock; 1375100127Salfred sock.sin_family = AF_INET; 1376100127Salfred sock.sin_port = sep->se_ctrladdr6.sin6_port; 1377100127Salfred } 1378100127Salfred } 13792657Scsgr if (debug) 13802657Scsgr print_service("REG ", sep); 13812657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1382100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid); 1383100127Salfred rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1384100127Salfred if (netid2) { 1385100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid2); 1386100127Salfred rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1387100127Salfred } 13882657Scsgr } 13892657Scsgr } 13901553Srgrimes if (sep->se_socktype == SOCK_STREAM) 139117197Sdg listen(sep->se_fd, 64); 139219618Sjulian enable(sep); 13931553Srgrimes if (debug) { 139429602Scharnier warnx("registered %s on %d", 13951553Srgrimes sep->se_server, sep->se_fd); 13961553Srgrimes } 13971553Srgrimes} 13981553Srgrimes 139956590Sshin#ifdef IPSEC 140056590Sshinvoid 140156590Sshinipsecsetup(sep) 140256590Sshin struct servtab *sep; 140356590Sshin{ 140456590Sshin char *buf; 140556590Sshin char *policy_in = NULL; 140656590Sshin char *policy_out = NULL; 140756590Sshin int level; 140856590Sshin int opt; 140956590Sshin 141056590Sshin switch (sep->se_family) { 141156590Sshin case AF_INET: 141256590Sshin level = IPPROTO_IP; 141356590Sshin opt = IP_IPSEC_POLICY; 141456590Sshin break; 141556590Sshin#ifdef INET6 141656590Sshin case AF_INET6: 141756590Sshin level = IPPROTO_IPV6; 141856590Sshin opt = IPV6_IPSEC_POLICY; 141956590Sshin break; 142056590Sshin#endif 142156590Sshin default: 142256590Sshin return; 142356590Sshin } 142456590Sshin 142556590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 142678694Sdwmalone static char def_in[] = "in entrust", def_out[] = "out entrust"; 142778694Sdwmalone policy_in = def_in; 142878694Sdwmalone policy_out = def_out; 142956590Sshin } else { 143056590Sshin if (!strncmp("in", sep->se_policy, 2)) 143156590Sshin policy_in = sep->se_policy; 143256590Sshin else if (!strncmp("out", sep->se_policy, 3)) 143356590Sshin policy_out = sep->se_policy; 143456590Sshin else { 143556590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 143656590Sshin sep->se_policy); 143756590Sshin return; 143856590Sshin } 143956590Sshin } 144056590Sshin 144156590Sshin if (policy_in != NULL) { 144256590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 144356590Sshin if (buf != NULL) { 144456590Sshin if (setsockopt(sep->se_fd, level, opt, 144556675Sshin buf, ipsec_get_policylen(buf)) < 0 && 144656759Sshin debug != 0) 144756759Sshin warnx("%s/%s: ipsec initialization failed; %s", 144856759Sshin sep->se_service, sep->se_proto, 144956759Sshin policy_in); 145056590Sshin free(buf); 145156590Sshin } else 145256590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 145356590Sshin policy_in); 145456590Sshin } 145556590Sshin if (policy_out != NULL) { 145656590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 145756590Sshin if (buf != NULL) { 145856590Sshin if (setsockopt(sep->se_fd, level, opt, 145956675Sshin buf, ipsec_get_policylen(buf)) < 0 && 146056759Sshin debug != 0) 146156759Sshin warnx("%s/%s: ipsec initialization failed; %s", 146256759Sshin sep->se_service, sep->se_proto, 146356759Sshin policy_out); 146456590Sshin free(buf); 146556590Sshin } else 146656590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 146756590Sshin policy_out); 146856590Sshin } 146956590Sshin} 147056590Sshin#endif 147156590Sshin 14721553Srgrimes/* 14731553Srgrimes * Finish with a service and its socket. 14741553Srgrimes */ 14751553Srgrimesvoid 147698558Sjmallettclose_sep(struct servtab *sep) 14771553Srgrimes{ 14781553Srgrimes if (sep->se_fd >= 0) { 147919618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 148019618Sjulian disable(sep); 14811553Srgrimes (void) close(sep->se_fd); 14821553Srgrimes sep->se_fd = -1; 14831553Srgrimes } 14841553Srgrimes sep->se_count = 0; 148519618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 14861553Srgrimes} 14871553Srgrimes 148848467Ssheldonhint 148998558Sjmallettmatchservent(const char *name1, const char *name2, const char *proto) 149048467Ssheldonh{ 149178356Sdwmalone char **alias, *p; 149248467Ssheldonh struct servent *se; 149348467Ssheldonh 149478356Sdwmalone if (strcmp(proto, "unix") == 0) { 149578356Sdwmalone if ((p = strrchr(name1, '/')) != NULL) 149678356Sdwmalone name1 = p + 1; 149778356Sdwmalone if ((p = strrchr(name2, '/')) != NULL) 149878356Sdwmalone name2 = p + 1; 149978356Sdwmalone } 150049026Sdes if (strcmp(name1, name2) == 0) 150149026Sdes return(1); 150248467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 150348467Ssheldonh if (strcmp(name2, se->s_name) == 0) 150448467Ssheldonh return(1); 150548467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 150648467Ssheldonh if (strcmp(name2, *alias) == 0) 150748467Ssheldonh return(1); 150848467Ssheldonh } 150948467Ssheldonh return(0); 151048467Ssheldonh} 151148467Ssheldonh 15121553Srgrimesstruct servtab * 151398558Sjmallettenter(struct servtab *cp) 15141553Srgrimes{ 15151553Srgrimes struct servtab *sep; 151642122Sdes long omask; 15171553Srgrimes 15181553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 15191553Srgrimes if (sep == (struct servtab *)0) { 152049102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 152119617Sjulian exit(EX_OSERR); 15221553Srgrimes } 15231553Srgrimes *sep = *cp; 15241553Srgrimes sep->se_fd = -1; 152542122Sdes omask = sigblock(SIGBLOCK); 15261553Srgrimes sep->se_next = servtab; 15271553Srgrimes servtab = sep; 152842122Sdes sigsetmask(omask); 15291553Srgrimes return (sep); 15301553Srgrimes} 15311553Srgrimes 153219618Sjulianvoid 153398558Sjmallettenable(struct servtab *sep) 153419618Sjulian{ 153519618Sjulian if (debug) 153629602Scharnier warnx( 153719618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 153819618Sjulian#ifdef SANITY_CHECK 153919618Sjulian if (sep->se_fd < 0) { 154019618Sjulian syslog(LOG_ERR, 154119618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 154219618Sjulian exit(EX_SOFTWARE); 154319618Sjulian } 154419618Sjulian if (ISMUX(sep)) { 154519618Sjulian syslog(LOG_ERR, 154619618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 154719618Sjulian exit(EX_SOFTWARE); 154819618Sjulian } 154919618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 155019618Sjulian syslog(LOG_ERR, 155119618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 155219618Sjulian exit(EX_SOFTWARE); 155319618Sjulian } 155448991Ssheldonh nsock++; 155519618Sjulian#endif 155619618Sjulian FD_SET(sep->se_fd, &allsock); 155719618Sjulian if (sep->se_fd > maxsock) 155819618Sjulian maxsock = sep->se_fd; 155919618Sjulian} 156019618Sjulian 156119618Sjulianvoid 156298558Sjmallettdisable(struct servtab *sep) 156319618Sjulian{ 156419618Sjulian if (debug) 156529602Scharnier warnx( 156619618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 156719618Sjulian#ifdef SANITY_CHECK 156819618Sjulian if (sep->se_fd < 0) { 156919618Sjulian syslog(LOG_ERR, 157019618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 157119618Sjulian exit(EX_SOFTWARE); 157219618Sjulian } 157319618Sjulian if (ISMUX(sep)) { 157419618Sjulian syslog(LOG_ERR, 157519618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 157619618Sjulian exit(EX_SOFTWARE); 157719618Sjulian } 157819618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 157919618Sjulian syslog(LOG_ERR, 158019618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 158119618Sjulian exit(EX_SOFTWARE); 158219618Sjulian } 158319618Sjulian if (nsock == 0) { 158419618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 158519618Sjulian exit(EX_SOFTWARE); 158619618Sjulian } 158748991Ssheldonh nsock--; 158819618Sjulian#endif 158919618Sjulian FD_CLR(sep->se_fd, &allsock); 159019618Sjulian if (sep->se_fd == maxsock) 159119618Sjulian maxsock--; 159219618Sjulian} 159319618Sjulian 15941553SrgrimesFILE *fconfig = NULL; 15951553Srgrimesstruct servtab serv; 15961553Srgrimeschar line[LINE_MAX]; 15971553Srgrimes 15981553Srgrimesint 159998558Sjmallettsetconfig(void) 16001553Srgrimes{ 16011553Srgrimes 16021553Srgrimes if (fconfig != NULL) { 16031553Srgrimes fseek(fconfig, 0L, SEEK_SET); 16041553Srgrimes return (1); 16051553Srgrimes } 16061553Srgrimes fconfig = fopen(CONFIG, "r"); 16071553Srgrimes return (fconfig != NULL); 16081553Srgrimes} 16091553Srgrimes 16101553Srgrimesvoid 161198558Sjmallettendconfig(void) 16121553Srgrimes{ 16131553Srgrimes if (fconfig) { 16141553Srgrimes (void) fclose(fconfig); 16151553Srgrimes fconfig = NULL; 16161553Srgrimes } 16171553Srgrimes} 16181553Srgrimes 16191553Srgrimesstruct servtab * 162098558Sjmallettgetconfigent(void) 16211553Srgrimes{ 16221553Srgrimes struct servtab *sep = &serv; 16231553Srgrimes int argc; 162419618Sjulian char *cp, *arg, *s; 16252657Scsgr char *versp; 16261553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 16271553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 162856590Sshin#ifdef IPSEC 1629102861Sdwmalone char *policy; 163056590Sshin#endif 1631102861Sdwmalone int v4bind; 163256590Sshin#ifdef INET6 1633102861Sdwmalone int v6bind; 163456590Sshin#endif 1635101474Sume int i; 16361553Srgrimes 1637102861Sdwmalone#ifdef IPSEC 1638102861Sdwmalone policy = NULL; 1639102861Sdwmalone#endif 16401553Srgrimesmore: 1641102861Sdwmalone v4bind = 0; 1642102861Sdwmalone#ifdef INET6 1643102861Sdwmalone v6bind = 0; 1644102861Sdwmalone#endif 164556590Sshin while ((cp = nextline(fconfig)) != NULL) { 164656590Sshin#ifdef IPSEC 164756590Sshin /* lines starting with #@ is not a comment, but the policy */ 164856590Sshin if (cp[0] == '#' && cp[1] == '@') { 164956590Sshin char *p; 165056590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 165156590Sshin ; 165256590Sshin if (*p == '\0') { 165356590Sshin if (policy) 165456590Sshin free(policy); 165556590Sshin policy = NULL; 165656590Sshin } else if (ipsec_get_policylen(p) >= 0) { 165756590Sshin if (policy) 165856590Sshin free(policy); 165956590Sshin policy = newstr(p); 166056590Sshin } else { 166156590Sshin syslog(LOG_ERR, 166256590Sshin "%s: invalid ipsec policy \"%s\"", 166356590Sshin CONFIG, p); 166456590Sshin exit(EX_CONFIG); 166556590Sshin } 166656590Sshin } 166756590Sshin#endif 166856590Sshin if (*cp == '#' || *cp == '\0') 166956590Sshin continue; 167056590Sshin break; 167156590Sshin } 16721553Srgrimes if (cp == NULL) 16731553Srgrimes return ((struct servtab *)0); 16741553Srgrimes /* 16751553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 16761553Srgrimes * for example) don't get initialized here. 16771553Srgrimes */ 167871399Sdwmalone memset(sep, 0, sizeof *sep); 16791553Srgrimes arg = skip(&cp); 16801553Srgrimes if (cp == NULL) { 16811553Srgrimes /* got an empty line containing just blanks/tabs. */ 16821553Srgrimes goto more; 16831553Srgrimes } 168478356Sdwmalone if (arg[0] == ':') { /* :user:group:perm: */ 168578356Sdwmalone char *user, *group, *perm; 168678356Sdwmalone struct passwd *pw; 168778356Sdwmalone struct group *gr; 168878356Sdwmalone user = arg+1; 168978356Sdwmalone if ((group = strchr(user, ':')) == NULL) { 169078356Sdwmalone syslog(LOG_ERR, "no group after user '%s'", user); 169178356Sdwmalone goto more; 169278356Sdwmalone } 169378356Sdwmalone *group++ = '\0'; 169478356Sdwmalone if ((perm = strchr(group, ':')) == NULL) { 169578356Sdwmalone syslog(LOG_ERR, "no mode after group '%s'", group); 169678356Sdwmalone goto more; 169778356Sdwmalone } 169878356Sdwmalone *perm++ = '\0'; 169978356Sdwmalone if ((pw = getpwnam(user)) == NULL) { 170078356Sdwmalone syslog(LOG_ERR, "no such user '%s'", user); 170178356Sdwmalone goto more; 170278356Sdwmalone } 170378356Sdwmalone sep->se_sockuid = pw->pw_uid; 170478356Sdwmalone if ((gr = getgrnam(group)) == NULL) { 170578356Sdwmalone syslog(LOG_ERR, "no such user '%s'", group); 170678356Sdwmalone goto more; 170778356Sdwmalone } 170878356Sdwmalone sep->se_sockgid = gr->gr_gid; 170978356Sdwmalone sep->se_sockmode = strtol(perm, &arg, 8); 171078356Sdwmalone if (*arg != ':') { 171178356Sdwmalone syslog(LOG_ERR, "bad mode '%s'", perm); 171278356Sdwmalone goto more; 171378356Sdwmalone } 171478356Sdwmalone *arg++ = '\0'; 171578356Sdwmalone } else { 171678356Sdwmalone sep->se_sockuid = euid; 171778356Sdwmalone sep->se_sockgid = egid; 171878356Sdwmalone sep->se_sockmode = 0200; 171978356Sdwmalone } 17201553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 17211553Srgrimes char *c = arg + MUX_LEN; 17221553Srgrimes if (*c == '+') { 17231553Srgrimes sep->se_type = MUXPLUS_TYPE; 17241553Srgrimes c++; 17251553Srgrimes } else 17261553Srgrimes sep->se_type = MUX_TYPE; 17271553Srgrimes sep->se_service = newstr(c); 17281553Srgrimes } else { 17291553Srgrimes sep->se_service = newstr(arg); 17301553Srgrimes sep->se_type = NORM_TYPE; 17311553Srgrimes } 17321553Srgrimes arg = sskip(&cp); 17331553Srgrimes if (strcmp(arg, "stream") == 0) 17341553Srgrimes sep->se_socktype = SOCK_STREAM; 17351553Srgrimes else if (strcmp(arg, "dgram") == 0) 17361553Srgrimes sep->se_socktype = SOCK_DGRAM; 17371553Srgrimes else if (strcmp(arg, "rdm") == 0) 17381553Srgrimes sep->se_socktype = SOCK_RDM; 17391553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 17401553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 17411553Srgrimes else if (strcmp(arg, "raw") == 0) 17421553Srgrimes sep->se_socktype = SOCK_RAW; 17431553Srgrimes else 17441553Srgrimes sep->se_socktype = -1; 174536042Sguido 174636042Sguido arg = sskip(&cp); 174756590Sshin if (strncmp(arg, "tcp", 3) == 0) { 174856590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 174956590Sshin if (arg != NULL) { 175056590Sshin if (strcmp(arg, "ttcp") == 0) 175156590Sshin sep->se_type = TTCP_TYPE; 175256590Sshin else if (strcmp(arg, "faith") == 0) 175356590Sshin sep->se_type = FAITH_TYPE; 175456590Sshin } 175577518Sume } else { 175677518Sume if (sep->se_type == NORM_TYPE && 175777518Sume strncmp(arg, "faith/", 6) == 0) { 175877518Sume arg += 6; 175977518Sume sep->se_type = FAITH_TYPE; 176077518Sume } 176136042Sguido sep->se_proto = newstr(arg); 176277518Sume } 17632657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 176419237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 176519237Sjoerg strlen(sep->se_proto) + 1 - 4); 17662657Scsgr sep->se_rpc = 1; 17672657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 17682657Scsgr sep->se_rpc_lowvers = 0; 176956590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 177056590Sshin sizeof(sep->se_ctrladdr4)); 17712657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 17722657Scsgr *versp++ = '\0'; 1773102859Sdwmalone switch (sscanf(versp, "%u-%u", 17742657Scsgr &sep->se_rpc_lowvers, 17752657Scsgr &sep->se_rpc_highvers)) { 17762657Scsgr case 2: 17772657Scsgr break; 17782657Scsgr case 1: 17792657Scsgr sep->se_rpc_highvers = 17802657Scsgr sep->se_rpc_lowvers; 17812657Scsgr break; 17822657Scsgr default: 17838857Srgrimes syslog(LOG_ERR, 178452219Scharnier "bad RPC version specifier; %s", 17852657Scsgr sep->se_service); 17862657Scsgr freeconfig(sep); 17872657Scsgr goto more; 17882657Scsgr } 17892657Scsgr } 17902657Scsgr else { 17912657Scsgr sep->se_rpc_lowvers = 17922657Scsgr sep->se_rpc_highvers = 1; 17932657Scsgr } 17942657Scsgr } 179556590Sshin sep->se_nomapped = 0; 179678356Sdwmalone if (strcmp(sep->se_proto, "unix") == 0) { 179778356Sdwmalone sep->se_family = AF_UNIX; 1798102937Sdwmalone } else { 1799102937Sdwmalone while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 180056590Sshin#ifdef INET6 1801102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1802102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1803102937Sdwmalone v6bind = 1; 1804102937Sdwmalone continue; 1805102937Sdwmalone } 1806102937Sdwmalone#endif 1807102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1808102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1809102937Sdwmalone v4bind = 1; 1810102937Sdwmalone continue; 1811102937Sdwmalone } 1812102937Sdwmalone /* illegal version num */ 1813102937Sdwmalone syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1814100127Salfred freeconfig(sep); 1815100127Salfred goto more; 1816100127Salfred } 1817102937Sdwmalone#ifdef INET6 1818102938Sdwmalone if (v6bind && !v6bind_ok) { 1819102937Sdwmalone syslog(LOG_INFO, "IPv6 bind is ignored for %s", 182056590Sshin sep->se_service); 1821102938Sdwmalone if (v4bind && v4bind_ok) 1822102937Sdwmalone v6bind = 0; 1823102937Sdwmalone else { 1824102937Sdwmalone freeconfig(sep); 1825102937Sdwmalone goto more; 1826102937Sdwmalone } 182756590Sshin } 1828102938Sdwmalone if (v6bind) { 1829102937Sdwmalone sep->se_family = AF_INET6; 1830102938Sdwmalone if (!v4bind || !v4bind_ok) 1831102937Sdwmalone sep->se_nomapped = 1; 1832102937Sdwmalone } else 1833102937Sdwmalone#endif 1834102937Sdwmalone { /* default to v4 bind if not v6 bind */ 1835102938Sdwmalone if (!v4bind_ok) { 1836102937Sdwmalone syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1837102937Sdwmalone sep->se_service); 1838102937Sdwmalone freeconfig(sep); 1839102937Sdwmalone goto more; 1840102937Sdwmalone } 1841102937Sdwmalone sep->se_family = AF_INET; 1842102937Sdwmalone } 184356590Sshin } 184456590Sshin /* init ctladdr */ 184556590Sshin switch(sep->se_family) { 184656590Sshin case AF_INET: 184756590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 184856590Sshin sizeof(sep->se_ctrladdr4)); 184956590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 185056590Sshin break; 185156590Sshin#ifdef INET6 185256590Sshin case AF_INET6: 185356590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 185456590Sshin sizeof(sep->se_ctrladdr6)); 185556590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 185656590Sshin break; 185756590Sshin#endif 185878356Sdwmalone case AF_UNIX: 185978356Sdwmalone if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 186078356Sdwmalone syslog(LOG_ERR, 186178356Sdwmalone "domain socket pathname too long for service %s", 186278356Sdwmalone sep->se_service); 186378356Sdwmalone goto more; 186478356Sdwmalone } 186578356Sdwmalone memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 186678356Sdwmalone sep->se_ctrladdr_un.sun_family = sep->se_family; 186778356Sdwmalone sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 186878356Sdwmalone strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 186978356Sdwmalone sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 187056590Sshin } 18711553Srgrimes arg = sskip(&cp); 187219618Sjulian if (!strncmp(arg, "wait", 4)) 187319618Sjulian sep->se_accept = 0; 187419618Sjulian else if (!strncmp(arg, "nowait", 6)) 187519618Sjulian sep->se_accept = 1; 187619618Sjulian else { 187719618Sjulian syslog(LOG_ERR, 187819618Sjulian "%s: bad wait/nowait for service %s", 187919618Sjulian CONFIG, sep->se_service); 188019618Sjulian goto more; 188119618Sjulian } 188248069Ssheldonh sep->se_maxchild = -1; 188348069Ssheldonh sep->se_maxcpm = -1; 1884101474Sume sep->se_maxperip = -1; 188519618Sjulian if ((s = strchr(arg, '/')) != NULL) { 188619618Sjulian char *eptr; 188719618Sjulian u_long val; 188819618Sjulian 188919618Sjulian val = strtoul(s + 1, &eptr, 10); 189030847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 189119618Sjulian syslog(LOG_ERR, 189219618Sjulian "%s: bad max-child for service %s", 189319618Sjulian CONFIG, sep->se_service); 189419618Sjulian goto more; 189519618Sjulian } 189648069Ssheldonh if (debug) 189748069Ssheldonh if (!sep->se_accept && val != 1) 189848069Ssheldonh warnx("maxchild=%lu for wait service %s" 189948069Ssheldonh " not recommended", val, sep->se_service); 190019618Sjulian sep->se_maxchild = val; 190130847Sdima if (*eptr == '/') 190230847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1903101474Sume if (*eptr == '/') 1904101474Sume sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 190530847Sdima /* 190630847Sdima * explicitly do not check for \0 for future expansion / 190730847Sdima * backwards compatibility 190830847Sdima */ 190919618Sjulian } 19101553Srgrimes if (ISMUX(sep)) { 19111553Srgrimes /* 191219618Sjulian * Silently enforce "nowait" mode for TCPMUX services 191319618Sjulian * since they don't have an assigned port to listen on. 19141553Srgrimes */ 191519618Sjulian sep->se_accept = 1; 19161553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 19178857Srgrimes syslog(LOG_ERR, 19181553Srgrimes "%s: bad protocol for tcpmux service %s", 19191553Srgrimes CONFIG, sep->se_service); 19201553Srgrimes goto more; 19211553Srgrimes } 19221553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 19238857Srgrimes syslog(LOG_ERR, 19241553Srgrimes "%s: bad socket type for tcpmux service %s", 19251553Srgrimes CONFIG, sep->se_service); 19261553Srgrimes goto more; 19271553Srgrimes } 19281553Srgrimes } 19291553Srgrimes sep->se_user = newstr(sskip(&cp)); 193030792Sache#ifdef LOGIN_CAP 193130792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 193230792Sache *s = '\0'; 193330792Sache sep->se_class = newstr(s + 1); 193430792Sache } else 193530792Sache sep->se_class = newstr(RESOURCE_RC); 193630792Sache#endif 193730807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 193830807Sache *s = '\0'; 193930807Sache sep->se_group = newstr(s + 1); 194030807Sache } else 194130807Sache sep->se_group = NULL; 19421553Srgrimes sep->se_server = newstr(sskip(&cp)); 194345588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 194445588Smarkm sep->se_server_name++; 19451553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 19461553Srgrimes struct biltin *bi; 19471553Srgrimes 19481553Srgrimes for (bi = biltins; bi->bi_service; bi++) 194949026Sdes if (bi->bi_socktype == sep->se_socktype && 195048467Ssheldonh matchservent(bi->bi_service, sep->se_service, 195148467Ssheldonh sep->se_proto)) 19521553Srgrimes break; 19531553Srgrimes if (bi->bi_service == 0) { 19541553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 19551553Srgrimes sep->se_service); 19561553Srgrimes goto more; 19571553Srgrimes } 195819618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 19591553Srgrimes sep->se_bi = bi; 19601553Srgrimes } else 19611553Srgrimes sep->se_bi = NULL; 1962101474Sume if (sep->se_maxperip < 0) 1963101474Sume sep->se_maxperip = maxperip; 196448069Ssheldonh if (sep->se_maxcpm < 0) 196548069Ssheldonh sep->se_maxcpm = maxcpm; 196645588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 196748069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 196819618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 196948069Ssheldonh else if (sep->se_accept) 197048069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 197119618Sjulian else 197248069Ssheldonh sep->se_maxchild = 1; 197345588Smarkm } 197464197Sdwmalone if (sep->se_maxchild > 0) { 197519618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 197619618Sjulian if (sep->se_pids == NULL) { 197749102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 197819618Sjulian exit(EX_OSERR); 197919618Sjulian } 198019618Sjulian } 19811553Srgrimes argc = 0; 19821553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 198319618Sjulian if (argc < MAXARGV) { 19841553Srgrimes sep->se_argv[argc++] = newstr(arg); 198519618Sjulian } else { 198619618Sjulian syslog(LOG_ERR, 198719618Sjulian "%s: too many arguments for service %s", 198819618Sjulian CONFIG, sep->se_service); 198919618Sjulian goto more; 199019618Sjulian } 19911553Srgrimes while (argc <= MAXARGV) 19921553Srgrimes sep->se_argv[argc++] = NULL; 1993101474Sume for (i = 0; i < PERIPSIZE; ++i) 1994101474Sume LIST_INIT(&sep->se_conn[i]); 199556590Sshin#ifdef IPSEC 199656590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 199756590Sshin#endif 19981553Srgrimes return (sep); 19991553Srgrimes} 20001553Srgrimes 20011553Srgrimesvoid 200298558Sjmallettfreeconfig(struct servtab *cp) 20031553Srgrimes{ 20041553Srgrimes int i; 20051553Srgrimes 20061553Srgrimes if (cp->se_service) 20071553Srgrimes free(cp->se_service); 20081553Srgrimes if (cp->se_proto) 20091553Srgrimes free(cp->se_proto); 20101553Srgrimes if (cp->se_user) 20111553Srgrimes free(cp->se_user); 201230807Sache if (cp->se_group) 201330807Sache free(cp->se_group); 201430792Sache#ifdef LOGIN_CAP 201530792Sache if (cp->se_class) 201630792Sache free(cp->se_class); 201730792Sache#endif 20181553Srgrimes if (cp->se_server) 20191553Srgrimes free(cp->se_server); 202019618Sjulian if (cp->se_pids) 202119618Sjulian free(cp->se_pids); 20221553Srgrimes for (i = 0; i < MAXARGV; i++) 20231553Srgrimes if (cp->se_argv[i]) 20241553Srgrimes free(cp->se_argv[i]); 2025101474Sume free_connlist(cp); 202656590Sshin#ifdef IPSEC 202756590Sshin if (cp->se_policy) 202856590Sshin free(cp->se_policy); 202956590Sshin#endif 20301553Srgrimes} 20311553Srgrimes 20321553Srgrimes 20331553Srgrimes/* 20341553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 20351553Srgrimes * configuration file and exit. 20361553Srgrimes */ 20371553Srgrimeschar * 203898558Sjmallettsskip(char **cpp) 20391553Srgrimes{ 20401553Srgrimes char *cp; 20411553Srgrimes 20421553Srgrimes cp = skip(cpp); 20431553Srgrimes if (cp == NULL) { 20441553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 204519617Sjulian exit(EX_DATAERR); 20461553Srgrimes } 20471553Srgrimes return (cp); 20481553Srgrimes} 20491553Srgrimes 20501553Srgrimeschar * 205198558Sjmallettskip(char **cpp) 20521553Srgrimes{ 20531553Srgrimes char *cp = *cpp; 20541553Srgrimes char *start; 205511933Sadam char quote = '\0'; 20561553Srgrimes 20571553Srgrimesagain: 20581553Srgrimes while (*cp == ' ' || *cp == '\t') 20591553Srgrimes cp++; 20601553Srgrimes if (*cp == '\0') { 20611553Srgrimes int c; 20621553Srgrimes 20631553Srgrimes c = getc(fconfig); 20641553Srgrimes (void) ungetc(c, fconfig); 20651553Srgrimes if (c == ' ' || c == '\t') 206619617Sjulian if ((cp = nextline(fconfig))) 20671553Srgrimes goto again; 20681553Srgrimes *cpp = (char *)0; 20691553Srgrimes return ((char *)0); 20701553Srgrimes } 207111933Sadam if (*cp == '"' || *cp == '\'') 207211933Sadam quote = *cp++; 20731553Srgrimes start = cp; 207411933Sadam if (quote) 207511933Sadam while (*cp && *cp != quote) 207611933Sadam cp++; 207711933Sadam else 207811933Sadam while (*cp && *cp != ' ' && *cp != '\t') 207911933Sadam cp++; 20801553Srgrimes if (*cp != '\0') 20811553Srgrimes *cp++ = '\0'; 20821553Srgrimes *cpp = cp; 20831553Srgrimes return (start); 20841553Srgrimes} 20851553Srgrimes 20861553Srgrimeschar * 208798558Sjmallettnextline(FILE *fd) 20881553Srgrimes{ 20891553Srgrimes char *cp; 20901553Srgrimes 20911553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 20921553Srgrimes return ((char *)0); 20931553Srgrimes cp = strchr(line, '\n'); 20941553Srgrimes if (cp) 20951553Srgrimes *cp = '\0'; 20961553Srgrimes return (line); 20971553Srgrimes} 20981553Srgrimes 20991553Srgrimeschar * 210098558Sjmallettnewstr(const char *cp) 21011553Srgrimes{ 210278694Sdwmalone char *cr; 210378694Sdwmalone 210478694Sdwmalone if ((cr = strdup(cp != NULL ? cp : ""))) 210578694Sdwmalone return (cr); 21061553Srgrimes syslog(LOG_ERR, "strdup: %m"); 210719617Sjulian exit(EX_OSERR); 21081553Srgrimes} 21091553Srgrimes 21101553Srgrimesvoid 211198558Sjmallettinetd_setproctitle(const char *a, int s) 21121553Srgrimes{ 211371399Sdwmalone socklen_t size; 211456590Sshin struct sockaddr_storage ss; 211556590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 21161553Srgrimes 211756590Sshin size = sizeof(ss); 211856590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 211956590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 212056590Sshin NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 212156590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 212256590Sshin } else 212313142Speter (void) sprintf(buf, "%s", a); 212413142Speter setproctitle("%s", buf); 212513142Speter} 212613142Speter 212778694Sdwmaloneint 212898558Sjmallettcheck_loop(const struct sockaddr *sa, const struct servtab *sep) 21295182Swollman{ 21305182Swollman struct servtab *se2; 213156590Sshin char pname[INET6_ADDRSTRLEN]; 21325182Swollman 21335182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 21345182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 21355182Swollman continue; 21365182Swollman 213756590Sshin switch (se2->se_family) { 213856590Sshin case AF_INET: 213978694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214056590Sshin se2->se_ctrladdr4.sin_port) 214156590Sshin goto isloop; 214256590Sshin continue; 214356590Sshin#ifdef INET6 214456590Sshin case AF_INET6: 214578694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214656590Sshin se2->se_ctrladdr4.sin_port) 214756590Sshin goto isloop; 214856590Sshin continue; 214956590Sshin#endif 215056590Sshin default: 215156590Sshin continue; 21525182Swollman } 215356590Sshin isloop: 215456590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 215556590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 215656590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 215756590Sshin sep->se_service, sep->se_proto, 215856590Sshin se2->se_service, se2->se_proto, 215956590Sshin pname); 216056590Sshin return 1; 21615182Swollman } 21625182Swollman return 0; 21635182Swollman} 21645182Swollman 21651553Srgrimes/* 21661553Srgrimes * print_service: 21671553Srgrimes * Dump relevant information to stderr 21681553Srgrimes */ 21691553Srgrimesvoid 217098558Sjmallettprint_service(const char *action, const struct servtab *sep) 21711553Srgrimes{ 217219617Sjulian fprintf(stderr, 217356590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 217430792Sache#ifdef LOGIN_CAP 217556590Sshin "class=%s" 217630792Sache#endif 217756590Sshin " builtin=%p server=%s" 217856590Sshin#ifdef IPSEC 217956590Sshin " policy=\"%s\"" 218056590Sshin#endif 218156590Sshin "\n", 218219617Sjulian action, sep->se_service, sep->se_proto, 218330807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 218430792Sache#ifdef LOGIN_CAP 218530792Sache sep->se_class, 218630792Sache#endif 218756590Sshin (void *) sep->se_bi, sep->se_server 218856590Sshin#ifdef IPSEC 218956590Sshin , (sep->se_policy ? sep->se_policy : "") 219056590Sshin#endif 219156590Sshin ); 21921553Srgrimes} 21931553Srgrimes 219430847Sdima#define CPMHSIZE 256 219530847Sdima#define CPMHMASK (CPMHSIZE-1) 219630847Sdima#define CHTGRAN 10 219730847Sdima#define CHTSIZE 6 219830847Sdima 219930847Sdimatypedef struct CTime { 220030847Sdima unsigned long ct_Ticks; 220130847Sdima int ct_Count; 220230847Sdima} CTime; 220330847Sdima 220430847Sdimatypedef struct CHash { 220556590Sshin union { 220656590Sshin struct in_addr c4_Addr; 220756590Sshin struct in6_addr c6_Addr; 220856590Sshin } cu_Addr; 220956590Sshin#define ch_Addr4 cu_Addr.c4_Addr 221056590Sshin#define ch_Addr6 cu_Addr.c6_Addr 221156590Sshin int ch_Family; 221230847Sdima time_t ch_LTime; 221330847Sdima char *ch_Service; 221430847Sdima CTime ch_Times[CHTSIZE]; 221530847Sdima} CHash; 221630847Sdima 221730847SdimaCHash CHashAry[CPMHSIZE]; 221830847Sdima 221930847Sdimaint 222098558Sjmallettcpmip(const struct servtab *sep, int ctrl) 222130847Sdima{ 222256590Sshin struct sockaddr_storage rss; 222371399Sdwmalone socklen_t rssLen = sizeof(rss); 222430847Sdima int r = 0; 222530847Sdima 222630847Sdima /* 222730847Sdima * If getpeername() fails, just let it through (if logging is 222830847Sdima * enabled the condition is caught elsewhere) 222930847Sdima */ 223030847Sdima 223130847Sdima if (sep->se_maxcpm > 0 && 223256590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 223330847Sdima time_t t = time(NULL); 223430847Sdima int hv = 0xABC3D20F; 223530847Sdima int i; 223630847Sdima int cnt = 0; 223730847Sdima CHash *chBest = NULL; 223830847Sdima unsigned int ticks = t / CHTGRAN; 223978694Sdwmalone struct sockaddr_in *sin4; 224056590Sshin#ifdef INET6 224156590Sshin struct sockaddr_in6 *sin6; 224256590Sshin#endif 224330847Sdima 224478694Sdwmalone sin4 = (struct sockaddr_in *)&rss; 224556590Sshin#ifdef INET6 224656590Sshin sin6 = (struct sockaddr_in6 *)&rss; 224756590Sshin#endif 224830847Sdima { 224930847Sdima char *p; 225078694Sdwmalone int addrlen; 225130847Sdima 225256590Sshin switch (rss.ss_family) { 225356590Sshin case AF_INET: 225478694Sdwmalone p = (char *)&sin4->sin_addr; 225556590Sshin addrlen = sizeof(struct in_addr); 225656590Sshin break; 225756590Sshin#ifdef INET6 225856590Sshin case AF_INET6: 225956590Sshin p = (char *)&sin6->sin6_addr; 226056590Sshin addrlen = sizeof(struct in6_addr); 226156590Sshin break; 226256590Sshin#endif 226356590Sshin default: 226456590Sshin /* should not happen */ 226556590Sshin return -1; 226656590Sshin } 226756590Sshin 226856590Sshin for (i = 0; i < addrlen; ++i, ++p) { 226930847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 227030847Sdima } 227130847Sdima hv = (hv ^ (hv >> 16)); 227230847Sdima } 227330847Sdima for (i = 0; i < 5; ++i) { 227430847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 227530847Sdima 227656590Sshin if (rss.ss_family == AF_INET && 227756590Sshin ch->ch_Family == AF_INET && 227878694Sdwmalone sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 227930847Sdima ch->ch_Service && strcmp(sep->se_service, 228030847Sdima ch->ch_Service) == 0) { 228130847Sdima chBest = ch; 228230847Sdima break; 228330847Sdima } 228456590Sshin#ifdef INET6 228556590Sshin if (rss.ss_family == AF_INET6 && 228656590Sshin ch->ch_Family == AF_INET6 && 228756590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 228856590Sshin &ch->ch_Addr6) != 0 && 228956590Sshin ch->ch_Service && strcmp(sep->se_service, 229056590Sshin ch->ch_Service) == 0) { 229156590Sshin chBest = ch; 229256590Sshin break; 229356590Sshin } 229456590Sshin#endif 229530847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 229630847Sdima ch->ch_LTime < chBest->ch_LTime) { 229730847Sdima chBest = ch; 229830847Sdima } 229930847Sdima } 230056590Sshin if ((rss.ss_family == AF_INET && 230156590Sshin (chBest->ch_Family != AF_INET || 230278694Sdwmalone sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 230330847Sdima chBest->ch_Service == NULL || 230430847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 230578694Sdwmalone chBest->ch_Family = sin4->sin_family; 230678694Sdwmalone chBest->ch_Addr4 = sin4->sin_addr; 230730847Sdima if (chBest->ch_Service) 230830847Sdima free(chBest->ch_Service); 230930847Sdima chBest->ch_Service = strdup(sep->se_service); 231030847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 231130847Sdima } 231256590Sshin#ifdef INET6 231356590Sshin if ((rss.ss_family == AF_INET6 && 231456590Sshin (chBest->ch_Family != AF_INET6 || 231556590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 231656590Sshin &chBest->ch_Addr6) == 0)) || 231756590Sshin chBest->ch_Service == NULL || 231856590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 231956590Sshin chBest->ch_Family = sin6->sin6_family; 232056590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 232156590Sshin if (chBest->ch_Service) 232256590Sshin free(chBest->ch_Service); 232356590Sshin chBest->ch_Service = strdup(sep->se_service); 232456590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 232556590Sshin } 232656590Sshin#endif 232730847Sdima chBest->ch_LTime = t; 232830847Sdima { 232930847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 233030847Sdima if (ct->ct_Ticks != ticks) { 233130847Sdima ct->ct_Ticks = ticks; 233230847Sdima ct->ct_Count = 0; 233330847Sdima } 233430847Sdima ++ct->ct_Count; 233530847Sdima } 233630847Sdima for (i = 0; i < CHTSIZE; ++i) { 233730847Sdima CTime *ct = &chBest->ch_Times[i]; 233830847Sdima if (ct->ct_Ticks <= ticks && 233930847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 234030847Sdima cnt += ct->ct_Count; 234130847Sdima } 234230847Sdima } 2343117644Sdwmalone if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 234456590Sshin char pname[INET6_ADDRSTRLEN]; 234556590Sshin 234656590Sshin getnameinfo((struct sockaddr *)&rss, 234756590Sshin ((struct sockaddr *)&rss)->sa_len, 234856590Sshin pname, sizeof(pname), NULL, 0, 234956590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 235030847Sdima r = -1; 235130847Sdima syslog(LOG_ERR, 235233794Spst "%s from %s exceeded counts/min (limit %d/min)", 235356590Sshin sep->se_service, pname, 235433794Spst sep->se_maxcpm); 235530847Sdima } 235630847Sdima } 235730847Sdima return(r); 235830847Sdima} 2359101474Sume 2360101474Sumestatic struct conninfo * 2361101474Sumesearch_conn(struct servtab *sep, int ctrl) 2362101474Sume{ 2363101474Sume struct sockaddr_storage ss; 2364101474Sume socklen_t sslen = sizeof(ss); 2365101474Sume struct conninfo *conn; 2366101474Sume int hv; 2367101474Sume char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2368101474Sume 2369101474Sume if (sep->se_maxperip <= 0) 2370101474Sume return NULL; 2371101474Sume 2372101474Sume /* 2373101474Sume * If getpeername() fails, just let it through (if logging is 2374101474Sume * enabled the condition is caught elsewhere) 2375101474Sume */ 2376101474Sume if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2377101474Sume return NULL; 2378101474Sume 2379101474Sume switch (ss.ss_family) { 2380101474Sume case AF_INET: 2381101474Sume hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2382101474Sume sizeof(struct in_addr)); 2383101474Sume break; 2384101474Sume#ifdef INET6 2385101474Sume case AF_INET6: 2386101474Sume hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2387101474Sume sizeof(struct in6_addr)); 2388101474Sume break; 2389101474Sume#endif 2390101474Sume default: 2391101474Sume /* 2392101474Sume * Since we only support AF_INET and AF_INET6, just 2393101474Sume * let other than AF_INET and AF_INET6 through. 2394101474Sume */ 2395101474Sume return NULL; 2396101474Sume } 2397101474Sume 2398101474Sume if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2399101474Sume NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0) 2400101474Sume return NULL; 2401101474Sume 2402101474Sume LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2403101474Sume if (getnameinfo((struct sockaddr *)&conn->co_addr, 2404101474Sume conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2405101474Sume NI_NUMERICHOST | NI_WITHSCOPEID) == 0 && 2406101474Sume strcmp(pname, pname2) == 0) 2407101474Sume break; 2408101474Sume } 2409101474Sume 2410101474Sume if (conn == NULL) { 2411101474Sume if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2412101474Sume syslog(LOG_ERR, "malloc: %m"); 2413101474Sume exit(EX_OSERR); 2414101474Sume } 2415101474Sume conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2416101474Sume if (conn->co_proc == NULL) { 2417101474Sume syslog(LOG_ERR, "malloc: %m"); 2418101474Sume exit(EX_OSERR); 2419101474Sume } 2420101474Sume memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2421101474Sume conn->co_numchild = 0; 2422101474Sume LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2423101474Sume } 2424101474Sume 2425101474Sume /* 2426101474Sume * Since a child process is not invoked yet, we cannot 2427101474Sume * determine a pid of a child. So, co_proc and co_numchild 2428101474Sume * should be filled leter. 2429101474Sume */ 2430101474Sume 2431101474Sume return conn; 2432101474Sume} 2433101474Sume 2434101474Sumestatic int 2435101474Sumeroom_conn(struct servtab *sep, struct conninfo *conn) 2436101474Sume{ 2437101474Sume char pname[NI_MAXHOST]; 2438101474Sume 2439101474Sume if (conn->co_numchild >= sep->se_maxperip) { 2440101474Sume getnameinfo((struct sockaddr *)&conn->co_addr, 2441101474Sume conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2442101474Sume NI_NUMERICHOST | NI_WITHSCOPEID); 2443101474Sume syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2444101474Sume sep->se_service, pname, sep->se_maxperip); 2445101474Sume return 0; 2446101474Sume } 2447101474Sume return 1; 2448101474Sume} 2449101474Sume 2450101474Sumestatic void 2451101474Sumeaddchild_conn(struct conninfo *conn, pid_t pid) 2452101474Sume{ 2453101474Sume struct procinfo *proc; 2454101474Sume 2455101474Sume if (conn == NULL) 2456101474Sume return; 2457101474Sume 2458101474Sume if ((proc = search_proc(pid, 1)) != NULL) { 2459101474Sume if (proc->pr_conn != NULL) { 2460101474Sume syslog(LOG_ERR, 2461101474Sume "addchild_conn: child already on process list"); 2462101474Sume exit(EX_OSERR); 2463101474Sume } 2464101474Sume proc->pr_conn = conn; 2465101474Sume } 2466101474Sume 2467101474Sume conn->co_proc[conn->co_numchild++] = proc; 2468101474Sume} 2469101474Sume 2470101474Sumestatic void 2471101474Sumereapchild_conn(pid_t pid) 2472101474Sume{ 2473101474Sume struct procinfo *proc; 2474101474Sume struct conninfo *conn; 2475101474Sume int i; 2476101474Sume 2477101474Sume if ((proc = search_proc(pid, 0)) == NULL) 2478101474Sume return; 2479101474Sume if ((conn = proc->pr_conn) == NULL) 2480101474Sume return; 2481101474Sume for (i = 0; i < conn->co_numchild; ++i) 2482101474Sume if (conn->co_proc[i] == proc) { 2483101474Sume conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2484101474Sume break; 2485101474Sume } 2486101474Sume free_proc(proc); 2487101474Sume free_conn(conn); 2488101474Sume} 2489101474Sume 2490101474Sumestatic void 2491102859Sdwmaloneresize_conn(struct servtab *sep, int maxpip) 2492101474Sume{ 2493101474Sume struct conninfo *conn; 2494101474Sume int i, j; 2495101474Sume 2496101474Sume if (sep->se_maxperip <= 0) 2497101474Sume return; 2498102859Sdwmalone if (maxpip <= 0) { 2499101474Sume free_connlist(sep); 2500101474Sume return; 2501101474Sume } 2502101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2503101474Sume LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2504102859Sdwmalone for (j = maxpip; j < conn->co_numchild; ++j) 2505101474Sume free_proc(conn->co_proc[j]); 2506101474Sume conn->co_proc = realloc(conn->co_proc, 2507102859Sdwmalone maxpip * sizeof(*conn->co_proc)); 2508101474Sume if (conn->co_proc == NULL) { 2509101474Sume syslog(LOG_ERR, "realloc: %m"); 2510101474Sume exit(EX_OSERR); 2511101474Sume } 2512102859Sdwmalone if (conn->co_numchild > maxpip) 2513102859Sdwmalone conn->co_numchild = maxpip; 2514101474Sume } 2515101474Sume } 2516101474Sume} 2517101474Sume 2518101474Sumestatic void 2519101474Sumefree_connlist(struct servtab *sep) 2520101474Sume{ 2521101474Sume struct conninfo *conn; 2522101474Sume int i, j; 2523101474Sume 2524101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2525101474Sume while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2526101474Sume for (j = 0; j < conn->co_numchild; ++j) 2527101474Sume free_proc(conn->co_proc[j]); 2528101474Sume conn->co_numchild = 0; 2529101474Sume free_conn(conn); 2530101474Sume } 2531101474Sume } 2532101474Sume} 2533101474Sume 2534101474Sumestatic void 2535101474Sumefree_conn(struct conninfo *conn) 2536101474Sume{ 2537101474Sume if (conn == NULL) 2538101474Sume return; 2539101474Sume if (conn->co_numchild <= 0) { 2540101474Sume LIST_REMOVE(conn, co_link); 2541101474Sume free(conn->co_proc); 2542101474Sume free(conn); 2543101474Sume } 2544101474Sume} 2545101474Sume 2546101474Sumestatic struct procinfo * 2547101474Sumesearch_proc(pid_t pid, int add) 2548101474Sume{ 2549101474Sume struct procinfo *proc; 2550101474Sume int hv; 2551101474Sume 2552101474Sume hv = hashval((char *)&pid, sizeof(pid)); 2553101474Sume LIST_FOREACH(proc, &proctable[hv], pr_link) { 2554101474Sume if (proc->pr_pid == pid) 2555101474Sume break; 2556101474Sume } 2557101474Sume if (proc == NULL && add) { 2558101474Sume if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2559101474Sume syslog(LOG_ERR, "malloc: %m"); 2560101474Sume exit(EX_OSERR); 2561101474Sume } 2562101474Sume proc->pr_pid = pid; 2563101474Sume proc->pr_conn = NULL; 2564101474Sume LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2565101474Sume } 2566101474Sume return proc; 2567101474Sume} 2568101474Sume 2569101474Sumestatic void 2570101474Sumefree_proc(struct procinfo *proc) 2571101474Sume{ 2572101474Sume if (proc == NULL) 2573101474Sume return; 2574101474Sume LIST_REMOVE(proc, pr_link); 2575101474Sume free(proc); 2576101474Sume} 2577101474Sume 2578101474Sumestatic int 2579101474Sumehashval(char *p, int len) 2580101474Sume{ 2581101474Sume int i, hv = 0xABC3D20F; 2582101474Sume 2583101474Sume for (i = 0; i < len; ++i, ++p) 2584101474Sume hv = (hv << 5) ^ (hv >> 23) ^ *p; 2585101474Sume hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2586101474Sume return hv; 2587101474Sume} 2588