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 * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 301553Srgrimes#ifndef lint 3129602Scharnierstatic const char copyright[] = 321553Srgrimes"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 331553Srgrimes The Regents of the University of California. All rights reserved.\n"; 341553Srgrimes#endif /* not lint */ 351553Srgrimes 361553Srgrimes#ifndef lint 3729602Scharnier#if 0 3829602Scharnierstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 3929602Scharnier#endif 401553Srgrimes#endif /* not lint */ 411553Srgrimes 4298563Sjmallett#include <sys/cdefs.h> 4398563Sjmallett__FBSDID("$FreeBSD$"); 4498563Sjmallett 451553Srgrimes/* 461553Srgrimes * Inetd - Internet super-server 471553Srgrimes * 481553Srgrimes * This program invokes all internet services as needed. Connection-oriented 491553Srgrimes * services are invoked each time a connection is made, by creating a process. 501553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 511553Srgrimes * to do a getpeername to find out the source host and port. 521553Srgrimes * 531553Srgrimes * Datagram oriented services are invoked when a datagram 541553Srgrimes * arrives; a process is created and passed a pending message 551553Srgrimes * on file descriptor 0. Datagram servers may either connect 561553Srgrimes * to their peer, freeing up the original socket for inetd 571553Srgrimes * to receive further messages on, or ``take over the socket'', 581553Srgrimes * processing all arriving datagrams and, eventually, timing 591553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 608857Srgrimes * the second type of server ``single-threaded''. 611553Srgrimes * 621553Srgrimes * Inetd uses a configuration file which is read at startup 631553Srgrimes * and, possibly, at some later time in response to a hangup signal. 641553Srgrimes * The configuration file is ``free format'' with fields given in the 6567514Sdwmalone * order shown below. Continuation lines for an entry must begin with 661553Srgrimes * a space or tab. All fields must be present in each entry. 671553Srgrimes * 6878356Sdwmalone * service name must be in /etc/services 6978356Sdwmalone * or name a tcpmux service 7078356Sdwmalone * or specify a unix domain socket 711553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 72162305Sru * protocol tcp[4][6][/faith], udp[4][6], unix 731553Srgrimes * wait/nowait single-threaded/multi-threaded 74188602Sdelphij * user[:group][/login-class] user/group/login-class to run daemon as 751553Srgrimes * server program full path name 761553Srgrimes * server program arguments maximum of MAXARGS (20) 771553Srgrimes * 781553Srgrimes * TCP services without official port numbers are handled with the 791553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 801553Srgrimes * requests. When a connection is made from a foreign host, the service 811553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 821553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 831553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 841553Srgrimes * server is expected to return the positive reply if the service type in 851553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 861553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 871553Srgrimes * process; this is for compatibility with older server code, and also 881553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 891553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 901553Srgrimes * because they do not have a well-known port and hence cannot listen 911553Srgrimes * for new requests. 921553Srgrimes * 932657Scsgr * For RPC services 942657Scsgr * service name/version must be in /etc/rpc 952657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 96100127Salfred * protocol rpc/tcp[4][6], rpc/udp[4][6] 972657Scsgr * wait/nowait single-threaded/multi-threaded 98188602Sdelphij * user[:group][/login-class] user/group/login-class to run daemon as 992657Scsgr * server program full path name 1002657Scsgr * server program arguments maximum of MAXARGS 1012657Scsgr * 1021553Srgrimes * Comment lines are indicated by a `#' in column 1. 10356590Sshin * 10456590Sshin * #ifdef IPSEC 10556590Sshin * Comment lines that start with "#@" denote IPsec policy string, as described 10656590Sshin * in ipsec_set_policy(3). This will affect all the following items in 10756590Sshin * inetd.conf(8). To reset the policy, just use "#@" line. By default, 10856590Sshin * there's no IPsec policy. 10956590Sshin * #endif 1101553Srgrimes */ 1111553Srgrimes#include <sys/param.h> 1121553Srgrimes#include <sys/ioctl.h> 113199804Sattilio#include <sys/mman.h> 1141553Srgrimes#include <sys/wait.h> 1151553Srgrimes#include <sys/time.h> 1161553Srgrimes#include <sys/resource.h> 11778356Sdwmalone#include <sys/stat.h> 11878356Sdwmalone#include <sys/un.h> 1191553Srgrimes 1201553Srgrimes#include <netinet/in.h> 12136042Sguido#include <netinet/tcp.h> 1221553Srgrimes#include <arpa/inet.h> 1232657Scsgr#include <rpc/rpc.h> 12419617Sjulian#include <rpc/pmap_clnt.h> 1251553Srgrimes 126106054Swollman#include <ctype.h> 1271553Srgrimes#include <errno.h> 12829602Scharnier#include <err.h> 1291553Srgrimes#include <fcntl.h> 13030807Sache#include <grp.h> 131106054Swollman#include <libutil.h> 132106054Swollman#include <limits.h> 1331553Srgrimes#include <netdb.h> 1341553Srgrimes#include <pwd.h> 1351553Srgrimes#include <signal.h> 1361553Srgrimes#include <stdio.h> 1371553Srgrimes#include <stdlib.h> 1381553Srgrimes#include <string.h> 139106054Swollman#include <sysexits.h> 1401553Srgrimes#include <syslog.h> 14148279Ssheldonh#include <tcpd.h> 1421553Srgrimes#include <unistd.h> 1431553Srgrimes 14448981Ssheldonh#include "inetd.h" 14548981Ssheldonh#include "pathnames.h" 14648981Ssheldonh 14756590Sshin#ifdef IPSEC 148171135Sgnn#include <netipsec/ipsec.h> 14956590Sshin#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 15056590Sshin#undef IPSEC 15156590Sshin#endif 15256590Sshin#endif 15356590Sshin 15445089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 15545089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 15645089Smarkm#endif 15745089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 15845089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 15945089Smarkm#endif 16045089Smarkm#ifndef LIBWRAP_DENY_FACILITY 16145089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 16245089Smarkm#endif 16345089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 16445089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 16545089Smarkm#endif 16645089Smarkm 16748382Ssheldonh#define ISWRAP(sep) \ 16848697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 16978356Sdwmalone && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 17048382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17148382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 17248382Ssheldonh 17321640Speter#ifdef LOGIN_CAP 17421640Speter#include <login_cap.h> 17530792Sache 17630792Sache/* see init.c */ 17730792Sache#define RESOURCE_RC "daemon" 17830792Sache 17921640Speter#endif 18021640Speter 18133794Spst#ifndef MAXCHILD 18233794Spst#define MAXCHILD -1 /* maximum number of this service 18333794Spst < 0 = no limit */ 18433794Spst#endif 18533794Spst 18633794Spst#ifndef MAXCPM 18733794Spst#define MAXCPM -1 /* rate limit invocations from a 18833794Spst single remote address, 18933794Spst < 0 = no limit */ 19033794Spst#endif 19133794Spst 192101474Sume#ifndef MAXPERIP 193101474Sume#define MAXPERIP -1 /* maximum number of this service 194101474Sume from a single remote address, 195101474Sume < 0 = no limit */ 196101474Sume#endif 197101474Sume 19864197Sdwmalone#ifndef TOOMANY 1992659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 20064197Sdwmalone#endif 2011553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 2021553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 20319618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 2041553Srgrimes 2051553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2061553Srgrimes 20798562Sjmallettvoid close_sep(struct servtab *); 208154530Sdelphijvoid flag_signal(int); 209154530Sdelphijvoid flag_config(int); 21098562Sjmallettvoid config(void); 21198562Sjmallettint cpmip(const struct servtab *, int); 21298562Sjmallettvoid endconfig(void); 21398562Sjmallettstruct servtab *enter(struct servtab *); 21498562Sjmallettvoid freeconfig(struct servtab *); 21598562Sjmallettstruct servtab *getconfigent(void); 21698562Sjmallettint matchservent(const char *, const char *, const char *); 21798562Sjmallettchar *nextline(FILE *); 21898562Sjmallettvoid addchild(struct servtab *, int); 219154530Sdelphijvoid flag_reapchild(int); 220154530Sdelphijvoid reapchild(void); 22198562Sjmallettvoid enable(struct servtab *); 22298562Sjmallettvoid disable(struct servtab *); 223154530Sdelphijvoid flag_retry(int); 22498562Sjmallettvoid retry(void); 22598562Sjmallettint setconfig(void); 22698562Sjmallettvoid setup(struct servtab *); 22778694Sdwmalone#ifdef IPSEC 22898562Sjmallettvoid ipsecsetup(struct servtab *); 22978694Sdwmalone#endif 23098562Sjmallettvoid unregisterrpc(register struct servtab *sep); 231101474Sumestatic struct conninfo *search_conn(struct servtab *sep, int ctrl); 232101474Sumestatic int room_conn(struct servtab *sep, struct conninfo *conn); 233101474Sumestatic void addchild_conn(struct conninfo *conn, pid_t pid); 234154530Sdelphijstatic void reapchild_conn(pid_t pid); 235101474Sumestatic void free_conn(struct conninfo *conn); 236101474Sumestatic void resize_conn(struct servtab *sep, int maxperip); 237101474Sumestatic void free_connlist(struct servtab *sep); 238101474Sumestatic void free_proc(struct procinfo *); 239101474Sumestatic struct procinfo *search_proc(pid_t pid, int add); 240101474Sumestatic int hashval(char *p, int len); 24178694Sdwmalone 24248279Ssheldonhint allow_severity; 24348279Ssheldonhint deny_severity; 24448697Ssheldonhint wrap_ex = 0; 24548279Ssheldonhint wrap_bi = 0; 2461553Srgrimesint debug = 0; 247121766Speterint dolog = 0; 24848988Ssheldonhint maxsock; /* highest-numbered descriptor */ 249154530Sdelphijfd_set allsock; 2501553Srgrimesint options; 2511553Srgrimesint timingout; 2521553Srgrimesint toomany = TOOMANY; 25348069Ssheldonhint maxchild = MAXCHILD; 25448069Ssheldonhint maxcpm = MAXCPM; 255101474Sumeint maxperip = MAXPERIP; 2561553Srgrimesstruct servent *sp; 2572657Scsgrstruct rpcent *rpc; 25856590Sshinchar *hostname = NULL; 25956590Sshinstruct sockaddr_in *bind_sa4; 260102938Sdwmaloneint v4bind_ok = 0; 26156590Sshin#ifdef INET6 26256590Sshinstruct sockaddr_in6 *bind_sa6; 263102938Sdwmaloneint v6bind_ok = 0; 26456590Sshin#endif 265154530Sdelphijint signalpipe[2]; 26648991Ssheldonh#ifdef SANITY_CHECK 26748991Ssheldonhint nsock; 26848991Ssheldonh#endif 26978356Sdwmaloneuid_t euid; 27078356Sdwmalonegid_t egid; 27178356Sdwmalonemode_t mask; 2721553Srgrimes 27348981Ssheldonhstruct servtab *servtab; 2741553Srgrimes 27548981Ssheldonhextern struct biltin biltins[]; 2761553Srgrimes 27778694Sdwmaloneconst char *CONFIG = _PATH_INETDCONF; 27878694Sdwmaloneconst char *pid_file = _PATH_INETDPID; 279149432Spjdstruct pidfh *pfh = NULL; 28013142Speter 281100127Salfredstruct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 282100127Salfred 283101474Sumestatic LIST_HEAD(, procinfo) proctable[PERIPSIZE]; 284101474Sume 2851553Srgrimesint 28698558Sjmallettgetvalue(const char *arg, int *value, const char *whine) 28733794Spst{ 28833794Spst int tmp; 28933794Spst char *p; 29033794Spst 29133794Spst tmp = strtol(arg, &p, 0); 29264197Sdwmalone if (tmp < 0 || *p) { 29333794Spst syslog(LOG_ERR, whine, arg); 29433794Spst return 1; /* failure */ 29533794Spst } 29633794Spst *value = tmp; 29733794Spst return 0; /* success */ 29833794Spst} 29933794Spst 300110802Sumestatic sa_family_t 301110802Sumewhichaf(struct request_info *req) 302110802Sume{ 303110802Sume struct sockaddr *sa; 304110802Sume 305110802Sume sa = (struct sockaddr *)req->client->sin; 306110802Sume if (sa == NULL) 307110802Sume return AF_UNSPEC; 308110802Sume if (sa->sa_family == AF_INET6 && 309110802Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) 310110802Sume return AF_INET; 311110802Sume return sa->sa_family; 312110802Sume} 313110802Sume 31433794Spstint 31598558Sjmallettmain(int argc, char **argv) 3161553Srgrimes{ 3171553Srgrimes struct servtab *sep; 3181553Srgrimes struct passwd *pwd; 31930807Sache struct group *grp; 32048962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 321121555Speter int ch, dofork; 3221553Srgrimes pid_t pid; 3231553Srgrimes char buf[50]; 32421640Speter#ifdef LOGIN_CAP 32521640Speter login_cap_t *lc = NULL; 32621640Speter#endif 32745089Smarkm struct request_info req; 32845089Smarkm int denied; 32945089Smarkm char *service = NULL; 33056590Sshin union { 33156590Sshin struct sockaddr peer_un; 33256590Sshin struct sockaddr_in peer_un4; 33356590Sshin struct sockaddr_in6 peer_un6; 33456590Sshin struct sockaddr_storage peer_max; 33556590Sshin } p_un; 33656590Sshin#define peer p_un.peer_un 33756590Sshin#define peer4 p_un.peer_un4 33856590Sshin#define peer6 p_un.peer_un6 33956590Sshin#define peermax p_un.peer_max 340154530Sdelphij int i; 34156590Sshin struct addrinfo hints, *res; 34278694Sdwmalone const char *servname; 34356590Sshin int error; 344101474Sume struct conninfo *conn; 3451553Srgrimes 34697293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 3471553Srgrimes 348101474Sume while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1) 3491553Srgrimes switch(ch) { 3501553Srgrimes case 'd': 3511553Srgrimes debug = 1; 3521553Srgrimes options |= SO_DEBUG; 3531553Srgrimes break; 3542659Scsgr case 'l': 355121766Speter dolog = 1; 3562659Scsgr break; 35733794Spst case 'R': 35833794Spst getvalue(optarg, &toomany, 35933794Spst "-R %s: bad value for service invocation rate"); 3601553Srgrimes break; 36133794Spst case 'c': 36233794Spst getvalue(optarg, &maxchild, 36333794Spst "-c %s: bad value for maximum children"); 36433794Spst break; 36533794Spst case 'C': 36633794Spst getvalue(optarg, &maxcpm, 36733794Spst "-C %s: bad value for maximum children/minute"); 36833794Spst break; 36917482Sjulian case 'a': 37056590Sshin hostname = optarg; 37117482Sjulian break; 37217482Sjulian case 'p': 37317482Sjulian pid_file = optarg; 37417482Sjulian break; 375101474Sume case 's': 376101474Sume getvalue(optarg, &maxperip, 377101474Sume "-s %s: bad value for maximum children per source address"); 378101474Sume break; 37948279Ssheldonh case 'w': 38048697Ssheldonh wrap_ex++; 38148279Ssheldonh break; 38248697Ssheldonh case 'W': 38348697Ssheldonh wrap_bi++; 38448697Ssheldonh break; 3851553Srgrimes case '?': 3861553Srgrimes default: 3871553Srgrimes syslog(LOG_ERR, 38848697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 38933794Spst " [-c maximum] [-C rate]" 39017482Sjulian " [-p pidfile] [conf-file]"); 39119617Sjulian exit(EX_USAGE); 3921553Srgrimes } 39356590Sshin /* 39456590Sshin * Initialize Bind Addrs. 39556590Sshin * When hostname is NULL, wild card bind addrs are obtained from 39656590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 39756590Sshin * hostname or servname is non NULL. 39856590Sshin * So when hostname is NULL, set dummy value to servname. 399128501Sbrooks * Since getaddrinfo() doesn't accept numeric servname, and 400128501Sbrooks * we doesn't use ai_socktype of struct addrinfo returned 401128501Sbrooks * from getaddrinfo(), we set dummy value to ai_socktype. 40256590Sshin */ 403128501Sbrooks servname = (hostname == NULL) ? "0" /* dummy */ : NULL; 40456590Sshin 40556590Sshin bzero(&hints, sizeof(struct addrinfo)); 40656590Sshin hints.ai_flags = AI_PASSIVE; 40756590Sshin hints.ai_family = AF_UNSPEC; 408128501Sbrooks hints.ai_socktype = SOCK_STREAM; /* dummy */ 40956590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 41056590Sshin if (error != 0) { 41156590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 41256590Sshin if (error == EAI_SYSTEM) 41356590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 41456590Sshin exit(EX_USAGE); 41556590Sshin } 41656590Sshin do { 41756590Sshin if (res->ai_addr == NULL) { 41856590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 41956590Sshin exit(EX_USAGE); 42056590Sshin } 42156590Sshin switch (res->ai_addr->sa_family) { 42256590Sshin case AF_INET: 423102938Sdwmalone if (v4bind_ok) 42456590Sshin continue; 42556590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 42656590Sshin /* init port num in case servname is dummy */ 42756590Sshin bind_sa4->sin_port = 0; 428102938Sdwmalone v4bind_ok = 1; 42956590Sshin continue; 43056590Sshin#ifdef INET6 43156590Sshin case AF_INET6: 432102938Sdwmalone if (v6bind_ok) 43356590Sshin continue; 43456590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 43556590Sshin /* init port num in case servname is dummy */ 43656590Sshin bind_sa6->sin6_port = 0; 437102938Sdwmalone v6bind_ok = 1; 43856590Sshin continue; 43956590Sshin#endif 44056590Sshin } 441102938Sdwmalone if (v4bind_ok 44256590Sshin#ifdef INET6 443102938Sdwmalone && v6bind_ok 44456590Sshin#endif 44556590Sshin ) 44656590Sshin break; 44756590Sshin } while ((res = res->ai_next) != NULL); 448102938Sdwmalone if (!v4bind_ok 44956590Sshin#ifdef INET6 450102938Sdwmalone && !v6bind_ok 45156590Sshin#endif 45256590Sshin ) { 45356590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 45456590Sshin exit(EX_USAGE); 45556590Sshin } 45656590Sshin 45778356Sdwmalone euid = geteuid(); 45878356Sdwmalone egid = getegid(); 45978356Sdwmalone umask(mask = umask(0777)); 46078356Sdwmalone 4611553Srgrimes argc -= optind; 4621553Srgrimes argv += optind; 4631553Srgrimes 4641553Srgrimes if (argc > 0) 4651553Srgrimes CONFIG = argv[0]; 466127301Sdwmalone if (access(CONFIG, R_OK) < 0) 467127301Sdwmalone syslog(LOG_ERR, "Accessing %s: %m, continuing anyway.", CONFIG); 4681553Srgrimes if (debug == 0) { 469149432Spjd pid_t otherpid; 470149432Spjd 471150214Spjd pfh = pidfile_open(pid_file, 0600, &otherpid); 472149432Spjd if (pfh == NULL) { 473149432Spjd if (errno == EEXIST) { 474149432Spjd syslog(LOG_ERR, "%s already running, pid: %d", 475149432Spjd getprogname(), otherpid); 476149432Spjd exit(EX_OSERR); 477149432Spjd } 478149432Spjd syslog(LOG_WARNING, "pidfile_open() failed: %m"); 479149432Spjd } 480149432Spjd 48112024Speter if (daemon(0, 0) < 0) { 48212024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 48312024Speter } 48497293Sjwd /* From now on we don't want syslog messages going to stderr. */ 48597293Sjwd closelog(); 48697293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 48712024Speter /* 48812024Speter * In case somebody has started inetd manually, we need to 48912024Speter * clear the logname, so that old servers run as root do not 49012024Speter * get the user's logname.. 49112024Speter */ 49212024Speter if (setlogin("") < 0) { 49312024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 49412024Speter /* no big deal if it fails.. */ 49512024Speter } 496149432Spjd if (pfh != NULL && pidfile_write(pfh) == -1) { 497149432Spjd syslog(LOG_WARNING, "pidfile_write(): %m"); 49811447Swollman } 4991553Srgrimes } 500100127Salfred 501199804Sattilio if (madvise(NULL, 0, MADV_PROTECT) != 0) 502199804Sattilio syslog(LOG_WARNING, "madvise() failed: %s", strerror(errno)); 503199804Sattilio 504101474Sume for (i = 0; i < PERIPSIZE; ++i) 505101474Sume LIST_INIT(&proctable[i]); 506101474Sume 507102938Sdwmalone if (v4bind_ok) { 508100127Salfred udpconf = getnetconfigent("udp"); 509100127Salfred tcpconf = getnetconfigent("tcp"); 510100127Salfred if (udpconf == NULL || tcpconf == NULL) { 511102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 512100127Salfred exit(EX_USAGE); 513100127Salfred } 514100127Salfred } 515100127Salfred#ifdef INET6 516102938Sdwmalone if (v6bind_ok) { 517100127Salfred udp6conf = getnetconfigent("udp6"); 518100127Salfred tcp6conf = getnetconfigent("tcp6"); 519100127Salfred if (udp6conf == NULL || tcp6conf == NULL) { 520102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 521100127Salfred exit(EX_USAGE); 522100127Salfred } 523100127Salfred } 524100127Salfred#endif 525100127Salfred 52635948Sbde sa.sa_flags = 0; 52735948Sbde sigemptyset(&sa.sa_mask); 52835948Sbde sigaddset(&sa.sa_mask, SIGALRM); 52935948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 53035948Sbde sigaddset(&sa.sa_mask, SIGHUP); 531154530Sdelphij sa.sa_handler = flag_retry; 53248962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 53342122Sdes config(); 534154530Sdelphij sa.sa_handler = flag_config; 53548962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 536154530Sdelphij sa.sa_handler = flag_reapchild; 537154530Sdelphij sigaction(SIGCHLD, &sa, &sachld); 538154530Sdelphij sa.sa_handler = SIG_IGN; 53935948Sbde sigaction(SIGPIPE, &sa, &sapipe); 5401553Srgrimes 5411553Srgrimes { 5421553Srgrimes /* space for daemons to overwrite environment for ps */ 5431553Srgrimes#define DUMMYSIZE 100 5441553Srgrimes char dummy[DUMMYSIZE]; 5451553Srgrimes 54619298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 5471553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 5481553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 5491553Srgrimes } 5501553Srgrimes 551154530Sdelphij if (pipe(signalpipe) != 0) { 552154530Sdelphij syslog(LOG_ERR, "pipe: %m"); 553154530Sdelphij exit(EX_OSERR); 554154530Sdelphij } 555154530Sdelphij if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 || 556154530Sdelphij fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) { 557154530Sdelphij syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m"); 558154530Sdelphij exit(EX_OSERR); 559154530Sdelphij } 560154530Sdelphij FD_SET(signalpipe[0], &allsock); 561154530Sdelphij#ifdef SANITY_CHECK 562154530Sdelphij nsock++; 563154530Sdelphij#endif 564154530Sdelphij if (signalpipe[0] > maxsock) 565154530Sdelphij maxsock = signalpipe[0]; 566154530Sdelphij if (signalpipe[1] > maxsock) 567154530Sdelphij maxsock = signalpipe[1]; 568154530Sdelphij 5691553Srgrimes for (;;) { 5701553Srgrimes int n, ctrl; 571154530Sdelphij fd_set readable; 5721553Srgrimes 57348991Ssheldonh#ifdef SANITY_CHECK 5741553Srgrimes if (nsock == 0) { 575135823Sstefanf syslog(LOG_ERR, "%s: nsock=0", __func__); 57647015Sdes exit(EX_SOFTWARE); 5771553Srgrimes } 57848991Ssheldonh#endif 579154530Sdelphij readable = allsock; 580154530Sdelphij if ((n = select(maxsock + 1, &readable, (fd_set *)0, 581154530Sdelphij (fd_set *)0, (struct timeval *)0)) <= 0) { 582154530Sdelphij if (n < 0 && errno != EINTR) { 583154530Sdelphij syslog(LOG_WARNING, "select: %m"); 58428907Simp sleep(1); 58528907Simp } 5861553Srgrimes continue; 5871553Srgrimes } 588154530Sdelphij /* handle any queued signal flags */ 589154530Sdelphij if (FD_ISSET(signalpipe[0], &readable)) { 590154530Sdelphij int nsig; 591154530Sdelphij if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 592154530Sdelphij syslog(LOG_ERR, "ioctl: %m"); 593154530Sdelphij exit(EX_OSERR); 594154530Sdelphij } 595154530Sdelphij while (--nsig >= 0) { 596154530Sdelphij char c; 597154530Sdelphij if (read(signalpipe[0], &c, 1) != 1) { 598154530Sdelphij syslog(LOG_ERR, "read: %m"); 599154530Sdelphij exit(EX_OSERR); 600154530Sdelphij } 60142250Sdes if (debug) 602154530Sdelphij warnx("handling signal flag %c", c); 603154530Sdelphij switch(c) { 604154530Sdelphij case 'A': /* sigalrm */ 605154530Sdelphij retry(); 606154530Sdelphij break; 607154530Sdelphij case 'C': /* sigchld */ 608154530Sdelphij reapchild(); 609154530Sdelphij break; 610154530Sdelphij case 'H': /* sighup */ 611154530Sdelphij config(); 612154530Sdelphij break; 613154530Sdelphij } 614154530Sdelphij } 615154530Sdelphij } 616154530Sdelphij for (sep = servtab; n && sep; sep = sep->se_next) 617154530Sdelphij if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 618154530Sdelphij n--; 6191553Srgrimes if (debug) 62029602Scharnier warnx("someone wants %s", sep->se_service); 621101474Sume dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 622101474Sume conn = NULL; 62319618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 62453256Speter i = 1; 62553256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 62653256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 6271553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62871399Sdwmalone (socklen_t *)0); 6291553Srgrimes if (debug) 63029602Scharnier warnx("accept, ctrl %d", ctrl); 6311553Srgrimes if (ctrl < 0) { 6321553Srgrimes if (errno != EINTR) 6331553Srgrimes syslog(LOG_WARNING, 6341553Srgrimes "accept (for %s): %m", 63537844Sphk sep->se_service); 63637816Sphk if (sep->se_accept && 63737816Sphk sep->se_socktype == SOCK_STREAM) 63837816Sphk close(ctrl); 6391553Srgrimes continue; 6401553Srgrimes } 64153256Speter i = 0; 64253256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 64353256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 64453256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 64553256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 64630847Sdima if (cpmip(sep, ctrl) < 0) { 64730847Sdima close(ctrl); 64830847Sdima continue; 64930847Sdima } 650101474Sume if (dofork && 651101474Sume (conn = search_conn(sep, ctrl)) != NULL && 652101474Sume !room_conn(sep, conn)) { 653101474Sume close(ctrl); 654101474Sume continue; 655101474Sume } 6561553Srgrimes } else 6571553Srgrimes ctrl = sep->se_fd; 658121766Speter if (dolog && !ISWRAP(sep)) { 65971399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 66071399Sdwmalone socklen_t sl; 66171399Sdwmalone sl = sizeof peermax; 66248382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 66371399Sdwmalone &peermax, &sl)) { 66471399Sdwmalone sl = sizeof peermax; 66548382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 66648382Ssheldonh MSG_PEEK, 66756590Sshin (struct sockaddr *)&peermax, 66871399Sdwmalone &sl) >= 0) { 66956590Sshin getnameinfo((struct sockaddr *)&peermax, 67057383Sshin peer.sa_len, 67156590Sshin pname, sizeof(pname), 672146187Sume NULL, 0, NI_NUMERICHOST); 67356590Sshin } 67456590Sshin } else { 67556590Sshin getnameinfo((struct sockaddr *)&peermax, 67657383Sshin peer.sa_len, 67756590Sshin pname, sizeof(pname), 678146187Sume NULL, 0, NI_NUMERICHOST); 67948382Ssheldonh } 68071399Sdwmalone syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 68148382Ssheldonh } 68242122Sdes (void) sigblock(SIGBLOCK); 6831553Srgrimes pid = 0; 68447972Ssheldonh /* 68548958Ssheldonh * Fork for all external services, builtins which need to 68648958Ssheldonh * fork and anything we're wrapping (as wrapping might 68748958Ssheldonh * block or use hosts_options(5) twist). 68847972Ssheldonh */ 6891553Srgrimes if (dofork) { 6901553Srgrimes if (sep->se_count++ == 0) 691236572Sdelphij (void)clock_gettime(CLOCK_MONOTONIC_FAST, &sep->se_time); 69264197Sdwmalone else if (toomany > 0 && sep->se_count >= toomany) { 693236572Sdelphij struct timespec now; 6941553Srgrimes 695236572Sdelphij (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); 6961553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 6971553Srgrimes CNT_INTVL) { 6981553Srgrimes sep->se_time = now; 6991553Srgrimes sep->se_count = 1; 7001553Srgrimes } else { 7011553Srgrimes syslog(LOG_ERR, 7021553Srgrimes "%s/%s server failing (looping), service terminated", 7031553Srgrimes sep->se_service, sep->se_proto); 70467415Sdwmalone if (sep->se_accept && 70567415Sdwmalone sep->se_socktype == SOCK_STREAM) 70667415Sdwmalone close(ctrl); 7071553Srgrimes close_sep(sep); 708101474Sume free_conn(conn); 70942122Sdes sigsetmask(0L); 7101553Srgrimes if (!timingout) { 7111553Srgrimes timingout = 1; 7121553Srgrimes alarm(RETRYTIME); 7131553Srgrimes } 7141553Srgrimes continue; 7151553Srgrimes } 7161553Srgrimes } 7171553Srgrimes pid = fork(); 7181553Srgrimes } 7191553Srgrimes if (pid < 0) { 7201553Srgrimes syslog(LOG_ERR, "fork: %m"); 72119618Sjulian if (sep->se_accept && 7221553Srgrimes sep->se_socktype == SOCK_STREAM) 7231553Srgrimes close(ctrl); 724101474Sume free_conn(conn); 72542122Sdes sigsetmask(0L); 7261553Srgrimes sleep(1); 7271553Srgrimes continue; 7281553Srgrimes } 729101474Sume if (pid) { 730101474Sume addchild_conn(conn, pid); 73119618Sjulian addchild(sep, pid); 732101474Sume } 73342122Sdes sigsetmask(0L); 7341553Srgrimes if (pid == 0) { 735149432Spjd pidfile_close(pfh); 7361553Srgrimes if (dofork) { 73748962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73848962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 73948962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 74048962Ssheldonh /* SIGPIPE reset before exec */ 7411553Srgrimes } 74235829Sguido /* 74335829Sguido * Call tcpmux to find the real service to exec. 74435829Sguido */ 74535829Sguido if (sep->se_bi && 74678694Sdwmalone sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 74735829Sguido sep = tcpmux(ctrl); 74835829Sguido if (sep == NULL) { 74935829Sguido close(ctrl); 75035829Sguido _exit(0); 75135829Sguido } 75235829Sguido } 75348382Ssheldonh if (ISWRAP(sep)) { 75448698Ssheldonh inetd_setproctitle("wrapping", ctrl); 75547972Ssheldonh service = sep->se_server_name ? 75647972Ssheldonh sep->se_server_name : sep->se_service; 757127865Sdwmalone request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, 0); 75845089Smarkm fromhost(&req); 75947972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 76047972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 76145089Smarkm denied = !hosts_access(&req); 76245089Smarkm if (denied) { 76345089Smarkm syslog(deny_severity, 76496224Sume "refused connection from %.500s, service %s (%s%s)", 76596224Sume eval_client(&req), service, sep->se_proto, 766110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 76748382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 76848382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 76964059Sdwmalone if (dofork) { 77064059Sdwmalone sleep(1); 77148382Ssheldonh _exit(0); 77264059Sdwmalone } 77345089Smarkm } 774121766Speter if (dolog) { 77545089Smarkm syslog(allow_severity, 77696224Sume "connection from %.500s, service %s (%s%s)", 77796224Sume eval_client(&req), service, sep->se_proto, 778110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 77945089Smarkm } 78045089Smarkm } 78119617Sjulian if (sep->se_bi) { 7821553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 78319617Sjulian } else { 7841553Srgrimes if (debug) 78529602Scharnier warnx("%d execl %s", 78629602Scharnier getpid(), sep->se_server); 787111324Sdwmalone /* Clear close-on-exec. */ 788111324Sdwmalone if (fcntl(ctrl, F_SETFD, 0) < 0) { 789111324Sdwmalone syslog(LOG_ERR, 790111324Sdwmalone "%s/%s: fcntl (F_SETFD, 0): %m", 791111324Sdwmalone sep->se_service, sep->se_proto); 792111324Sdwmalone _exit(EX_OSERR); 793111324Sdwmalone } 794111324Sdwmalone if (ctrl != 0) { 795111324Sdwmalone dup2(ctrl, 0); 796111324Sdwmalone close(ctrl); 797111324Sdwmalone } 7981553Srgrimes dup2(0, 1); 7991553Srgrimes dup2(0, 2); 8001553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 8011553Srgrimes syslog(LOG_ERR, 80256482Scharnier "%s/%s: %s: no such user", 8031553Srgrimes sep->se_service, sep->se_proto, 8041553Srgrimes sep->se_user); 8051553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8061553Srgrimes recv(0, buf, sizeof (buf), 0); 80719617Sjulian _exit(EX_NOUSER); 8081553Srgrimes } 80930807Sache grp = NULL; 81030807Sache if ( sep->se_group != NULL 81130807Sache && (grp = getgrnam(sep->se_group)) == NULL 81230807Sache ) { 81330807Sache syslog(LOG_ERR, 81456482Scharnier "%s/%s: %s: no such group", 81530807Sache sep->se_service, sep->se_proto, 81630807Sache sep->se_group); 81730807Sache if (sep->se_socktype != SOCK_STREAM) 81830807Sache recv(0, buf, sizeof (buf), 0); 81930807Sache _exit(EX_NOUSER); 82030807Sache } 82130807Sache if (grp != NULL) 82230807Sache pwd->pw_gid = grp->gr_gid; 82321640Speter#ifdef LOGIN_CAP 82430792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 82530792Sache /* error syslogged by getclass */ 82630792Sache syslog(LOG_ERR, 82730792Sache "%s/%s: %s: login class error", 82837850Sache sep->se_service, sep->se_proto, 82937850Sache sep->se_class); 83030792Sache if (sep->se_socktype != SOCK_STREAM) 83130792Sache recv(0, buf, sizeof (buf), 0); 83230792Sache _exit(EX_NOUSER); 83330792Sache } 83421640Speter#endif 83512024Speter if (setsid() < 0) { 83612024Speter syslog(LOG_ERR, 83712024Speter "%s: can't setsid(): %m", 83812024Speter sep->se_service); 83919617Sjulian /* _exit(EX_OSERR); not fatal yet */ 84012024Speter } 84121640Speter#ifdef LOGIN_CAP 84221640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 843109349Srwatson LOGIN_SETALL & ~LOGIN_SETMAC) 844108951Srwatson != 0) { 84521640Speter syslog(LOG_ERR, 84621640Speter "%s: can't setusercontext(..%s..): %m", 84721640Speter sep->se_service, sep->se_user); 84821640Speter _exit(EX_OSERR); 84921640Speter } 850111323Sdwmalone login_close(lc); 85121640Speter#else 8521553Srgrimes if (pwd->pw_uid) { 85312024Speter if (setlogin(sep->se_user) < 0) { 85412024Speter syslog(LOG_ERR, 85512024Speter "%s: can't setlogin(%s): %m", 85612024Speter sep->se_service, sep->se_user); 85719617Sjulian /* _exit(EX_OSERR); not yet */ 85812024Speter } 8591553Srgrimes if (setgid(pwd->pw_gid) < 0) { 8601553Srgrimes syslog(LOG_ERR, 8618857Srgrimes "%s: can't set gid %d: %m", 8621553Srgrimes sep->se_service, pwd->pw_gid); 86319617Sjulian _exit(EX_OSERR); 8641553Srgrimes } 8651553Srgrimes (void) initgroups(pwd->pw_name, 8661553Srgrimes pwd->pw_gid); 8671553Srgrimes if (setuid(pwd->pw_uid) < 0) { 8681553Srgrimes syslog(LOG_ERR, 8698857Srgrimes "%s: can't set uid %d: %m", 8701553Srgrimes sep->se_service, pwd->pw_uid); 87119617Sjulian _exit(EX_OSERR); 8721553Srgrimes } 8731553Srgrimes } 87421640Speter#endif 87535948Sbde sigaction(SIGPIPE, &sapipe, 87635948Sbde (struct sigaction *)0); 8771553Srgrimes execv(sep->se_server, sep->se_argv); 87845089Smarkm syslog(LOG_ERR, 87945089Smarkm "cannot execute %s: %m", sep->se_server); 8801553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8811553Srgrimes recv(0, buf, sizeof (buf), 0); 8821553Srgrimes } 88347972Ssheldonh if (dofork) 88447972Ssheldonh _exit(0); 8851553Srgrimes } 88619618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 8871553Srgrimes close(ctrl); 8881553Srgrimes } 8891553Srgrimes } 8901553Srgrimes} 8911553Srgrimes 89219618Sjulian/* 893154530Sdelphij * Add a signal flag to the signal flag queue for later handling 894154530Sdelphij */ 895154530Sdelphij 896154530Sdelphijvoid 897154530Sdelphijflag_signal(int c) 898154530Sdelphij{ 899154530Sdelphij char ch = c; 900154530Sdelphij 901154530Sdelphij if (write(signalpipe[1], &ch, 1) != 1) { 902154530Sdelphij syslog(LOG_ERR, "write: %m"); 903154530Sdelphij _exit(EX_OSERR); 904154530Sdelphij } 905154530Sdelphij} 906154530Sdelphij 907154530Sdelphij/* 90819618Sjulian * Record a new child pid for this service. If we've reached the 90919618Sjulian * limit on children, then stop accepting incoming requests. 91019618Sjulian */ 91119618Sjulian 9121553Srgrimesvoid 91319618Sjulianaddchild(struct servtab *sep, pid_t pid) 91419618Sjulian{ 915154530Sdelphij if (sep->se_maxchild <= 0) 916154530Sdelphij return; 91719618Sjulian#ifdef SANITY_CHECK 918154530Sdelphij if (sep->se_numchild >= sep->se_maxchild) { 91919618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 920135823Sstefanf __func__, sep->se_numchild, sep->se_maxchild); 92119618Sjulian exit(EX_SOFTWARE); 92219618Sjulian } 92319618Sjulian#endif 924154530Sdelphij sep->se_pids[sep->se_numchild++] = pid; 925154530Sdelphij if (sep->se_numchild == sep->se_maxchild) 92619618Sjulian disable(sep); 92719618Sjulian} 92819618Sjulian 929154530Sdelphij/* 930154530Sdelphij * Some child process has exited. See if it's on somebody's list. 931154530Sdelphij */ 932154530Sdelphij 93319618Sjulianvoid 934154530Sdelphijflag_reapchild(int signo __unused) 935154530Sdelphij{ 936154530Sdelphij flag_signal('C'); 937154530Sdelphij} 938154530Sdelphij 939154530Sdelphijvoid 940154530Sdelphijreapchild(void) 941154530Sdelphij{ 942154530Sdelphij int k, status; 943154530Sdelphij pid_t pid; 944154530Sdelphij struct servtab *sep; 945154530Sdelphij 946154530Sdelphij for (;;) { 947154530Sdelphij pid = wait3(&status, WNOHANG, (struct rusage *)0); 948154530Sdelphij if (pid <= 0) 949154530Sdelphij break; 950154530Sdelphij if (debug) 951154530Sdelphij warnx("%d reaped, %s %u", pid, 952154530Sdelphij WIFEXITED(status) ? "status" : "signal", 953154530Sdelphij WIFEXITED(status) ? WEXITSTATUS(status) 954154530Sdelphij : WTERMSIG(status)); 955154530Sdelphij for (sep = servtab; sep; sep = sep->se_next) { 956154530Sdelphij for (k = 0; k < sep->se_numchild; k++) 957154530Sdelphij if (sep->se_pids[k] == pid) 958154530Sdelphij break; 959154530Sdelphij if (k == sep->se_numchild) 960154530Sdelphij continue; 961154530Sdelphij if (sep->se_numchild == sep->se_maxchild) 962154530Sdelphij enable(sep); 963154530Sdelphij sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 964154530Sdelphij if (WIFSIGNALED(status) || WEXITSTATUS(status)) 965154530Sdelphij syslog(LOG_WARNING, 966154530Sdelphij "%s[%d]: exited, %s %u", 967154530Sdelphij sep->se_server, pid, 968154530Sdelphij WIFEXITED(status) ? "status" : "signal", 969154530Sdelphij WIFEXITED(status) ? WEXITSTATUS(status) 970154530Sdelphij : WTERMSIG(status)); 971154530Sdelphij break; 972154530Sdelphij } 973154530Sdelphij reapchild_conn(pid); 974154530Sdelphij } 975154530Sdelphij} 976154530Sdelphij 977154530Sdelphijvoid 978154530Sdelphijflag_config(int signo __unused) 979154530Sdelphij{ 980154530Sdelphij flag_signal('H'); 981154530Sdelphij} 982154530Sdelphij 983154530Sdelphijvoid 98498558Sjmallettconfig(void) 98542122Sdes{ 98619618Sjulian struct servtab *sep, *new, **sepp; 98742122Sdes long omask; 988100127Salfred int new_nomapped; 989111323Sdwmalone#ifdef LOGIN_CAP 990111323Sdwmalone login_cap_t *lc = NULL; 991111323Sdwmalone#endif 9921553Srgrimes 9931553Srgrimes if (!setconfig()) { 9941553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 9951553Srgrimes return; 9961553Srgrimes } 997154530Sdelphij for (sep = servtab; sep; sep = sep->se_next) 9981553Srgrimes sep->se_checked = 0; 99919618Sjulian while ((new = getconfigent())) { 100030807Sache if (getpwnam(new->se_user) == NULL) { 10011553Srgrimes syslog(LOG_ERR, 100256482Scharnier "%s/%s: no such user '%s', service ignored", 100319618Sjulian new->se_service, new->se_proto, new->se_user); 10041553Srgrimes continue; 10051553Srgrimes } 100630807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 100730807Sache syslog(LOG_ERR, 100856482Scharnier "%s/%s: no such group '%s', service ignored", 100930807Sache new->se_service, new->se_proto, new->se_group); 101030807Sache continue; 101130807Sache } 101230792Sache#ifdef LOGIN_CAP 1013111323Sdwmalone if ((lc = login_getclass(new->se_class)) == NULL) { 101430792Sache /* error syslogged by getclass */ 101530792Sache syslog(LOG_ERR, 101637850Sache "%s/%s: %s: login class error, service ignored", 101737850Sache new->se_service, new->se_proto, new->se_class); 101830792Sache continue; 101930792Sache } 1020111323Sdwmalone login_close(lc); 102130792Sache#endif 1022100127Salfred new_nomapped = new->se_nomapped; 10231553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 102419618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 102556590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 1026100127Salfred sep->se_rpc == new->se_rpc && 102778356Sdwmalone sep->se_socktype == new->se_socktype && 102856590Sshin sep->se_family == new->se_family) 10291553Srgrimes break; 10301553Srgrimes if (sep != 0) { 10311553Srgrimes int i; 10321553Srgrimes 103398611Sjmallett#define SWAP(t,a, b) { t c = a; a = b; b = c; } 103442122Sdes omask = sigblock(SIGBLOCK); 103556590Sshin if (sep->se_nomapped != new->se_nomapped) { 1036100127Salfred /* for rpc keep old nommaped till unregister */ 1037100127Salfred if (!sep->se_rpc) 1038100127Salfred sep->se_nomapped = new->se_nomapped; 103956590Sshin sep->se_reset = 1; 104056590Sshin } 104119618Sjulian /* copy over outstanding child pids */ 104264197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 104319618Sjulian new->se_numchild = sep->se_numchild; 104419618Sjulian if (new->se_numchild > new->se_maxchild) 104519618Sjulian new->se_numchild = new->se_maxchild; 104619618Sjulian memcpy(new->se_pids, sep->se_pids, 104719618Sjulian new->se_numchild * sizeof(*new->se_pids)); 104819618Sjulian } 104998611Sjmallett SWAP(pid_t *, sep->se_pids, new->se_pids); 105019618Sjulian sep->se_maxchild = new->se_maxchild; 105119618Sjulian sep->se_numchild = new->se_numchild; 105230847Sdima sep->se_maxcpm = new->se_maxcpm; 1053101474Sume resize_conn(sep, new->se_maxperip); 1054101474Sume sep->se_maxperip = new->se_maxperip; 105566544Sdwmalone sep->se_bi = new->se_bi; 105619618Sjulian /* might need to turn on or off service now */ 105719618Sjulian if (sep->se_fd >= 0) { 1058154530Sdelphij if (sep->se_maxchild > 0 1059154530Sdelphij && sep->se_numchild == sep->se_maxchild) { 1060154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) 1061154530Sdelphij disable(sep); 1062154530Sdelphij } else { 1063154530Sdelphij if (!FD_ISSET(sep->se_fd, &allsock)) 1064154530Sdelphij enable(sep); 1065154530Sdelphij } 106619618Sjulian } 106719618Sjulian sep->se_accept = new->se_accept; 106898611Sjmallett SWAP(char *, sep->se_user, new->se_user); 106998611Sjmallett SWAP(char *, sep->se_group, new->se_group); 107030792Sache#ifdef LOGIN_CAP 107198611Sjmallett SWAP(char *, sep->se_class, new->se_class); 107230792Sache#endif 107398611Sjmallett SWAP(char *, sep->se_server, new->se_server); 107498611Sjmallett SWAP(char *, sep->se_server_name, new->se_server_name); 10751553Srgrimes for (i = 0; i < MAXARGV; i++) 107698611Sjmallett SWAP(char *, sep->se_argv[i], new->se_argv[i]); 107756590Sshin#ifdef IPSEC 107898611Sjmallett SWAP(char *, sep->se_policy, new->se_policy); 107956590Sshin ipsecsetup(sep); 108056590Sshin#endif 108142122Sdes sigsetmask(omask); 108219618Sjulian freeconfig(new); 10831553Srgrimes if (debug) 10841553Srgrimes print_service("REDO", sep); 10851553Srgrimes } else { 108619618Sjulian sep = enter(new); 10871553Srgrimes if (debug) 10881553Srgrimes print_service("ADD ", sep); 10891553Srgrimes } 10901553Srgrimes sep->se_checked = 1; 10911553Srgrimes if (ISMUX(sep)) { 10921553Srgrimes sep->se_fd = -1; 10931553Srgrimes continue; 10941553Srgrimes } 109556590Sshin switch (sep->se_family) { 109656590Sshin case AF_INET: 1097102938Sdwmalone if (!v4bind_ok) { 109856590Sshin sep->se_fd = -1; 109956590Sshin continue; 110056590Sshin } 110156590Sshin break; 110256590Sshin#ifdef INET6 110356590Sshin case AF_INET6: 1104102938Sdwmalone if (!v6bind_ok) { 110556590Sshin sep->se_fd = -1; 110656590Sshin continue; 110756590Sshin } 110856590Sshin break; 110956590Sshin#endif 111056590Sshin } 11112657Scsgr if (!sep->se_rpc) { 111278356Sdwmalone if (sep->se_family != AF_UNIX) { 111378356Sdwmalone sp = getservbyname(sep->se_service, sep->se_proto); 111478356Sdwmalone if (sp == 0) { 111578356Sdwmalone syslog(LOG_ERR, "%s/%s: unknown service", 111678356Sdwmalone sep->se_service, sep->se_proto); 111778356Sdwmalone sep->se_checked = 0; 111878356Sdwmalone continue; 111978356Sdwmalone } 11202657Scsgr } 112156590Sshin switch (sep->se_family) { 112256590Sshin case AF_INET: 112356590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 112456590Sshin sep->se_ctrladdr4.sin_port = 112556590Sshin sp->s_port; 112656590Sshin sep->se_reset = 1; 112756590Sshin } 112856590Sshin break; 112956590Sshin#ifdef INET6 113056590Sshin case AF_INET6: 113156590Sshin if (sp->s_port != 113256590Sshin sep->se_ctrladdr6.sin6_port) { 113356590Sshin sep->se_ctrladdr6.sin6_port = 113456590Sshin sp->s_port; 113556590Sshin sep->se_reset = 1; 113656590Sshin } 113756590Sshin break; 113856590Sshin#endif 11392657Scsgr } 114056590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 114156590Sshin close_sep(sep); 11422657Scsgr } else { 11432657Scsgr rpc = getrpcbyname(sep->se_service); 11442657Scsgr if (rpc == 0) { 114552219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 11462657Scsgr sep->se_service, sep->se_proto); 11472657Scsgr if (sep->se_fd != -1) 11482657Scsgr (void) close(sep->se_fd); 11492657Scsgr sep->se_fd = -1; 11502657Scsgr continue; 11512657Scsgr } 1152100127Salfred if (sep->se_reset != 0 || 1153100127Salfred rpc->r_number != sep->se_rpc_prog) { 11542657Scsgr if (sep->se_rpc_prog) 11552657Scsgr unregisterrpc(sep); 11562657Scsgr sep->se_rpc_prog = rpc->r_number; 11572657Scsgr if (sep->se_fd != -1) 11582657Scsgr (void) close(sep->se_fd); 11592657Scsgr sep->se_fd = -1; 11602657Scsgr } 1161100127Salfred sep->se_nomapped = new_nomapped; 11621553Srgrimes } 1163100127Salfred sep->se_reset = 0; 11641553Srgrimes if (sep->se_fd == -1) 11651553Srgrimes setup(sep); 11661553Srgrimes } 11671553Srgrimes endconfig(); 11681553Srgrimes /* 11691553Srgrimes * Purge anything not looked at above. 11701553Srgrimes */ 117142122Sdes omask = sigblock(SIGBLOCK); 11721553Srgrimes sepp = &servtab; 117319617Sjulian while ((sep = *sepp)) { 11741553Srgrimes if (sep->se_checked) { 11751553Srgrimes sepp = &sep->se_next; 11761553Srgrimes continue; 11771553Srgrimes } 11781553Srgrimes *sepp = sep->se_next; 11791553Srgrimes if (sep->se_fd >= 0) 11801553Srgrimes close_sep(sep); 11811553Srgrimes if (debug) 11821553Srgrimes print_service("FREE", sep); 11832657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 11842657Scsgr unregisterrpc(sep); 1185154530Sdelphij freeconfig(sep); 1186154530Sdelphij free(sep); 11871553Srgrimes } 118842122Sdes (void) sigsetmask(omask); 11891553Srgrimes} 11901553Srgrimes 11911553Srgrimesvoid 119298558Sjmallettunregisterrpc(struct servtab *sep) 11932657Scsgr{ 119478694Sdwmalone u_int i; 11952657Scsgr struct servtab *sepp; 119642122Sdes long omask; 1197100127Salfred struct netconfig *netid4, *netid6; 11982657Scsgr 119942122Sdes omask = sigblock(SIGBLOCK); 1200100127Salfred netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1201100127Salfred netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1202100127Salfred if (sep->se_family == AF_INET) 1203100127Salfred netid6 = NULL; 1204100127Salfred else if (sep->se_nomapped) 1205100127Salfred netid4 = NULL; 1206100127Salfred /* 1207100127Salfred * Conflict if same prog and protocol - In that case one should look 1208100127Salfred * to versions, but it is not interesting: having separate servers for 1209100127Salfred * different versions does not work well. 1210100127Salfred * Therefore one do not unregister if there is a conflict. 1211100127Salfred * There is also transport conflict if destroying INET when INET46 1212100127Salfred * exists, or destroying INET46 when INET exists 1213100127Salfred */ 12142657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 12152657Scsgr if (sepp == sep) 12162657Scsgr continue; 1217100127Salfred if (sepp->se_checked == 0 || 12182657Scsgr !sepp->se_rpc || 1219100127Salfred strcmp(sep->se_proto, sepp->se_proto) != 0 || 12202657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 12212657Scsgr continue; 1222100127Salfred if (sepp->se_family == AF_INET) 1223100127Salfred netid4 = NULL; 1224100127Salfred if (sepp->se_family == AF_INET6) { 1225100127Salfred netid6 = NULL; 1226100127Salfred if (!sep->se_nomapped) 1227100127Salfred netid4 = NULL; 1228100127Salfred } 1229100127Salfred if (netid4 == NULL && netid6 == NULL) 1230100127Salfred return; 12312657Scsgr } 12322657Scsgr if (debug) 12332657Scsgr print_service("UNREG", sep); 1234100127Salfred for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1235100127Salfred if (netid4) 1236100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid4); 1237100127Salfred if (netid6) 1238100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid6); 1239100127Salfred } 12402657Scsgr if (sep->se_fd != -1) 12412657Scsgr (void) close(sep->se_fd); 12422657Scsgr sep->se_fd = -1; 124342122Sdes (void) sigsetmask(omask); 12442657Scsgr} 12452657Scsgr 12462657Scsgrvoid 1247154530Sdelphijflag_retry(int signo __unused) 1248154530Sdelphij{ 1249154530Sdelphij flag_signal('A'); 1250154530Sdelphij} 1251154530Sdelphij 1252154530Sdelphijvoid 125398558Sjmallettretry(void) 125442122Sdes{ 12551553Srgrimes struct servtab *sep; 12561553Srgrimes 12571553Srgrimes timingout = 0; 12581553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 125919617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 12601553Srgrimes setup(sep); 12611553Srgrimes} 12621553Srgrimes 12631553Srgrimesvoid 126498558Sjmallettsetup(struct servtab *sep) 12651553Srgrimes{ 12661553Srgrimes int on = 1; 12671553Srgrimes 126856590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 12691553Srgrimes if (debug) 127029602Scharnier warn("socket failed on %s/%s", 127129602Scharnier sep->se_service, sep->se_proto); 12721553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 12731553Srgrimes sep->se_service, sep->se_proto); 12741553Srgrimes return; 12751553Srgrimes } 1276111324Sdwmalone /* Set all listening sockets to close-on-exec. */ 1277111324Sdwmalone if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) { 1278111324Sdwmalone syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m", 1279111324Sdwmalone sep->se_service, sep->se_proto); 1280111324Sdwmalone close(sep->se_fd); 1281111324Sdwmalone return; 1282111324Sdwmalone } 12831553Srgrimes#define turnon(fd, opt) \ 12841553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 12851553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 1286154530Sdelphij turnon(sep->se_fd, SO_DEBUG) < 0) 12871553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 1288154530Sdelphij if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 12891553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 129025253Swollman#ifdef SO_PRIVSTATE 1291154530Sdelphij if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 129213956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 129325253Swollman#endif 129456590Sshin /* tftpd opens a new connection then needs more infos */ 129556590Sshin if ((sep->se_family == AF_INET6) && 129656590Sshin (strcmp(sep->se_proto, "udp") == 0) && 129756590Sshin (sep->se_accept == 0) && 1298121559Sume (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1299154530Sdelphij (char *)&on, sizeof (on)) < 0)) 130056590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 130158935Sume if (sep->se_family == AF_INET6) { 130258935Sume int flag = sep->se_nomapped ? 1 : 0; 1303100505Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 130458935Sume (char *)&flag, sizeof (flag)) < 0) 1305100505Sume syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 130658935Sume } 13071553Srgrimes#undef turnon 130856590Sshin#ifdef IPV6_FAITH 130956590Sshin if (sep->se_type == FAITH_TYPE) { 131056590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 131156590Sshin sizeof(on)) < 0) { 131256590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 131356590Sshin } 131456590Sshin } 131556590Sshin#endif 131656590Sshin#ifdef IPSEC 131756590Sshin ipsecsetup(sep); 131856590Sshin#endif 131978356Sdwmalone if (sep->se_family == AF_UNIX) { 132078356Sdwmalone (void) unlink(sep->se_ctrladdr_un.sun_path); 132178356Sdwmalone umask(0777); /* Make socket with conservative permissions */ 132278356Sdwmalone } 13231553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 132456590Sshin sep->se_ctrladdr_size) < 0) { 13251553Srgrimes if (debug) 132629602Scharnier warn("bind failed on %s/%s", 132729602Scharnier sep->se_service, sep->se_proto); 13281553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 13291553Srgrimes sep->se_service, sep->se_proto); 13301553Srgrimes (void) close(sep->se_fd); 13311553Srgrimes sep->se_fd = -1; 13321553Srgrimes if (!timingout) { 13331553Srgrimes timingout = 1; 13341553Srgrimes alarm(RETRYTIME); 13351553Srgrimes } 133678356Sdwmalone if (sep->se_family == AF_UNIX) 133778356Sdwmalone umask(mask); 13381553Srgrimes return; 13391553Srgrimes } 134078356Sdwmalone if (sep->se_family == AF_UNIX) { 134178356Sdwmalone /* Ick - fch{own,mod} don't work on Unix domain sockets */ 134278356Sdwmalone if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 134378356Sdwmalone syslog(LOG_ERR, "chown socket: %m"); 134478356Sdwmalone if (chmod(sep->se_service, sep->se_sockmode) < 0) 134578356Sdwmalone syslog(LOG_ERR, "chmod socket: %m"); 134678356Sdwmalone umask(mask); 134778356Sdwmalone } 13482657Scsgr if (sep->se_rpc) { 134978694Sdwmalone u_int i; 135071399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 1351100127Salfred struct netconfig *netid, *netid2 = NULL; 1352100127Salfred struct sockaddr_in sock; 1353100127Salfred struct netbuf nbuf, nbuf2; 13542657Scsgr 13558857Srgrimes if (getsockname(sep->se_fd, 13562657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 13572657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 13582657Scsgr sep->se_service, sep->se_proto); 13592657Scsgr (void) close(sep->se_fd); 13602657Scsgr sep->se_fd = -1; 13618857Srgrimes return; 13622657Scsgr } 1363100127Salfred nbuf.buf = &sep->se_ctrladdr; 1364100127Salfred nbuf.len = sep->se_ctrladdr.sa_len; 1365100127Salfred if (sep->se_family == AF_INET) 1366100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1367100127Salfred else { 1368100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1369100127Salfred if (!sep->se_nomapped) { /* INET and INET6 */ 1370100127Salfred netid2 = netid==udp6conf? udpconf:tcpconf; 1371100127Salfred memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1372100127Salfred nbuf2.buf = &sock; 1373100127Salfred nbuf2.len = sock.sin_len = sizeof sock; 1374100127Salfred sock.sin_family = AF_INET; 1375100127Salfred sock.sin_port = sep->se_ctrladdr6.sin6_port; 1376100127Salfred } 1377100127Salfred } 13782657Scsgr if (debug) 13792657Scsgr print_service("REG ", sep); 13802657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1381100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid); 1382100127Salfred rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1383100127Salfred if (netid2) { 1384100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid2); 1385100127Salfred rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1386100127Salfred } 13872657Scsgr } 13882657Scsgr } 13891553Srgrimes if (sep->se_socktype == SOCK_STREAM) 1390245696Szont listen(sep->se_fd, -1); 139119618Sjulian enable(sep); 13921553Srgrimes if (debug) { 139329602Scharnier warnx("registered %s on %d", 13941553Srgrimes sep->se_server, sep->se_fd); 13951553Srgrimes } 13961553Srgrimes} 13971553Srgrimes 139856590Sshin#ifdef IPSEC 139956590Sshinvoid 1400201387Sedipsecsetup(struct servtab *sep) 140156590Sshin{ 140256590Sshin char *buf; 140356590Sshin char *policy_in = NULL; 140456590Sshin char *policy_out = NULL; 140556590Sshin int level; 140656590Sshin int opt; 140756590Sshin 140856590Sshin switch (sep->se_family) { 140956590Sshin case AF_INET: 141056590Sshin level = IPPROTO_IP; 141156590Sshin opt = IP_IPSEC_POLICY; 141256590Sshin break; 141356590Sshin#ifdef INET6 141456590Sshin case AF_INET6: 141556590Sshin level = IPPROTO_IPV6; 141656590Sshin opt = IPV6_IPSEC_POLICY; 141756590Sshin break; 141856590Sshin#endif 141956590Sshin default: 142056590Sshin return; 142156590Sshin } 142256590Sshin 142356590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 142478694Sdwmalone static char def_in[] = "in entrust", def_out[] = "out entrust"; 142578694Sdwmalone policy_in = def_in; 142678694Sdwmalone policy_out = def_out; 142756590Sshin } else { 142856590Sshin if (!strncmp("in", sep->se_policy, 2)) 142956590Sshin policy_in = sep->se_policy; 143056590Sshin else if (!strncmp("out", sep->se_policy, 3)) 143156590Sshin policy_out = sep->se_policy; 143256590Sshin else { 143356590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 143456590Sshin sep->se_policy); 143556590Sshin return; 143656590Sshin } 143756590Sshin } 143856590Sshin 143956590Sshin if (policy_in != NULL) { 144056590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 144156590Sshin if (buf != NULL) { 144256590Sshin if (setsockopt(sep->se_fd, level, opt, 144356675Sshin buf, ipsec_get_policylen(buf)) < 0 && 144456759Sshin debug != 0) 144556759Sshin warnx("%s/%s: ipsec initialization failed; %s", 144656759Sshin sep->se_service, sep->se_proto, 144756759Sshin policy_in); 144856590Sshin free(buf); 144956590Sshin } else 145056590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 145156590Sshin policy_in); 145256590Sshin } 145356590Sshin if (policy_out != NULL) { 145456590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 145556590Sshin if (buf != NULL) { 145656590Sshin if (setsockopt(sep->se_fd, level, opt, 145756675Sshin buf, ipsec_get_policylen(buf)) < 0 && 145856759Sshin debug != 0) 145956759Sshin warnx("%s/%s: ipsec initialization failed; %s", 146056759Sshin sep->se_service, sep->se_proto, 146156759Sshin policy_out); 146256590Sshin free(buf); 146356590Sshin } else 146456590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 146556590Sshin policy_out); 146656590Sshin } 146756590Sshin} 146856590Sshin#endif 146956590Sshin 14701553Srgrimes/* 14711553Srgrimes * Finish with a service and its socket. 14721553Srgrimes */ 14731553Srgrimesvoid 147498558Sjmallettclose_sep(struct servtab *sep) 14751553Srgrimes{ 14761553Srgrimes if (sep->se_fd >= 0) { 1477154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) 1478154530Sdelphij disable(sep); 14791553Srgrimes (void) close(sep->se_fd); 14801553Srgrimes sep->se_fd = -1; 14811553Srgrimes } 14821553Srgrimes sep->se_count = 0; 148319618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 14841553Srgrimes} 14851553Srgrimes 148648467Ssheldonhint 148798558Sjmallettmatchservent(const char *name1, const char *name2, const char *proto) 148848467Ssheldonh{ 148978356Sdwmalone char **alias, *p; 149048467Ssheldonh struct servent *se; 149148467Ssheldonh 149278356Sdwmalone if (strcmp(proto, "unix") == 0) { 149378356Sdwmalone if ((p = strrchr(name1, '/')) != NULL) 149478356Sdwmalone name1 = p + 1; 149578356Sdwmalone if ((p = strrchr(name2, '/')) != NULL) 149678356Sdwmalone name2 = p + 1; 149778356Sdwmalone } 149849026Sdes if (strcmp(name1, name2) == 0) 149949026Sdes return(1); 150048467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 150148467Ssheldonh if (strcmp(name2, se->s_name) == 0) 150248467Ssheldonh return(1); 150348467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 150448467Ssheldonh if (strcmp(name2, *alias) == 0) 150548467Ssheldonh return(1); 150648467Ssheldonh } 150748467Ssheldonh return(0); 150848467Ssheldonh} 150948467Ssheldonh 15101553Srgrimesstruct servtab * 151198558Sjmallettenter(struct servtab *cp) 15121553Srgrimes{ 15131553Srgrimes struct servtab *sep; 151442122Sdes long omask; 15151553Srgrimes 15161553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 1517154530Sdelphij if (sep == (struct servtab *)0) { 151849102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 151919617Sjulian exit(EX_OSERR); 15201553Srgrimes } 15211553Srgrimes *sep = *cp; 15221553Srgrimes sep->se_fd = -1; 152342122Sdes omask = sigblock(SIGBLOCK); 15241553Srgrimes sep->se_next = servtab; 15251553Srgrimes servtab = sep; 152642122Sdes sigsetmask(omask); 15271553Srgrimes return (sep); 15281553Srgrimes} 15291553Srgrimes 153019618Sjulianvoid 153198558Sjmallettenable(struct servtab *sep) 153219618Sjulian{ 153319618Sjulian if (debug) 153429602Scharnier warnx( 153519618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 153619618Sjulian#ifdef SANITY_CHECK 153719618Sjulian if (sep->se_fd < 0) { 153819618Sjulian syslog(LOG_ERR, 1539135823Sstefanf "%s: %s: bad fd", __func__, sep->se_service); 154019618Sjulian exit(EX_SOFTWARE); 154119618Sjulian } 154219618Sjulian if (ISMUX(sep)) { 154319618Sjulian syslog(LOG_ERR, 1544135823Sstefanf "%s: %s: is mux", __func__, sep->se_service); 154519618Sjulian exit(EX_SOFTWARE); 154619618Sjulian } 1547154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) { 1548154530Sdelphij syslog(LOG_ERR, 1549154530Sdelphij "%s: %s: not off", __func__, sep->se_service); 1550154530Sdelphij exit(EX_SOFTWARE); 1551154530Sdelphij } 155248991Ssheldonh nsock++; 155319618Sjulian#endif 1554154530Sdelphij FD_SET(sep->se_fd, &allsock); 155519618Sjulian if (sep->se_fd > maxsock) 155619618Sjulian maxsock = sep->se_fd; 155719618Sjulian} 155819618Sjulian 155919618Sjulianvoid 156098558Sjmallettdisable(struct servtab *sep) 156119618Sjulian{ 156219618Sjulian if (debug) 156329602Scharnier warnx( 156419618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 156519618Sjulian#ifdef SANITY_CHECK 156619618Sjulian if (sep->se_fd < 0) { 156719618Sjulian syslog(LOG_ERR, 1568135823Sstefanf "%s: %s: bad fd", __func__, sep->se_service); 156919618Sjulian exit(EX_SOFTWARE); 157019618Sjulian } 157119618Sjulian if (ISMUX(sep)) { 157219618Sjulian syslog(LOG_ERR, 1573135823Sstefanf "%s: %s: is mux", __func__, sep->se_service); 157419618Sjulian exit(EX_SOFTWARE); 157519618Sjulian } 1576154530Sdelphij if (!FD_ISSET(sep->se_fd, &allsock)) { 1577154530Sdelphij syslog(LOG_ERR, 1578154530Sdelphij "%s: %s: not on", __func__, sep->se_service); 1579154530Sdelphij exit(EX_SOFTWARE); 1580154530Sdelphij } 158119618Sjulian if (nsock == 0) { 1582135823Sstefanf syslog(LOG_ERR, "%s: nsock=0", __func__); 158319618Sjulian exit(EX_SOFTWARE); 158419618Sjulian } 158548991Ssheldonh nsock--; 158619618Sjulian#endif 1587154530Sdelphij FD_CLR(sep->se_fd, &allsock); 158819618Sjulian if (sep->se_fd == maxsock) 158919618Sjulian maxsock--; 159019618Sjulian} 159119618Sjulian 15921553SrgrimesFILE *fconfig = NULL; 15931553Srgrimesstruct servtab serv; 15941553Srgrimeschar line[LINE_MAX]; 15951553Srgrimes 15961553Srgrimesint 159798558Sjmallettsetconfig(void) 15981553Srgrimes{ 15991553Srgrimes 16001553Srgrimes if (fconfig != NULL) { 16011553Srgrimes fseek(fconfig, 0L, SEEK_SET); 16021553Srgrimes return (1); 16031553Srgrimes } 16041553Srgrimes fconfig = fopen(CONFIG, "r"); 16051553Srgrimes return (fconfig != NULL); 16061553Srgrimes} 16071553Srgrimes 16081553Srgrimesvoid 160998558Sjmallettendconfig(void) 16101553Srgrimes{ 16111553Srgrimes if (fconfig) { 16121553Srgrimes (void) fclose(fconfig); 16131553Srgrimes fconfig = NULL; 16141553Srgrimes } 16151553Srgrimes} 16161553Srgrimes 16171553Srgrimesstruct servtab * 161898558Sjmallettgetconfigent(void) 16191553Srgrimes{ 16201553Srgrimes struct servtab *sep = &serv; 16211553Srgrimes int argc; 162219618Sjulian char *cp, *arg, *s; 16232657Scsgr char *versp; 16241553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 16251553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 162656590Sshin#ifdef IPSEC 1627102861Sdwmalone char *policy; 162856590Sshin#endif 1629102861Sdwmalone int v4bind; 163056590Sshin#ifdef INET6 1631102861Sdwmalone int v6bind; 163256590Sshin#endif 1633101474Sume int i; 16341553Srgrimes 1635102861Sdwmalone#ifdef IPSEC 1636102861Sdwmalone policy = NULL; 1637102861Sdwmalone#endif 16381553Srgrimesmore: 1639102861Sdwmalone v4bind = 0; 1640102861Sdwmalone#ifdef INET6 1641102861Sdwmalone v6bind = 0; 1642102861Sdwmalone#endif 164356590Sshin while ((cp = nextline(fconfig)) != NULL) { 164456590Sshin#ifdef IPSEC 164556590Sshin /* lines starting with #@ is not a comment, but the policy */ 164656590Sshin if (cp[0] == '#' && cp[1] == '@') { 164756590Sshin char *p; 164856590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 164956590Sshin ; 165056590Sshin if (*p == '\0') { 1651154530Sdelphij if (policy) 1652154530Sdelphij free(policy); 165356590Sshin policy = NULL; 165456590Sshin } else if (ipsec_get_policylen(p) >= 0) { 1655154530Sdelphij if (policy) 1656154530Sdelphij free(policy); 165756590Sshin policy = newstr(p); 165856590Sshin } else { 165956590Sshin syslog(LOG_ERR, 166056590Sshin "%s: invalid ipsec policy \"%s\"", 166156590Sshin CONFIG, p); 166256590Sshin exit(EX_CONFIG); 166356590Sshin } 166456590Sshin } 166556590Sshin#endif 166656590Sshin if (*cp == '#' || *cp == '\0') 166756590Sshin continue; 166856590Sshin break; 166956590Sshin } 16701553Srgrimes if (cp == NULL) 16711553Srgrimes return ((struct servtab *)0); 16721553Srgrimes /* 16731553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 16741553Srgrimes * for example) don't get initialized here. 16751553Srgrimes */ 167671399Sdwmalone memset(sep, 0, sizeof *sep); 16771553Srgrimes arg = skip(&cp); 16781553Srgrimes if (cp == NULL) { 16791553Srgrimes /* got an empty line containing just blanks/tabs. */ 16801553Srgrimes goto more; 16811553Srgrimes } 168278356Sdwmalone if (arg[0] == ':') { /* :user:group:perm: */ 168378356Sdwmalone char *user, *group, *perm; 168478356Sdwmalone struct passwd *pw; 168578356Sdwmalone struct group *gr; 168678356Sdwmalone user = arg+1; 168778356Sdwmalone if ((group = strchr(user, ':')) == NULL) { 168878356Sdwmalone syslog(LOG_ERR, "no group after user '%s'", user); 168978356Sdwmalone goto more; 169078356Sdwmalone } 169178356Sdwmalone *group++ = '\0'; 169278356Sdwmalone if ((perm = strchr(group, ':')) == NULL) { 169378356Sdwmalone syslog(LOG_ERR, "no mode after group '%s'", group); 169478356Sdwmalone goto more; 169578356Sdwmalone } 169678356Sdwmalone *perm++ = '\0'; 169778356Sdwmalone if ((pw = getpwnam(user)) == NULL) { 169878356Sdwmalone syslog(LOG_ERR, "no such user '%s'", user); 169978356Sdwmalone goto more; 170078356Sdwmalone } 170178356Sdwmalone sep->se_sockuid = pw->pw_uid; 170278356Sdwmalone if ((gr = getgrnam(group)) == NULL) { 170378356Sdwmalone syslog(LOG_ERR, "no such user '%s'", group); 170478356Sdwmalone goto more; 170578356Sdwmalone } 170678356Sdwmalone sep->se_sockgid = gr->gr_gid; 170778356Sdwmalone sep->se_sockmode = strtol(perm, &arg, 8); 170878356Sdwmalone if (*arg != ':') { 170978356Sdwmalone syslog(LOG_ERR, "bad mode '%s'", perm); 171078356Sdwmalone goto more; 171178356Sdwmalone } 171278356Sdwmalone *arg++ = '\0'; 171378356Sdwmalone } else { 171478356Sdwmalone sep->se_sockuid = euid; 171578356Sdwmalone sep->se_sockgid = egid; 171678356Sdwmalone sep->se_sockmode = 0200; 171778356Sdwmalone } 17181553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 17191553Srgrimes char *c = arg + MUX_LEN; 17201553Srgrimes if (*c == '+') { 17211553Srgrimes sep->se_type = MUXPLUS_TYPE; 17221553Srgrimes c++; 17231553Srgrimes } else 17241553Srgrimes sep->se_type = MUX_TYPE; 17251553Srgrimes sep->se_service = newstr(c); 17261553Srgrimes } else { 17271553Srgrimes sep->se_service = newstr(arg); 17281553Srgrimes sep->se_type = NORM_TYPE; 17291553Srgrimes } 17301553Srgrimes arg = sskip(&cp); 17311553Srgrimes if (strcmp(arg, "stream") == 0) 17321553Srgrimes sep->se_socktype = SOCK_STREAM; 17331553Srgrimes else if (strcmp(arg, "dgram") == 0) 17341553Srgrimes sep->se_socktype = SOCK_DGRAM; 17351553Srgrimes else if (strcmp(arg, "rdm") == 0) 17361553Srgrimes sep->se_socktype = SOCK_RDM; 17371553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 17381553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 17391553Srgrimes else if (strcmp(arg, "raw") == 0) 17401553Srgrimes sep->se_socktype = SOCK_RAW; 17411553Srgrimes else 17421553Srgrimes sep->se_socktype = -1; 174336042Sguido 174436042Sguido arg = sskip(&cp); 174556590Sshin if (strncmp(arg, "tcp", 3) == 0) { 174656590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 174756590Sshin if (arg != NULL) { 1748162305Sru if (strcmp(arg, "faith") == 0) 174956590Sshin sep->se_type = FAITH_TYPE; 175056590Sshin } 175177518Sume } else { 175277518Sume if (sep->se_type == NORM_TYPE && 175377518Sume strncmp(arg, "faith/", 6) == 0) { 175477518Sume arg += 6; 175577518Sume sep->se_type = FAITH_TYPE; 175677518Sume } 175736042Sguido sep->se_proto = newstr(arg); 175877518Sume } 17592657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 176019237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 176119237Sjoerg strlen(sep->se_proto) + 1 - 4); 17622657Scsgr sep->se_rpc = 1; 17632657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 17642657Scsgr sep->se_rpc_lowvers = 0; 176556590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 176656590Sshin sizeof(sep->se_ctrladdr4)); 1767229403Sed if ((versp = strrchr(sep->se_service, '/'))) { 17682657Scsgr *versp++ = '\0'; 1769102859Sdwmalone switch (sscanf(versp, "%u-%u", 17702657Scsgr &sep->se_rpc_lowvers, 17712657Scsgr &sep->se_rpc_highvers)) { 17722657Scsgr case 2: 17732657Scsgr break; 17742657Scsgr case 1: 17752657Scsgr sep->se_rpc_highvers = 17762657Scsgr sep->se_rpc_lowvers; 17772657Scsgr break; 17782657Scsgr default: 17798857Srgrimes syslog(LOG_ERR, 178052219Scharnier "bad RPC version specifier; %s", 17812657Scsgr sep->se_service); 17822657Scsgr freeconfig(sep); 17832657Scsgr goto more; 17842657Scsgr } 17852657Scsgr } 17862657Scsgr else { 17872657Scsgr sep->se_rpc_lowvers = 17882657Scsgr sep->se_rpc_highvers = 1; 17892657Scsgr } 17902657Scsgr } 179156590Sshin sep->se_nomapped = 0; 179278356Sdwmalone if (strcmp(sep->se_proto, "unix") == 0) { 179378356Sdwmalone sep->se_family = AF_UNIX; 1794102937Sdwmalone } else { 1795102937Sdwmalone while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 179656590Sshin#ifdef INET6 1797102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1798102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1799102937Sdwmalone v6bind = 1; 1800102937Sdwmalone continue; 1801102937Sdwmalone } 1802102937Sdwmalone#endif 1803102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1804102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1805102937Sdwmalone v4bind = 1; 1806102937Sdwmalone continue; 1807102937Sdwmalone } 1808102937Sdwmalone /* illegal version num */ 1809102937Sdwmalone syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1810100127Salfred freeconfig(sep); 1811100127Salfred goto more; 1812100127Salfred } 1813102937Sdwmalone#ifdef INET6 1814102938Sdwmalone if (v6bind && !v6bind_ok) { 1815102937Sdwmalone syslog(LOG_INFO, "IPv6 bind is ignored for %s", 181656590Sshin sep->se_service); 1817102938Sdwmalone if (v4bind && v4bind_ok) 1818102937Sdwmalone v6bind = 0; 1819102937Sdwmalone else { 1820102937Sdwmalone freeconfig(sep); 1821102937Sdwmalone goto more; 1822102937Sdwmalone } 182356590Sshin } 1824102938Sdwmalone if (v6bind) { 1825102937Sdwmalone sep->se_family = AF_INET6; 1826102938Sdwmalone if (!v4bind || !v4bind_ok) 1827102937Sdwmalone sep->se_nomapped = 1; 1828102937Sdwmalone } else 1829102937Sdwmalone#endif 1830102937Sdwmalone { /* default to v4 bind if not v6 bind */ 1831102938Sdwmalone if (!v4bind_ok) { 1832102937Sdwmalone syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1833102937Sdwmalone sep->se_service); 1834102937Sdwmalone freeconfig(sep); 1835102937Sdwmalone goto more; 1836102937Sdwmalone } 1837102937Sdwmalone sep->se_family = AF_INET; 1838102937Sdwmalone } 183956590Sshin } 184056590Sshin /* init ctladdr */ 184156590Sshin switch(sep->se_family) { 184256590Sshin case AF_INET: 184356590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 184456590Sshin sizeof(sep->se_ctrladdr4)); 184556590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 184656590Sshin break; 184756590Sshin#ifdef INET6 184856590Sshin case AF_INET6: 184956590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 185056590Sshin sizeof(sep->se_ctrladdr6)); 185156590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 185256590Sshin break; 185356590Sshin#endif 185478356Sdwmalone case AF_UNIX: 185578356Sdwmalone if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 185678356Sdwmalone syslog(LOG_ERR, 185778356Sdwmalone "domain socket pathname too long for service %s", 185878356Sdwmalone sep->se_service); 185978356Sdwmalone goto more; 186078356Sdwmalone } 186178356Sdwmalone memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 186278356Sdwmalone sep->se_ctrladdr_un.sun_family = sep->se_family; 186378356Sdwmalone sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 186478356Sdwmalone strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 186578356Sdwmalone sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 186656590Sshin } 18671553Srgrimes arg = sskip(&cp); 186819618Sjulian if (!strncmp(arg, "wait", 4)) 186919618Sjulian sep->se_accept = 0; 187019618Sjulian else if (!strncmp(arg, "nowait", 6)) 187119618Sjulian sep->se_accept = 1; 187219618Sjulian else { 187319618Sjulian syslog(LOG_ERR, 187419618Sjulian "%s: bad wait/nowait for service %s", 187519618Sjulian CONFIG, sep->se_service); 187619618Sjulian goto more; 187719618Sjulian } 187848069Ssheldonh sep->se_maxchild = -1; 187948069Ssheldonh sep->se_maxcpm = -1; 1880101474Sume sep->se_maxperip = -1; 188119618Sjulian if ((s = strchr(arg, '/')) != NULL) { 188219618Sjulian char *eptr; 188319618Sjulian u_long val; 188419618Sjulian 188519618Sjulian val = strtoul(s + 1, &eptr, 10); 188630847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 188719618Sjulian syslog(LOG_ERR, 188819618Sjulian "%s: bad max-child for service %s", 188919618Sjulian CONFIG, sep->se_service); 189019618Sjulian goto more; 189119618Sjulian } 189248069Ssheldonh if (debug) 189348069Ssheldonh if (!sep->se_accept && val != 1) 189448069Ssheldonh warnx("maxchild=%lu for wait service %s" 189548069Ssheldonh " not recommended", val, sep->se_service); 189619618Sjulian sep->se_maxchild = val; 189730847Sdima if (*eptr == '/') 189830847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1899101474Sume if (*eptr == '/') 1900101474Sume sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 190130847Sdima /* 190230847Sdima * explicitly do not check for \0 for future expansion / 190330847Sdima * backwards compatibility 190430847Sdima */ 190519618Sjulian } 19061553Srgrimes if (ISMUX(sep)) { 19071553Srgrimes /* 190819618Sjulian * Silently enforce "nowait" mode for TCPMUX services 190919618Sjulian * since they don't have an assigned port to listen on. 19101553Srgrimes */ 191119618Sjulian sep->se_accept = 1; 19121553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 19138857Srgrimes syslog(LOG_ERR, 19141553Srgrimes "%s: bad protocol for tcpmux service %s", 19151553Srgrimes CONFIG, sep->se_service); 19161553Srgrimes goto more; 19171553Srgrimes } 19181553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 19198857Srgrimes syslog(LOG_ERR, 19201553Srgrimes "%s: bad socket type for tcpmux service %s", 19211553Srgrimes CONFIG, sep->se_service); 19221553Srgrimes goto more; 19231553Srgrimes } 19241553Srgrimes } 19251553Srgrimes sep->se_user = newstr(sskip(&cp)); 192630792Sache#ifdef LOGIN_CAP 192730792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 192830792Sache *s = '\0'; 192930792Sache sep->se_class = newstr(s + 1); 193030792Sache } else 193130792Sache sep->se_class = newstr(RESOURCE_RC); 193230792Sache#endif 193330807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 193430807Sache *s = '\0'; 193530807Sache sep->se_group = newstr(s + 1); 193630807Sache } else 193730807Sache sep->se_group = NULL; 19381553Srgrimes sep->se_server = newstr(sskip(&cp)); 1939229403Sed if ((sep->se_server_name = strrchr(sep->se_server, '/'))) 194045588Smarkm sep->se_server_name++; 19411553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 19421553Srgrimes struct biltin *bi; 19431553Srgrimes 19441553Srgrimes for (bi = biltins; bi->bi_service; bi++) 194549026Sdes if (bi->bi_socktype == sep->se_socktype && 194648467Ssheldonh matchservent(bi->bi_service, sep->se_service, 194748467Ssheldonh sep->se_proto)) 19481553Srgrimes break; 19491553Srgrimes if (bi->bi_service == 0) { 19501553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 19511553Srgrimes sep->se_service); 19521553Srgrimes goto more; 19531553Srgrimes } 195419618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 19551553Srgrimes sep->se_bi = bi; 19561553Srgrimes } else 19571553Srgrimes sep->se_bi = NULL; 1958101474Sume if (sep->se_maxperip < 0) 1959101474Sume sep->se_maxperip = maxperip; 196048069Ssheldonh if (sep->se_maxcpm < 0) 196148069Ssheldonh sep->se_maxcpm = maxcpm; 196245588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 196348069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 196419618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 196548069Ssheldonh else if (sep->se_accept) 196648069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 196719618Sjulian else 196848069Ssheldonh sep->se_maxchild = 1; 196945588Smarkm } 197064197Sdwmalone if (sep->se_maxchild > 0) { 197119618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 197219618Sjulian if (sep->se_pids == NULL) { 197349102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 197419618Sjulian exit(EX_OSERR); 197519618Sjulian } 197619618Sjulian } 19771553Srgrimes argc = 0; 19781553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 197919618Sjulian if (argc < MAXARGV) { 19801553Srgrimes sep->se_argv[argc++] = newstr(arg); 198119618Sjulian } else { 198219618Sjulian syslog(LOG_ERR, 198319618Sjulian "%s: too many arguments for service %s", 198419618Sjulian CONFIG, sep->se_service); 198519618Sjulian goto more; 198619618Sjulian } 19871553Srgrimes while (argc <= MAXARGV) 19881553Srgrimes sep->se_argv[argc++] = NULL; 1989101474Sume for (i = 0; i < PERIPSIZE; ++i) 1990101474Sume LIST_INIT(&sep->se_conn[i]); 199156590Sshin#ifdef IPSEC 199256590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 199356590Sshin#endif 19941553Srgrimes return (sep); 19951553Srgrimes} 19961553Srgrimes 19971553Srgrimesvoid 199898558Sjmallettfreeconfig(struct servtab *cp) 19991553Srgrimes{ 20001553Srgrimes int i; 20011553Srgrimes 2002154530Sdelphij if (cp->se_service) 2003154530Sdelphij free(cp->se_service); 2004154530Sdelphij if (cp->se_proto) 2005154530Sdelphij free(cp->se_proto); 2006154530Sdelphij if (cp->se_user) 2007154530Sdelphij free(cp->se_user); 2008154530Sdelphij if (cp->se_group) 2009154530Sdelphij free(cp->se_group); 201030792Sache#ifdef LOGIN_CAP 2011154530Sdelphij if (cp->se_class) 2012154530Sdelphij free(cp->se_class); 201330792Sache#endif 2014154530Sdelphij if (cp->se_server) 2015154530Sdelphij free(cp->se_server); 2016154530Sdelphij if (cp->se_pids) 2017154530Sdelphij free(cp->se_pids); 20181553Srgrimes for (i = 0; i < MAXARGV; i++) 2019154530Sdelphij if (cp->se_argv[i]) 2020154530Sdelphij free(cp->se_argv[i]); 2021101474Sume free_connlist(cp); 202256590Sshin#ifdef IPSEC 2023154530Sdelphij if (cp->se_policy) 2024154530Sdelphij free(cp->se_policy); 202556590Sshin#endif 20261553Srgrimes} 20271553Srgrimes 20281553Srgrimes 20291553Srgrimes/* 20301553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 20311553Srgrimes * configuration file and exit. 20321553Srgrimes */ 20331553Srgrimeschar * 203498558Sjmallettsskip(char **cpp) 20351553Srgrimes{ 20361553Srgrimes char *cp; 20371553Srgrimes 20381553Srgrimes cp = skip(cpp); 20391553Srgrimes if (cp == NULL) { 20401553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 204119617Sjulian exit(EX_DATAERR); 20421553Srgrimes } 20431553Srgrimes return (cp); 20441553Srgrimes} 20451553Srgrimes 20461553Srgrimeschar * 204798558Sjmallettskip(char **cpp) 20481553Srgrimes{ 20491553Srgrimes char *cp = *cpp; 20501553Srgrimes char *start; 205111933Sadam char quote = '\0'; 20521553Srgrimes 20531553Srgrimesagain: 20541553Srgrimes while (*cp == ' ' || *cp == '\t') 20551553Srgrimes cp++; 20561553Srgrimes if (*cp == '\0') { 20571553Srgrimes int c; 20581553Srgrimes 20591553Srgrimes c = getc(fconfig); 20601553Srgrimes (void) ungetc(c, fconfig); 20611553Srgrimes if (c == ' ' || c == '\t') 206219617Sjulian if ((cp = nextline(fconfig))) 20631553Srgrimes goto again; 20641553Srgrimes *cpp = (char *)0; 20651553Srgrimes return ((char *)0); 20661553Srgrimes } 206711933Sadam if (*cp == '"' || *cp == '\'') 206811933Sadam quote = *cp++; 20691553Srgrimes start = cp; 207011933Sadam if (quote) 207111933Sadam while (*cp && *cp != quote) 207211933Sadam cp++; 207311933Sadam else 207411933Sadam while (*cp && *cp != ' ' && *cp != '\t') 207511933Sadam cp++; 20761553Srgrimes if (*cp != '\0') 20771553Srgrimes *cp++ = '\0'; 20781553Srgrimes *cpp = cp; 20791553Srgrimes return (start); 20801553Srgrimes} 20811553Srgrimes 20821553Srgrimeschar * 208398558Sjmallettnextline(FILE *fd) 20841553Srgrimes{ 20851553Srgrimes char *cp; 20861553Srgrimes 20871553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 20881553Srgrimes return ((char *)0); 20891553Srgrimes cp = strchr(line, '\n'); 20901553Srgrimes if (cp) 20911553Srgrimes *cp = '\0'; 20921553Srgrimes return (line); 20931553Srgrimes} 20941553Srgrimes 20951553Srgrimeschar * 209698558Sjmallettnewstr(const char *cp) 20971553Srgrimes{ 209878694Sdwmalone char *cr; 209978694Sdwmalone 210078694Sdwmalone if ((cr = strdup(cp != NULL ? cp : ""))) 210178694Sdwmalone return (cr); 21021553Srgrimes syslog(LOG_ERR, "strdup: %m"); 210319617Sjulian exit(EX_OSERR); 21041553Srgrimes} 21051553Srgrimes 21061553Srgrimesvoid 210798558Sjmallettinetd_setproctitle(const char *a, int s) 21081553Srgrimes{ 210971399Sdwmalone socklen_t size; 211056590Sshin struct sockaddr_storage ss; 211156590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 21121553Srgrimes 211356590Sshin size = sizeof(ss); 211456590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 211556590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 2116146187Sume NULL, 0, NI_NUMERICHOST); 211756590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 211856590Sshin } else 211913142Speter (void) sprintf(buf, "%s", a); 212013142Speter setproctitle("%s", buf); 212113142Speter} 212213142Speter 212378694Sdwmaloneint 212498558Sjmallettcheck_loop(const struct sockaddr *sa, const struct servtab *sep) 21255182Swollman{ 21265182Swollman struct servtab *se2; 212756590Sshin char pname[INET6_ADDRSTRLEN]; 21285182Swollman 21295182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 21305182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 21315182Swollman continue; 21325182Swollman 213356590Sshin switch (se2->se_family) { 213456590Sshin case AF_INET: 213578694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 213656590Sshin se2->se_ctrladdr4.sin_port) 213756590Sshin goto isloop; 213856590Sshin continue; 213956590Sshin#ifdef INET6 214056590Sshin case AF_INET6: 214178694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214256590Sshin se2->se_ctrladdr4.sin_port) 214356590Sshin goto isloop; 214456590Sshin continue; 214556590Sshin#endif 214656590Sshin default: 214756590Sshin continue; 21485182Swollman } 214956590Sshin isloop: 215056590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 2151146187Sume NI_NUMERICHOST); 215256590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 215356590Sshin sep->se_service, sep->se_proto, 215456590Sshin se2->se_service, se2->se_proto, 215556590Sshin pname); 215656590Sshin return 1; 21575182Swollman } 21585182Swollman return 0; 21595182Swollman} 21605182Swollman 21611553Srgrimes/* 21621553Srgrimes * print_service: 21631553Srgrimes * Dump relevant information to stderr 21641553Srgrimes */ 21651553Srgrimesvoid 216698558Sjmallettprint_service(const char *action, const struct servtab *sep) 21671553Srgrimes{ 216819617Sjulian fprintf(stderr, 216956590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 217030792Sache#ifdef LOGIN_CAP 217156590Sshin "class=%s" 217230792Sache#endif 217356590Sshin " builtin=%p server=%s" 217456590Sshin#ifdef IPSEC 217556590Sshin " policy=\"%s\"" 217656590Sshin#endif 217756590Sshin "\n", 217819617Sjulian action, sep->se_service, sep->se_proto, 217930807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 218030792Sache#ifdef LOGIN_CAP 218130792Sache sep->se_class, 218230792Sache#endif 218356590Sshin (void *) sep->se_bi, sep->se_server 218456590Sshin#ifdef IPSEC 218556590Sshin , (sep->se_policy ? sep->se_policy : "") 218656590Sshin#endif 218756590Sshin ); 21881553Srgrimes} 21891553Srgrimes 219030847Sdima#define CPMHSIZE 256 219130847Sdima#define CPMHMASK (CPMHSIZE-1) 219230847Sdima#define CHTGRAN 10 219330847Sdima#define CHTSIZE 6 219430847Sdima 219530847Sdimatypedef struct CTime { 219630847Sdima unsigned long ct_Ticks; 219730847Sdima int ct_Count; 219830847Sdima} CTime; 219930847Sdima 220030847Sdimatypedef struct CHash { 220156590Sshin union { 220256590Sshin struct in_addr c4_Addr; 220356590Sshin struct in6_addr c6_Addr; 220456590Sshin } cu_Addr; 220556590Sshin#define ch_Addr4 cu_Addr.c4_Addr 220656590Sshin#define ch_Addr6 cu_Addr.c6_Addr 220756590Sshin int ch_Family; 220830847Sdima time_t ch_LTime; 220930847Sdima char *ch_Service; 221030847Sdima CTime ch_Times[CHTSIZE]; 221130847Sdima} CHash; 221230847Sdima 221330847SdimaCHash CHashAry[CPMHSIZE]; 221430847Sdima 221530847Sdimaint 221698558Sjmallettcpmip(const struct servtab *sep, int ctrl) 221730847Sdima{ 221856590Sshin struct sockaddr_storage rss; 221971399Sdwmalone socklen_t rssLen = sizeof(rss); 222030847Sdima int r = 0; 222130847Sdima 222230847Sdima /* 222330847Sdima * If getpeername() fails, just let it through (if logging is 222430847Sdima * enabled the condition is caught elsewhere) 222530847Sdima */ 222630847Sdima 222730847Sdima if (sep->se_maxcpm > 0 && 2228167455Sdwmalone (sep->se_family == AF_INET || sep->se_family == AF_INET6) && 222956590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 223030847Sdima time_t t = time(NULL); 223130847Sdima int hv = 0xABC3D20F; 223230847Sdima int i; 223330847Sdima int cnt = 0; 223430847Sdima CHash *chBest = NULL; 223530847Sdima unsigned int ticks = t / CHTGRAN; 223678694Sdwmalone struct sockaddr_in *sin4; 223756590Sshin#ifdef INET6 223856590Sshin struct sockaddr_in6 *sin6; 223956590Sshin#endif 224030847Sdima 224178694Sdwmalone sin4 = (struct sockaddr_in *)&rss; 224256590Sshin#ifdef INET6 224356590Sshin sin6 = (struct sockaddr_in6 *)&rss; 224456590Sshin#endif 224530847Sdima { 224630847Sdima char *p; 224778694Sdwmalone int addrlen; 224830847Sdima 224956590Sshin switch (rss.ss_family) { 225056590Sshin case AF_INET: 225178694Sdwmalone p = (char *)&sin4->sin_addr; 225256590Sshin addrlen = sizeof(struct in_addr); 225356590Sshin break; 225456590Sshin#ifdef INET6 225556590Sshin case AF_INET6: 225656590Sshin p = (char *)&sin6->sin6_addr; 225756590Sshin addrlen = sizeof(struct in6_addr); 225856590Sshin break; 225956590Sshin#endif 226056590Sshin default: 226156590Sshin /* should not happen */ 226256590Sshin return -1; 226356590Sshin } 226456590Sshin 226556590Sshin for (i = 0; i < addrlen; ++i, ++p) { 226630847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 226730847Sdima } 226830847Sdima hv = (hv ^ (hv >> 16)); 226930847Sdima } 227030847Sdima for (i = 0; i < 5; ++i) { 227130847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 227230847Sdima 227356590Sshin if (rss.ss_family == AF_INET && 227456590Sshin ch->ch_Family == AF_INET && 227578694Sdwmalone sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 227630847Sdima ch->ch_Service && strcmp(sep->se_service, 227730847Sdima ch->ch_Service) == 0) { 227830847Sdima chBest = ch; 227930847Sdima break; 228030847Sdima } 228156590Sshin#ifdef INET6 228256590Sshin if (rss.ss_family == AF_INET6 && 228356590Sshin ch->ch_Family == AF_INET6 && 228456590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 228556590Sshin &ch->ch_Addr6) != 0 && 228656590Sshin ch->ch_Service && strcmp(sep->se_service, 228756590Sshin ch->ch_Service) == 0) { 228856590Sshin chBest = ch; 228956590Sshin break; 229056590Sshin } 229156590Sshin#endif 229230847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 229330847Sdima ch->ch_LTime < chBest->ch_LTime) { 229430847Sdima chBest = ch; 229530847Sdima } 229630847Sdima } 229756590Sshin if ((rss.ss_family == AF_INET && 229856590Sshin (chBest->ch_Family != AF_INET || 229978694Sdwmalone sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 230030847Sdima chBest->ch_Service == NULL || 230130847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 230278694Sdwmalone chBest->ch_Family = sin4->sin_family; 230378694Sdwmalone chBest->ch_Addr4 = sin4->sin_addr; 2304154530Sdelphij if (chBest->ch_Service) 2305154530Sdelphij free(chBest->ch_Service); 230630847Sdima chBest->ch_Service = strdup(sep->se_service); 230730847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 230830847Sdima } 230956590Sshin#ifdef INET6 231056590Sshin if ((rss.ss_family == AF_INET6 && 231156590Sshin (chBest->ch_Family != AF_INET6 || 231256590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 231356590Sshin &chBest->ch_Addr6) == 0)) || 231456590Sshin chBest->ch_Service == NULL || 231556590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 231656590Sshin chBest->ch_Family = sin6->sin6_family; 231756590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 2318154530Sdelphij if (chBest->ch_Service) 2319154530Sdelphij free(chBest->ch_Service); 232056590Sshin chBest->ch_Service = strdup(sep->se_service); 232156590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 232256590Sshin } 232356590Sshin#endif 232430847Sdima chBest->ch_LTime = t; 232530847Sdima { 232630847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 232730847Sdima if (ct->ct_Ticks != ticks) { 232830847Sdima ct->ct_Ticks = ticks; 232930847Sdima ct->ct_Count = 0; 233030847Sdima } 233130847Sdima ++ct->ct_Count; 233230847Sdima } 233330847Sdima for (i = 0; i < CHTSIZE; ++i) { 233430847Sdima CTime *ct = &chBest->ch_Times[i]; 233530847Sdima if (ct->ct_Ticks <= ticks && 233630847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 233730847Sdima cnt += ct->ct_Count; 233830847Sdima } 233930847Sdima } 2340117644Sdwmalone if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 234156590Sshin char pname[INET6_ADDRSTRLEN]; 234256590Sshin 234356590Sshin getnameinfo((struct sockaddr *)&rss, 234456590Sshin ((struct sockaddr *)&rss)->sa_len, 234556590Sshin pname, sizeof(pname), NULL, 0, 2346146187Sume NI_NUMERICHOST); 234730847Sdima r = -1; 234830847Sdima syslog(LOG_ERR, 234933794Spst "%s from %s exceeded counts/min (limit %d/min)", 235056590Sshin sep->se_service, pname, 235133794Spst sep->se_maxcpm); 235230847Sdima } 235330847Sdima } 235430847Sdima return(r); 235530847Sdima} 2356101474Sume 2357101474Sumestatic struct conninfo * 2358101474Sumesearch_conn(struct servtab *sep, int ctrl) 2359101474Sume{ 2360101474Sume struct sockaddr_storage ss; 2361101474Sume socklen_t sslen = sizeof(ss); 2362101474Sume struct conninfo *conn; 2363101474Sume int hv; 2364101474Sume char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2365101474Sume 2366101474Sume if (sep->se_maxperip <= 0) 2367101474Sume return NULL; 2368101474Sume 2369101474Sume /* 2370101474Sume * If getpeername() fails, just let it through (if logging is 2371101474Sume * enabled the condition is caught elsewhere) 2372101474Sume */ 2373101474Sume if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2374101474Sume return NULL; 2375101474Sume 2376101474Sume switch (ss.ss_family) { 2377101474Sume case AF_INET: 2378101474Sume hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2379101474Sume sizeof(struct in_addr)); 2380101474Sume break; 2381101474Sume#ifdef INET6 2382101474Sume case AF_INET6: 2383101474Sume hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2384101474Sume sizeof(struct in6_addr)); 2385101474Sume break; 2386101474Sume#endif 2387101474Sume default: 2388101474Sume /* 2389101474Sume * Since we only support AF_INET and AF_INET6, just 2390101474Sume * let other than AF_INET and AF_INET6 through. 2391101474Sume */ 2392101474Sume return NULL; 2393101474Sume } 2394101474Sume 2395101474Sume if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2396146187Sume NULL, 0, NI_NUMERICHOST) != 0) 2397101474Sume return NULL; 2398101474Sume 2399101474Sume LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2400101474Sume if (getnameinfo((struct sockaddr *)&conn->co_addr, 2401101474Sume conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2402146187Sume NI_NUMERICHOST) == 0 && 2403101474Sume strcmp(pname, pname2) == 0) 2404101474Sume break; 2405101474Sume } 2406101474Sume 2407101474Sume if (conn == NULL) { 2408101474Sume if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2409101474Sume syslog(LOG_ERR, "malloc: %m"); 2410101474Sume exit(EX_OSERR); 2411101474Sume } 2412101474Sume conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2413101474Sume if (conn->co_proc == NULL) { 2414101474Sume syslog(LOG_ERR, "malloc: %m"); 2415101474Sume exit(EX_OSERR); 2416101474Sume } 2417101474Sume memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2418101474Sume conn->co_numchild = 0; 2419101474Sume LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2420101474Sume } 2421101474Sume 2422101474Sume /* 2423101474Sume * Since a child process is not invoked yet, we cannot 2424101474Sume * determine a pid of a child. So, co_proc and co_numchild 2425101474Sume * should be filled leter. 2426101474Sume */ 2427101474Sume 2428101474Sume return conn; 2429101474Sume} 2430101474Sume 2431101474Sumestatic int 2432101474Sumeroom_conn(struct servtab *sep, struct conninfo *conn) 2433101474Sume{ 2434101474Sume char pname[NI_MAXHOST]; 2435101474Sume 2436101474Sume if (conn->co_numchild >= sep->se_maxperip) { 2437101474Sume getnameinfo((struct sockaddr *)&conn->co_addr, 2438101474Sume conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2439146187Sume NI_NUMERICHOST); 2440101474Sume syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2441101474Sume sep->se_service, pname, sep->se_maxperip); 2442101474Sume return 0; 2443101474Sume } 2444101474Sume return 1; 2445101474Sume} 2446101474Sume 2447101474Sumestatic void 2448101474Sumeaddchild_conn(struct conninfo *conn, pid_t pid) 2449101474Sume{ 2450101474Sume struct procinfo *proc; 2451101474Sume 2452101474Sume if (conn == NULL) 2453101474Sume return; 2454101474Sume 2455101474Sume if ((proc = search_proc(pid, 1)) != NULL) { 2456101474Sume if (proc->pr_conn != NULL) { 2457101474Sume syslog(LOG_ERR, 2458101474Sume "addchild_conn: child already on process list"); 2459101474Sume exit(EX_OSERR); 2460101474Sume } 2461101474Sume proc->pr_conn = conn; 2462101474Sume } 2463101474Sume 2464101474Sume conn->co_proc[conn->co_numchild++] = proc; 2465101474Sume} 2466101474Sume 2467101474Sumestatic void 2468154530Sdelphijreapchild_conn(pid_t pid) 2469154530Sdelphij{ 2470154530Sdelphij struct procinfo *proc; 2471154530Sdelphij struct conninfo *conn; 2472154530Sdelphij int i; 2473154530Sdelphij 2474154530Sdelphij if ((proc = search_proc(pid, 0)) == NULL) 2475154530Sdelphij return; 2476154530Sdelphij if ((conn = proc->pr_conn) == NULL) 2477154530Sdelphij return; 2478154530Sdelphij for (i = 0; i < conn->co_numchild; ++i) 2479154530Sdelphij if (conn->co_proc[i] == proc) { 2480154530Sdelphij conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2481154530Sdelphij break; 2482154530Sdelphij } 2483154530Sdelphij free_proc(proc); 2484154530Sdelphij free_conn(conn); 2485154530Sdelphij} 2486154530Sdelphij 2487154530Sdelphijstatic void 2488102859Sdwmaloneresize_conn(struct servtab *sep, int maxpip) 2489101474Sume{ 2490101474Sume struct conninfo *conn; 2491101474Sume int i, j; 2492101474Sume 2493101474Sume if (sep->se_maxperip <= 0) 2494101474Sume return; 2495102859Sdwmalone if (maxpip <= 0) { 2496101474Sume free_connlist(sep); 2497101474Sume return; 2498101474Sume } 2499101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2500101474Sume LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2501102859Sdwmalone for (j = maxpip; j < conn->co_numchild; ++j) 2502101474Sume free_proc(conn->co_proc[j]); 2503101474Sume conn->co_proc = realloc(conn->co_proc, 2504102859Sdwmalone maxpip * sizeof(*conn->co_proc)); 2505101474Sume if (conn->co_proc == NULL) { 2506101474Sume syslog(LOG_ERR, "realloc: %m"); 2507101474Sume exit(EX_OSERR); 2508101474Sume } 2509102859Sdwmalone if (conn->co_numchild > maxpip) 2510102859Sdwmalone conn->co_numchild = maxpip; 2511101474Sume } 2512101474Sume } 2513101474Sume} 2514101474Sume 2515101474Sumestatic void 2516101474Sumefree_connlist(struct servtab *sep) 2517101474Sume{ 2518101474Sume struct conninfo *conn; 2519101474Sume int i, j; 2520101474Sume 2521101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2522101474Sume while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2523101474Sume for (j = 0; j < conn->co_numchild; ++j) 2524101474Sume free_proc(conn->co_proc[j]); 2525101474Sume conn->co_numchild = 0; 2526101474Sume free_conn(conn); 2527101474Sume } 2528101474Sume } 2529101474Sume} 2530101474Sume 2531101474Sumestatic void 2532101474Sumefree_conn(struct conninfo *conn) 2533101474Sume{ 2534101474Sume if (conn == NULL) 2535101474Sume return; 2536101474Sume if (conn->co_numchild <= 0) { 2537101474Sume LIST_REMOVE(conn, co_link); 2538101474Sume free(conn->co_proc); 2539101474Sume free(conn); 2540101474Sume } 2541101474Sume} 2542101474Sume 2543101474Sumestatic struct procinfo * 2544101474Sumesearch_proc(pid_t pid, int add) 2545101474Sume{ 2546101474Sume struct procinfo *proc; 2547101474Sume int hv; 2548101474Sume 2549101474Sume hv = hashval((char *)&pid, sizeof(pid)); 2550101474Sume LIST_FOREACH(proc, &proctable[hv], pr_link) { 2551101474Sume if (proc->pr_pid == pid) 2552101474Sume break; 2553101474Sume } 2554101474Sume if (proc == NULL && add) { 2555101474Sume if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2556101474Sume syslog(LOG_ERR, "malloc: %m"); 2557101474Sume exit(EX_OSERR); 2558101474Sume } 2559101474Sume proc->pr_pid = pid; 2560101474Sume proc->pr_conn = NULL; 2561101474Sume LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2562101474Sume } 2563101474Sume return proc; 2564101474Sume} 2565101474Sume 2566101474Sumestatic void 2567101474Sumefree_proc(struct procinfo *proc) 2568101474Sume{ 2569101474Sume if (proc == NULL) 2570101474Sume return; 2571101474Sume LIST_REMOVE(proc, pr_link); 2572101474Sume free(proc); 2573101474Sume} 2574101474Sume 2575101474Sumestatic int 2576101474Sumehashval(char *p, int len) 2577101474Sume{ 2578101474Sume int i, hv = 0xABC3D20F; 2579101474Sume 2580101474Sume for (i = 0; i < len; ++i, ++p) 2581101474Sume hv = (hv << 5) ^ (hv >> 23) ^ *p; 2582101474Sume hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2583101474Sume return hv; 2584101474Sume} 2585