inetd.c revision 128501
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1991, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3529602Scharnierstatic const char copyright[] = 361553Srgrimes"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 371553Srgrimes The Regents of the University of California. All rights reserved.\n"; 381553Srgrimes#endif /* not lint */ 391553Srgrimes 401553Srgrimes#ifndef lint 4129602Scharnier#if 0 4229602Scharnierstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 4329602Scharnier#endif 441553Srgrimes#endif /* not lint */ 451553Srgrimes 4698563Sjmallett#include <sys/cdefs.h> 4798563Sjmallett__FBSDID("$FreeBSD: head/usr.sbin/inetd/inetd.c 128501 2004-04-20 23:34:39Z brooks $"); 4898563Sjmallett 491553Srgrimes/* 501553Srgrimes * Inetd - Internet super-server 511553Srgrimes * 521553Srgrimes * This program invokes all internet services as needed. Connection-oriented 531553Srgrimes * services are invoked each time a connection is made, by creating a process. 541553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 551553Srgrimes * to do a getpeername to find out the source host and port. 561553Srgrimes * 571553Srgrimes * Datagram oriented services are invoked when a datagram 581553Srgrimes * arrives; a process is created and passed a pending message 591553Srgrimes * on file descriptor 0. Datagram servers may either connect 601553Srgrimes * to their peer, freeing up the original socket for inetd 611553Srgrimes * to receive further messages on, or ``take over the socket'', 621553Srgrimes * processing all arriving datagrams and, eventually, timing 631553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 648857Srgrimes * the second type of server ``single-threaded''. 651553Srgrimes * 661553Srgrimes * Inetd uses a configuration file which is read at startup 671553Srgrimes * and, possibly, at some later time in response to a hangup signal. 681553Srgrimes * The configuration file is ``free format'' with fields given in the 6967514Sdwmalone * order shown below. Continuation lines for an entry must begin with 701553Srgrimes * a space or tab. All fields must be present in each entry. 711553Srgrimes * 7278356Sdwmalone * service name must be in /etc/services 7378356Sdwmalone * or name a tcpmux service 7478356Sdwmalone * or specify a unix domain socket 751553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 7678356Sdwmalone * protocol tcp[4][6][/faith,ttcp], udp[4][6], unix 771553Srgrimes * wait/nowait single-threaded/multi-threaded 781553Srgrimes * user user to run daemon as 791553Srgrimes * server program full path name 801553Srgrimes * server program arguments maximum of MAXARGS (20) 811553Srgrimes * 821553Srgrimes * TCP services without official port numbers are handled with the 831553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 841553Srgrimes * requests. When a connection is made from a foreign host, the service 851553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 861553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 871553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 881553Srgrimes * server is expected to return the positive reply if the service type in 891553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 901553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 911553Srgrimes * process; this is for compatibility with older server code, and also 921553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 931553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 941553Srgrimes * because they do not have a well-known port and hence cannot listen 951553Srgrimes * for new requests. 961553Srgrimes * 972657Scsgr * For RPC services 982657Scsgr * service name/version must be in /etc/rpc 992657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 100100127Salfred * protocol rpc/tcp[4][6], rpc/udp[4][6] 1012657Scsgr * wait/nowait single-threaded/multi-threaded 1022657Scsgr * user user to run daemon as 1032657Scsgr * server program full path name 1042657Scsgr * server program arguments maximum of MAXARGS 1052657Scsgr * 1061553Srgrimes * Comment lines are indicated by a `#' in column 1. 10756590Sshin * 10856590Sshin * #ifdef IPSEC 10956590Sshin * Comment lines that start with "#@" denote IPsec policy string, as described 11056590Sshin * in ipsec_set_policy(3). This will affect all the following items in 11156590Sshin * inetd.conf(8). To reset the policy, just use "#@" line. By default, 11256590Sshin * there's no IPsec policy. 11356590Sshin * #endif 1141553Srgrimes */ 1151553Srgrimes#include <sys/param.h> 1161553Srgrimes#include <sys/ioctl.h> 1171553Srgrimes#include <sys/wait.h> 1181553Srgrimes#include <sys/time.h> 1191553Srgrimes#include <sys/resource.h> 12078356Sdwmalone#include <sys/stat.h> 12178356Sdwmalone#include <sys/un.h> 1221553Srgrimes 1231553Srgrimes#include <netinet/in.h> 12436042Sguido#include <netinet/tcp.h> 1251553Srgrimes#include <arpa/inet.h> 1262657Scsgr#include <rpc/rpc.h> 12719617Sjulian#include <rpc/pmap_clnt.h> 1281553Srgrimes 129106054Swollman#include <ctype.h> 1301553Srgrimes#include <errno.h> 13129602Scharnier#include <err.h> 1321553Srgrimes#include <fcntl.h> 13330807Sache#include <grp.h> 134106054Swollman#include <libutil.h> 135106054Swollman#include <limits.h> 1361553Srgrimes#include <netdb.h> 1371553Srgrimes#include <pwd.h> 1381553Srgrimes#include <signal.h> 1391553Srgrimes#include <stdio.h> 1401553Srgrimes#include <stdlib.h> 1411553Srgrimes#include <string.h> 142106054Swollman#include <sysexits.h> 1431553Srgrimes#include <syslog.h> 14448279Ssheldonh#include <tcpd.h> 1451553Srgrimes#include <unistd.h> 1461553Srgrimes 14748981Ssheldonh#include "inetd.h" 14848981Ssheldonh#include "pathnames.h" 14948981Ssheldonh 15056590Sshin#ifdef IPSEC 15156590Sshin#include <netinet6/ipsec.h> 15256590Sshin#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 15356590Sshin#undef IPSEC 15456590Sshin#endif 15556590Sshin#endif 15656590Sshin 15756590Sshin/* wrapper for KAME-special getnameinfo() */ 15856590Sshin#ifndef NI_WITHSCOPEID 15956590Sshin#define NI_WITHSCOPEID 0 16056590Sshin#endif 16156590Sshin 16245089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 16345089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 16445089Smarkm#endif 16545089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 16645089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 16745089Smarkm#endif 16845089Smarkm#ifndef LIBWRAP_DENY_FACILITY 16945089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 17045089Smarkm#endif 17145089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 17245089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 17345089Smarkm#endif 17445089Smarkm 17548382Ssheldonh#define ISWRAP(sep) \ 17648697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 17778356Sdwmalone && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 17848382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17948382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 18048382Ssheldonh 18121640Speter#ifdef LOGIN_CAP 18221640Speter#include <login_cap.h> 18330792Sache 18430792Sache/* see init.c */ 18530792Sache#define RESOURCE_RC "daemon" 18630792Sache 18721640Speter#endif 18821640Speter 18933794Spst#ifndef MAXCHILD 19033794Spst#define MAXCHILD -1 /* maximum number of this service 19133794Spst < 0 = no limit */ 19233794Spst#endif 19333794Spst 19433794Spst#ifndef MAXCPM 19533794Spst#define MAXCPM -1 /* rate limit invocations from a 19633794Spst single remote address, 19733794Spst < 0 = no limit */ 19833794Spst#endif 19933794Spst 200101474Sume#ifndef MAXPERIP 201101474Sume#define MAXPERIP -1 /* maximum number of this service 202101474Sume from a single remote address, 203101474Sume < 0 = no limit */ 204101474Sume#endif 205101474Sume 20664197Sdwmalone#ifndef TOOMANY 2072659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 20864197Sdwmalone#endif 2091553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 2101553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 21119618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 2121553Srgrimes 2131553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2141553Srgrimes 21598562Sjmallettvoid close_sep(struct servtab *); 21698562Sjmallettvoid flag_signal(int); 21798562Sjmallettvoid flag_config(int); 21898562Sjmallettvoid config(void); 21998562Sjmallettint cpmip(const struct servtab *, int); 22098562Sjmallettvoid endconfig(void); 22198562Sjmallettstruct servtab *enter(struct servtab *); 22298562Sjmallettvoid freeconfig(struct servtab *); 22398562Sjmallettstruct servtab *getconfigent(void); 22498562Sjmallettint matchservent(const char *, const char *, const char *); 22598562Sjmallettchar *nextline(FILE *); 22698562Sjmallettvoid addchild(struct servtab *, int); 22798562Sjmallettvoid flag_reapchild(int); 22898562Sjmallettvoid reapchild(void); 22998562Sjmallettvoid enable(struct servtab *); 23098562Sjmallettvoid disable(struct servtab *); 23198562Sjmallettvoid flag_retry(int); 23298562Sjmallettvoid retry(void); 23398562Sjmallettint setconfig(void); 23498562Sjmallettvoid setup(struct servtab *); 23578694Sdwmalone#ifdef IPSEC 23698562Sjmallettvoid ipsecsetup(struct servtab *); 23778694Sdwmalone#endif 23898562Sjmallettvoid unregisterrpc(register struct servtab *sep); 239101474Sumestatic struct conninfo *search_conn(struct servtab *sep, int ctrl); 240101474Sumestatic int room_conn(struct servtab *sep, struct conninfo *conn); 241101474Sumestatic void addchild_conn(struct conninfo *conn, pid_t pid); 242101474Sumestatic void reapchild_conn(pid_t pid); 243101474Sumestatic void free_conn(struct conninfo *conn); 244101474Sumestatic void resize_conn(struct servtab *sep, int maxperip); 245101474Sumestatic void free_connlist(struct servtab *sep); 246101474Sumestatic void free_proc(struct procinfo *); 247101474Sumestatic struct procinfo *search_proc(pid_t pid, int add); 248101474Sumestatic int hashval(char *p, int len); 24978694Sdwmalone 25048279Ssheldonhint allow_severity; 25148279Ssheldonhint deny_severity; 25248697Ssheldonhint wrap_ex = 0; 25348279Ssheldonhint wrap_bi = 0; 2541553Srgrimesint debug = 0; 255121766Speterint dolog = 0; 25648988Ssheldonhint maxsock; /* highest-numbered descriptor */ 2571553Srgrimesfd_set allsock; 2581553Srgrimesint options; 2591553Srgrimesint timingout; 2601553Srgrimesint toomany = TOOMANY; 26148069Ssheldonhint maxchild = MAXCHILD; 26248069Ssheldonhint maxcpm = MAXCPM; 263101474Sumeint maxperip = MAXPERIP; 2641553Srgrimesstruct servent *sp; 2652657Scsgrstruct rpcent *rpc; 26656590Sshinchar *hostname = NULL; 26756590Sshinstruct sockaddr_in *bind_sa4; 268102938Sdwmaloneint v4bind_ok = 0; 26956590Sshin#ifdef INET6 27056590Sshinstruct sockaddr_in6 *bind_sa6; 271102938Sdwmaloneint v6bind_ok = 0; 27256590Sshin#endif 27342122Sdesint signalpipe[2]; 27448991Ssheldonh#ifdef SANITY_CHECK 27548991Ssheldonhint nsock; 27648991Ssheldonh#endif 27778356Sdwmaloneuid_t euid; 27878356Sdwmalonegid_t egid; 27978356Sdwmalonemode_t mask; 2801553Srgrimes 28148981Ssheldonhstruct servtab *servtab; 2821553Srgrimes 28348981Ssheldonhextern struct biltin biltins[]; 2841553Srgrimes 28578694Sdwmaloneconst char *CONFIG = _PATH_INETDCONF; 28678694Sdwmaloneconst char *pid_file = _PATH_INETDPID; 28713142Speter 288100127Salfredstruct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 289100127Salfred 290101474Sumestatic LIST_HEAD(, procinfo) proctable[PERIPSIZE]; 291101474Sume 2921553Srgrimesint 29398558Sjmallettgetvalue(const char *arg, int *value, const char *whine) 29433794Spst{ 29533794Spst int tmp; 29633794Spst char *p; 29733794Spst 29833794Spst tmp = strtol(arg, &p, 0); 29964197Sdwmalone if (tmp < 0 || *p) { 30033794Spst syslog(LOG_ERR, whine, arg); 30133794Spst return 1; /* failure */ 30233794Spst } 30333794Spst *value = tmp; 30433794Spst return 0; /* success */ 30533794Spst} 30633794Spst 307110802Sumestatic sa_family_t 308110802Sumewhichaf(struct request_info *req) 309110802Sume{ 310110802Sume struct sockaddr *sa; 311110802Sume 312110802Sume sa = (struct sockaddr *)req->client->sin; 313110802Sume if (sa == NULL) 314110802Sume return AF_UNSPEC; 315110802Sume if (sa->sa_family == AF_INET6 && 316110802Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) 317110802Sume return AF_INET; 318110802Sume return sa->sa_family; 319110802Sume} 320110802Sume 32133794Spstint 32298558Sjmallettmain(int argc, char **argv) 3231553Srgrimes{ 3241553Srgrimes struct servtab *sep; 3251553Srgrimes struct passwd *pwd; 32630807Sache struct group *grp; 32748962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 328121555Speter int ch, dofork; 3291553Srgrimes pid_t pid; 3301553Srgrimes char buf[50]; 33121640Speter#ifdef LOGIN_CAP 33221640Speter login_cap_t *lc = NULL; 33321640Speter#endif 33445089Smarkm struct request_info req; 33545089Smarkm int denied; 33645089Smarkm char *service = NULL; 33756590Sshin union { 33856590Sshin struct sockaddr peer_un; 33956590Sshin struct sockaddr_in peer_un4; 34056590Sshin struct sockaddr_in6 peer_un6; 34156590Sshin struct sockaddr_storage peer_max; 34256590Sshin } p_un; 34356590Sshin#define peer p_un.peer_un 34456590Sshin#define peer4 p_un.peer_un4 34556590Sshin#define peer6 p_un.peer_un6 34656590Sshin#define peermax p_un.peer_max 34747972Ssheldonh int i; 34856590Sshin struct addrinfo hints, *res; 34978694Sdwmalone const char *servname; 35056590Sshin int error; 351101474Sume struct conninfo *conn; 3521553Srgrimes 35397293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 3541553Srgrimes 355101474Sume while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1) 3561553Srgrimes switch(ch) { 3571553Srgrimes case 'd': 3581553Srgrimes debug = 1; 3591553Srgrimes options |= SO_DEBUG; 3601553Srgrimes break; 3612659Scsgr case 'l': 362121766Speter dolog = 1; 3632659Scsgr break; 36433794Spst case 'R': 36533794Spst getvalue(optarg, &toomany, 36633794Spst "-R %s: bad value for service invocation rate"); 3671553Srgrimes break; 36833794Spst case 'c': 36933794Spst getvalue(optarg, &maxchild, 37033794Spst "-c %s: bad value for maximum children"); 37133794Spst break; 37233794Spst case 'C': 37333794Spst getvalue(optarg, &maxcpm, 37433794Spst "-C %s: bad value for maximum children/minute"); 37533794Spst break; 37617482Sjulian case 'a': 37756590Sshin hostname = optarg; 37817482Sjulian break; 37917482Sjulian case 'p': 38017482Sjulian pid_file = optarg; 38117482Sjulian break; 382101474Sume case 's': 383101474Sume getvalue(optarg, &maxperip, 384101474Sume "-s %s: bad value for maximum children per source address"); 385101474Sume break; 38648279Ssheldonh case 'w': 38748697Ssheldonh wrap_ex++; 38848279Ssheldonh break; 38948697Ssheldonh case 'W': 39048697Ssheldonh wrap_bi++; 39148697Ssheldonh break; 3921553Srgrimes case '?': 3931553Srgrimes default: 3941553Srgrimes syslog(LOG_ERR, 39548697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 39633794Spst " [-c maximum] [-C rate]" 39717482Sjulian " [-p pidfile] [conf-file]"); 39819617Sjulian exit(EX_USAGE); 3991553Srgrimes } 40056590Sshin /* 40156590Sshin * Initialize Bind Addrs. 40256590Sshin * When hostname is NULL, wild card bind addrs are obtained from 40356590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 40456590Sshin * hostname or servname is non NULL. 40556590Sshin * So when hostname is NULL, set dummy value to servname. 406128501Sbrooks * Since getaddrinfo() doesn't accept numeric servname, and 407128501Sbrooks * we doesn't use ai_socktype of struct addrinfo returned 408128501Sbrooks * from getaddrinfo(), we set dummy value to ai_socktype. 40956590Sshin */ 410128501Sbrooks servname = (hostname == NULL) ? "0" /* dummy */ : NULL; 41156590Sshin 41256590Sshin bzero(&hints, sizeof(struct addrinfo)); 41356590Sshin hints.ai_flags = AI_PASSIVE; 41456590Sshin hints.ai_family = AF_UNSPEC; 415128501Sbrooks hints.ai_socktype = SOCK_STREAM; /* dummy */ 41656590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 41756590Sshin if (error != 0) { 41856590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 41956590Sshin if (error == EAI_SYSTEM) 42056590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 42156590Sshin exit(EX_USAGE); 42256590Sshin } 42356590Sshin do { 42456590Sshin if (res->ai_addr == NULL) { 42556590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 42656590Sshin exit(EX_USAGE); 42756590Sshin } 42856590Sshin switch (res->ai_addr->sa_family) { 42956590Sshin case AF_INET: 430102938Sdwmalone if (v4bind_ok) 43156590Sshin continue; 43256590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 43356590Sshin /* init port num in case servname is dummy */ 43456590Sshin bind_sa4->sin_port = 0; 435102938Sdwmalone v4bind_ok = 1; 43656590Sshin continue; 43756590Sshin#ifdef INET6 43856590Sshin case AF_INET6: 439102938Sdwmalone if (v6bind_ok) 44056590Sshin continue; 44156590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 44256590Sshin /* init port num in case servname is dummy */ 44356590Sshin bind_sa6->sin6_port = 0; 444102938Sdwmalone v6bind_ok = 1; 44556590Sshin continue; 44656590Sshin#endif 44756590Sshin } 448102938Sdwmalone if (v4bind_ok 44956590Sshin#ifdef INET6 450102938Sdwmalone && v6bind_ok 45156590Sshin#endif 45256590Sshin ) 45356590Sshin break; 45456590Sshin } while ((res = res->ai_next) != NULL); 455102938Sdwmalone if (!v4bind_ok 45656590Sshin#ifdef INET6 457102938Sdwmalone && !v6bind_ok 45856590Sshin#endif 45956590Sshin ) { 46056590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 46156590Sshin exit(EX_USAGE); 46256590Sshin } 46356590Sshin 46478356Sdwmalone euid = geteuid(); 46578356Sdwmalone egid = getegid(); 46678356Sdwmalone umask(mask = umask(0777)); 46778356Sdwmalone 4681553Srgrimes argc -= optind; 4691553Srgrimes argv += optind; 4701553Srgrimes 4711553Srgrimes if (argc > 0) 4721553Srgrimes CONFIG = argv[0]; 473127301Sdwmalone if (access(CONFIG, R_OK) < 0) 474127301Sdwmalone syslog(LOG_ERR, "Accessing %s: %m, continuing anyway.", CONFIG); 4751553Srgrimes if (debug == 0) { 47611447Swollman FILE *fp; 47712024Speter if (daemon(0, 0) < 0) { 47812024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 47912024Speter } 48097293Sjwd /* From now on we don't want syslog messages going to stderr. */ 48197293Sjwd closelog(); 48297293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 48312024Speter /* 48412024Speter * In case somebody has started inetd manually, we need to 48512024Speter * clear the logname, so that old servers run as root do not 48612024Speter * get the user's logname.. 48712024Speter */ 48812024Speter if (setlogin("") < 0) { 48912024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 49012024Speter /* no big deal if it fails.. */ 49112024Speter } 49211447Swollman pid = getpid(); 49317482Sjulian fp = fopen(pid_file, "w"); 49411447Swollman if (fp) { 49511447Swollman fprintf(fp, "%ld\n", (long)pid); 49611447Swollman fclose(fp); 49711447Swollman } else { 49817482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 49911447Swollman } 5001553Srgrimes } 501100127Salfred 502101474Sume for (i = 0; i < PERIPSIZE; ++i) 503101474Sume LIST_INIT(&proctable[i]); 504101474Sume 505102938Sdwmalone if (v4bind_ok) { 506100127Salfred udpconf = getnetconfigent("udp"); 507100127Salfred tcpconf = getnetconfigent("tcp"); 508100127Salfred if (udpconf == NULL || tcpconf == NULL) { 509102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 510100127Salfred exit(EX_USAGE); 511100127Salfred } 512100127Salfred } 513100127Salfred#ifdef INET6 514102938Sdwmalone if (v6bind_ok) { 515100127Salfred udp6conf = getnetconfigent("udp6"); 516100127Salfred tcp6conf = getnetconfigent("tcp6"); 517100127Salfred if (udp6conf == NULL || tcp6conf == NULL) { 518102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 519100127Salfred exit(EX_USAGE); 520100127Salfred } 521100127Salfred } 522100127Salfred#endif 523100127Salfred 52435948Sbde sa.sa_flags = 0; 52535948Sbde sigemptyset(&sa.sa_mask); 52635948Sbde sigaddset(&sa.sa_mask, SIGALRM); 52735948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 52835948Sbde sigaddset(&sa.sa_mask, SIGHUP); 52942122Sdes sa.sa_handler = flag_retry; 53048962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 53142122Sdes config(); 53242122Sdes sa.sa_handler = flag_config; 53348962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 53442122Sdes sa.sa_handler = flag_reapchild; 53548962Ssheldonh sigaction(SIGCHLD, &sa, &sachld); 53635848Sguido sa.sa_handler = SIG_IGN; 53735948Sbde sigaction(SIGPIPE, &sa, &sapipe); 5381553Srgrimes 5391553Srgrimes { 5401553Srgrimes /* space for daemons to overwrite environment for ps */ 5411553Srgrimes#define DUMMYSIZE 100 5421553Srgrimes char dummy[DUMMYSIZE]; 5431553Srgrimes 54419298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 5451553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 5461553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 5471553Srgrimes } 5481553Srgrimes 54942250Sdes if (pipe(signalpipe) != 0) { 55052219Scharnier syslog(LOG_ERR, "pipe: %m"); 55142250Sdes exit(EX_OSERR); 55242122Sdes } 553111324Sdwmalone if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 || 554111324Sdwmalone fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) { 555111324Sdwmalone syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m"); 556111324Sdwmalone exit(EX_OSERR); 557111324Sdwmalone } 55842122Sdes FD_SET(signalpipe[0], &allsock); 55948991Ssheldonh#ifdef SANITY_CHECK 56047015Sdes nsock++; 56148991Ssheldonh#endif 56248989Ssheldonh if (signalpipe[0] > maxsock) 56348989Ssheldonh maxsock = signalpipe[0]; 56448989Ssheldonh if (signalpipe[1] > maxsock) 56548989Ssheldonh maxsock = signalpipe[1]; 56641685Sdillon 5671553Srgrimes for (;;) { 5681553Srgrimes int n, ctrl; 5691553Srgrimes fd_set readable; 5701553Srgrimes 57148991Ssheldonh#ifdef SANITY_CHECK 5721553Srgrimes if (nsock == 0) { 57347015Sdes syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 57447015Sdes exit(EX_SOFTWARE); 5751553Srgrimes } 57648991Ssheldonh#endif 5771553Srgrimes readable = allsock; 57842122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 57942122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 58042122Sdes if (n < 0 && errno != EINTR) { 5811553Srgrimes syslog(LOG_WARNING, "select: %m"); 58228907Simp sleep(1); 58328907Simp } 5841553Srgrimes continue; 5851553Srgrimes } 58642122Sdes /* handle any queued signal flags */ 58742250Sdes if (FD_ISSET(signalpipe[0], &readable)) { 58871399Sdwmalone int nsig; 58971399Sdwmalone if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 59042122Sdes syslog(LOG_ERR, "ioctl: %m"); 59142122Sdes exit(EX_OSERR); 59242122Sdes } 59371399Sdwmalone while (--nsig >= 0) { 59442250Sdes char c; 59542250Sdes if (read(signalpipe[0], &c, 1) != 1) { 59642250Sdes syslog(LOG_ERR, "read: %m"); 59742250Sdes exit(EX_OSERR); 59842250Sdes } 59942250Sdes if (debug) 60056482Scharnier warnx("handling signal flag %c", c); 60142250Sdes switch(c) { 60242250Sdes case 'A': /* sigalrm */ 60342250Sdes retry(); 60442250Sdes break; 60542250Sdes case 'C': /* sigchld */ 60642250Sdes reapchild(); 60742250Sdes break; 60842250Sdes case 'H': /* sighup */ 60942250Sdes config(); 61042250Sdes break; 61142250Sdes } 61242250Sdes } 61342122Sdes } 6141553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 6151553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 6161553Srgrimes n--; 6171553Srgrimes if (debug) 61829602Scharnier warnx("someone wants %s", sep->se_service); 619101474Sume dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 620101474Sume conn = NULL; 62119618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 62253256Speter i = 1; 62353256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 62453256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 6251553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62671399Sdwmalone (socklen_t *)0); 6271553Srgrimes if (debug) 62829602Scharnier warnx("accept, ctrl %d", ctrl); 6291553Srgrimes if (ctrl < 0) { 6301553Srgrimes if (errno != EINTR) 6311553Srgrimes syslog(LOG_WARNING, 6321553Srgrimes "accept (for %s): %m", 63337844Sphk sep->se_service); 63437816Sphk if (sep->se_accept && 63537816Sphk sep->se_socktype == SOCK_STREAM) 63637816Sphk close(ctrl); 6371553Srgrimes continue; 6381553Srgrimes } 63953256Speter i = 0; 64053256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 64153256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 64253256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 64353256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 64430847Sdima if (cpmip(sep, ctrl) < 0) { 64530847Sdima close(ctrl); 64630847Sdima continue; 64730847Sdima } 648101474Sume if (dofork && 649101474Sume (conn = search_conn(sep, ctrl)) != NULL && 650101474Sume !room_conn(sep, conn)) { 651101474Sume close(ctrl); 652101474Sume continue; 653101474Sume } 6541553Srgrimes } else 6551553Srgrimes ctrl = sep->se_fd; 656121766Speter if (dolog && !ISWRAP(sep)) { 65771399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 65871399Sdwmalone socklen_t sl; 65971399Sdwmalone sl = sizeof peermax; 66048382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 66171399Sdwmalone &peermax, &sl)) { 66271399Sdwmalone sl = sizeof peermax; 66348382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 66448382Ssheldonh MSG_PEEK, 66556590Sshin (struct sockaddr *)&peermax, 66671399Sdwmalone &sl) >= 0) { 66756590Sshin getnameinfo((struct sockaddr *)&peermax, 66857383Sshin peer.sa_len, 66956590Sshin pname, sizeof(pname), 67056590Sshin NULL, 0, 67156590Sshin NI_NUMERICHOST| 67256590Sshin NI_WITHSCOPEID); 67356590Sshin } 67456590Sshin } else { 67556590Sshin getnameinfo((struct sockaddr *)&peermax, 67657383Sshin peer.sa_len, 67756590Sshin pname, sizeof(pname), 67856590Sshin NULL, 0, 67956590Sshin NI_NUMERICHOST| 68056590Sshin NI_WITHSCOPEID); 68148382Ssheldonh } 68271399Sdwmalone syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 68348382Ssheldonh } 68442122Sdes (void) sigblock(SIGBLOCK); 6851553Srgrimes pid = 0; 68647972Ssheldonh /* 68748958Ssheldonh * Fork for all external services, builtins which need to 68848958Ssheldonh * fork and anything we're wrapping (as wrapping might 68948958Ssheldonh * block or use hosts_options(5) twist). 69047972Ssheldonh */ 6911553Srgrimes if (dofork) { 6921553Srgrimes if (sep->se_count++ == 0) 69337856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 69464197Sdwmalone else if (toomany > 0 && sep->se_count >= toomany) { 6951553Srgrimes struct timeval now; 6961553Srgrimes 69737856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 6981553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 6991553Srgrimes CNT_INTVL) { 7001553Srgrimes sep->se_time = now; 7011553Srgrimes sep->se_count = 1; 7021553Srgrimes } else { 7031553Srgrimes syslog(LOG_ERR, 7041553Srgrimes "%s/%s server failing (looping), service terminated", 7051553Srgrimes sep->se_service, sep->se_proto); 70667415Sdwmalone if (sep->se_accept && 70767415Sdwmalone sep->se_socktype == SOCK_STREAM) 70867415Sdwmalone close(ctrl); 7091553Srgrimes close_sep(sep); 710101474Sume free_conn(conn); 71142122Sdes sigsetmask(0L); 7121553Srgrimes if (!timingout) { 7131553Srgrimes timingout = 1; 7141553Srgrimes alarm(RETRYTIME); 7151553Srgrimes } 7161553Srgrimes continue; 7171553Srgrimes } 7181553Srgrimes } 7191553Srgrimes pid = fork(); 7201553Srgrimes } 7211553Srgrimes if (pid < 0) { 7221553Srgrimes syslog(LOG_ERR, "fork: %m"); 72319618Sjulian if (sep->se_accept && 7241553Srgrimes sep->se_socktype == SOCK_STREAM) 7251553Srgrimes close(ctrl); 726101474Sume free_conn(conn); 72742122Sdes sigsetmask(0L); 7281553Srgrimes sleep(1); 7291553Srgrimes continue; 7301553Srgrimes } 731101474Sume if (pid) { 732101474Sume addchild_conn(conn, pid); 73319618Sjulian addchild(sep, pid); 734101474Sume } 73542122Sdes sigsetmask(0L); 7361553Srgrimes if (pid == 0) { 7371553Srgrimes if (dofork) { 73848962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73948962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 74048962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 74148962Ssheldonh /* SIGPIPE reset before exec */ 7421553Srgrimes } 74335829Sguido /* 74435829Sguido * Call tcpmux to find the real service to exec. 74535829Sguido */ 74635829Sguido if (sep->se_bi && 74778694Sdwmalone sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 74835829Sguido sep = tcpmux(ctrl); 74935829Sguido if (sep == NULL) { 75035829Sguido close(ctrl); 75135829Sguido _exit(0); 75235829Sguido } 75335829Sguido } 75448382Ssheldonh if (ISWRAP(sep)) { 75548698Ssheldonh inetd_setproctitle("wrapping", ctrl); 75647972Ssheldonh service = sep->se_server_name ? 75747972Ssheldonh sep->se_server_name : sep->se_service; 758127865Sdwmalone request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, 0); 75945089Smarkm fromhost(&req); 76047972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 76147972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 76245089Smarkm denied = !hosts_access(&req); 76345089Smarkm if (denied) { 76445089Smarkm syslog(deny_severity, 76596224Sume "refused connection from %.500s, service %s (%s%s)", 76696224Sume eval_client(&req), service, sep->se_proto, 767110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 76848382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 76948382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 77064059Sdwmalone if (dofork) { 77164059Sdwmalone sleep(1); 77248382Ssheldonh _exit(0); 77364059Sdwmalone } 77445089Smarkm } 775121766Speter if (dolog) { 77645089Smarkm syslog(allow_severity, 77796224Sume "connection from %.500s, service %s (%s%s)", 77896224Sume eval_client(&req), service, sep->se_proto, 779110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 78045089Smarkm } 78145089Smarkm } 78219617Sjulian if (sep->se_bi) { 7831553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 78419617Sjulian } else { 7851553Srgrimes if (debug) 78629602Scharnier warnx("%d execl %s", 78729602Scharnier getpid(), sep->se_server); 788111324Sdwmalone /* Clear close-on-exec. */ 789111324Sdwmalone if (fcntl(ctrl, F_SETFD, 0) < 0) { 790111324Sdwmalone syslog(LOG_ERR, 791111324Sdwmalone "%s/%s: fcntl (F_SETFD, 0): %m", 792111324Sdwmalone sep->se_service, sep->se_proto); 793111324Sdwmalone _exit(EX_OSERR); 794111324Sdwmalone } 795111324Sdwmalone if (ctrl != 0) { 796111324Sdwmalone dup2(ctrl, 0); 797111324Sdwmalone close(ctrl); 798111324Sdwmalone } 7991553Srgrimes dup2(0, 1); 8001553Srgrimes dup2(0, 2); 8011553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 8021553Srgrimes syslog(LOG_ERR, 80356482Scharnier "%s/%s: %s: no such user", 8041553Srgrimes sep->se_service, sep->se_proto, 8051553Srgrimes sep->se_user); 8061553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8071553Srgrimes recv(0, buf, sizeof (buf), 0); 80819617Sjulian _exit(EX_NOUSER); 8091553Srgrimes } 81030807Sache grp = NULL; 81130807Sache if ( sep->se_group != NULL 81230807Sache && (grp = getgrnam(sep->se_group)) == NULL 81330807Sache ) { 81430807Sache syslog(LOG_ERR, 81556482Scharnier "%s/%s: %s: no such group", 81630807Sache sep->se_service, sep->se_proto, 81730807Sache sep->se_group); 81830807Sache if (sep->se_socktype != SOCK_STREAM) 81930807Sache recv(0, buf, sizeof (buf), 0); 82030807Sache _exit(EX_NOUSER); 82130807Sache } 82230807Sache if (grp != NULL) 82330807Sache pwd->pw_gid = grp->gr_gid; 82421640Speter#ifdef LOGIN_CAP 82530792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 82630792Sache /* error syslogged by getclass */ 82730792Sache syslog(LOG_ERR, 82830792Sache "%s/%s: %s: login class error", 82937850Sache sep->se_service, sep->se_proto, 83037850Sache sep->se_class); 83130792Sache if (sep->se_socktype != SOCK_STREAM) 83230792Sache recv(0, buf, sizeof (buf), 0); 83330792Sache _exit(EX_NOUSER); 83430792Sache } 83521640Speter#endif 83612024Speter if (setsid() < 0) { 83712024Speter syslog(LOG_ERR, 83812024Speter "%s: can't setsid(): %m", 83912024Speter sep->se_service); 84019617Sjulian /* _exit(EX_OSERR); not fatal yet */ 84112024Speter } 84221640Speter#ifdef LOGIN_CAP 84321640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 844109349Srwatson LOGIN_SETALL & ~LOGIN_SETMAC) 845108951Srwatson != 0) { 84621640Speter syslog(LOG_ERR, 84721640Speter "%s: can't setusercontext(..%s..): %m", 84821640Speter sep->se_service, sep->se_user); 84921640Speter _exit(EX_OSERR); 85021640Speter } 851111323Sdwmalone login_close(lc); 85221640Speter#else 8531553Srgrimes if (pwd->pw_uid) { 85412024Speter if (setlogin(sep->se_user) < 0) { 85512024Speter syslog(LOG_ERR, 85612024Speter "%s: can't setlogin(%s): %m", 85712024Speter sep->se_service, sep->se_user); 85819617Sjulian /* _exit(EX_OSERR); not yet */ 85912024Speter } 8601553Srgrimes if (setgid(pwd->pw_gid) < 0) { 8611553Srgrimes syslog(LOG_ERR, 8628857Srgrimes "%s: can't set gid %d: %m", 8631553Srgrimes sep->se_service, pwd->pw_gid); 86419617Sjulian _exit(EX_OSERR); 8651553Srgrimes } 8661553Srgrimes (void) initgroups(pwd->pw_name, 8671553Srgrimes pwd->pw_gid); 8681553Srgrimes if (setuid(pwd->pw_uid) < 0) { 8691553Srgrimes syslog(LOG_ERR, 8708857Srgrimes "%s: can't set uid %d: %m", 8711553Srgrimes sep->se_service, pwd->pw_uid); 87219617Sjulian _exit(EX_OSERR); 8731553Srgrimes } 8741553Srgrimes } 87521640Speter#endif 87635948Sbde sigaction(SIGPIPE, &sapipe, 87735948Sbde (struct sigaction *)0); 8781553Srgrimes execv(sep->se_server, sep->se_argv); 87945089Smarkm syslog(LOG_ERR, 88045089Smarkm "cannot execute %s: %m", sep->se_server); 8811553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8821553Srgrimes recv(0, buf, sizeof (buf), 0); 8831553Srgrimes } 88447972Ssheldonh if (dofork) 88547972Ssheldonh _exit(0); 8861553Srgrimes } 88719618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 8881553Srgrimes close(ctrl); 8891553Srgrimes } 8901553Srgrimes } 8911553Srgrimes} 8921553Srgrimes 89319618Sjulian/* 89442122Sdes * Add a signal flag to the signal flag queue for later handling 89542122Sdes */ 89642122Sdes 89778694Sdwmalonevoid 89898558Sjmallettflag_signal(int c) 89942122Sdes{ 90069546Sdwmalone char ch = c; 90169546Sdwmalone 90269546Sdwmalone if (write(signalpipe[1], &ch, 1) != 1) { 90342250Sdes syslog(LOG_ERR, "write: %m"); 90448985Ssheldonh _exit(EX_OSERR); 90542250Sdes } 90642122Sdes} 90742122Sdes 90842122Sdes/* 90919618Sjulian * Record a new child pid for this service. If we've reached the 91019618Sjulian * limit on children, then stop accepting incoming requests. 91119618Sjulian */ 91219618Sjulian 9131553Srgrimesvoid 91419618Sjulianaddchild(struct servtab *sep, pid_t pid) 91519618Sjulian{ 91664197Sdwmalone if (sep->se_maxchild <= 0) 91764197Sdwmalone return; 91819618Sjulian#ifdef SANITY_CHECK 91919618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 92019618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 92119618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 92219618Sjulian exit(EX_SOFTWARE); 92319618Sjulian } 92419618Sjulian#endif 92519618Sjulian sep->se_pids[sep->se_numchild++] = pid; 92619618Sjulian if (sep->se_numchild == sep->se_maxchild) 92719618Sjulian disable(sep); 92819618Sjulian} 92919618Sjulian 93019618Sjulian/* 93119618Sjulian * Some child process has exited. See if it's on somebody's list. 93219618Sjulian */ 93319618Sjulian 93419618Sjulianvoid 93598561Sjmallettflag_reapchild(int signo __unused) 9361553Srgrimes{ 93742250Sdes flag_signal('C'); 93842122Sdes} 93942122Sdes 94042122Sdesvoid 94198558Sjmallettreapchild(void) 94242122Sdes{ 94319618Sjulian int k, status; 9441553Srgrimes pid_t pid; 9451553Srgrimes struct servtab *sep; 9461553Srgrimes 9471553Srgrimes for (;;) { 9481553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 9491553Srgrimes if (pid <= 0) 9501553Srgrimes break; 9511553Srgrimes if (debug) 952102939Sdwmalone warnx("%d reaped, %s %u", pid, 953102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 954102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 955102939Sdwmalone : WTERMSIG(status)); 95619618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 95719618Sjulian for (k = 0; k < sep->se_numchild; k++) 95819618Sjulian if (sep->se_pids[k] == pid) 95919618Sjulian break; 96019618Sjulian if (k == sep->se_numchild) 96119618Sjulian continue; 96219618Sjulian if (sep->se_numchild == sep->se_maxchild) 96319618Sjulian enable(sep); 96419618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 965102939Sdwmalone if (WIFSIGNALED(status) || WEXITSTATUS(status)) 96619618Sjulian syslog(LOG_WARNING, 967102939Sdwmalone "%s[%d]: exited, %s %u", 968102939Sdwmalone sep->se_server, pid, 969102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 970102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 971102939Sdwmalone : WTERMSIG(status)); 97219618Sjulian break; 97319618Sjulian } 974101474Sume reapchild_conn(pid); 9751553Srgrimes } 9761553Srgrimes} 9771553Srgrimes 9781553Srgrimesvoid 97998561Sjmallettflag_config(int signo __unused) 9801553Srgrimes{ 98142250Sdes flag_signal('H'); 98242122Sdes} 98342122Sdes 98478694Sdwmalonevoid 98598558Sjmallettconfig(void) 98642122Sdes{ 98719618Sjulian struct servtab *sep, *new, **sepp; 98842122Sdes long omask; 989100127Salfred int new_nomapped; 990111323Sdwmalone#ifdef LOGIN_CAP 991111323Sdwmalone login_cap_t *lc = NULL; 992111323Sdwmalone#endif 9931553Srgrimes 9941553Srgrimes if (!setconfig()) { 9951553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 9961553Srgrimes return; 9971553Srgrimes } 9981553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 9991553Srgrimes sep->se_checked = 0; 100019618Sjulian while ((new = getconfigent())) { 100130807Sache if (getpwnam(new->se_user) == NULL) { 10021553Srgrimes syslog(LOG_ERR, 100356482Scharnier "%s/%s: no such user '%s', service ignored", 100419618Sjulian new->se_service, new->se_proto, new->se_user); 10051553Srgrimes continue; 10061553Srgrimes } 100730807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 100830807Sache syslog(LOG_ERR, 100956482Scharnier "%s/%s: no such group '%s', service ignored", 101030807Sache new->se_service, new->se_proto, new->se_group); 101130807Sache continue; 101230807Sache } 101330792Sache#ifdef LOGIN_CAP 1014111323Sdwmalone if ((lc = login_getclass(new->se_class)) == NULL) { 101530792Sache /* error syslogged by getclass */ 101630792Sache syslog(LOG_ERR, 101737850Sache "%s/%s: %s: login class error, service ignored", 101837850Sache new->se_service, new->se_proto, new->se_class); 101930792Sache continue; 102030792Sache } 1021111323Sdwmalone login_close(lc); 102230792Sache#endif 1023100127Salfred new_nomapped = new->se_nomapped; 10241553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 102519618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 102656590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 1027100127Salfred sep->se_rpc == new->se_rpc && 102878356Sdwmalone sep->se_socktype == new->se_socktype && 102956590Sshin sep->se_family == new->se_family) 10301553Srgrimes break; 10311553Srgrimes if (sep != 0) { 10321553Srgrimes int i; 10331553Srgrimes 103498611Sjmallett#define SWAP(t,a, b) { t c = a; a = b; b = c; } 103542122Sdes omask = sigblock(SIGBLOCK); 103656590Sshin if (sep->se_nomapped != new->se_nomapped) { 1037100127Salfred /* for rpc keep old nommaped till unregister */ 1038100127Salfred if (!sep->se_rpc) 1039100127Salfred sep->se_nomapped = new->se_nomapped; 104056590Sshin sep->se_reset = 1; 104156590Sshin } 104219618Sjulian /* copy over outstanding child pids */ 104364197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 104419618Sjulian new->se_numchild = sep->se_numchild; 104519618Sjulian if (new->se_numchild > new->se_maxchild) 104619618Sjulian new->se_numchild = new->se_maxchild; 104719618Sjulian memcpy(new->se_pids, sep->se_pids, 104819618Sjulian new->se_numchild * sizeof(*new->se_pids)); 104919618Sjulian } 105098611Sjmallett SWAP(pid_t *, sep->se_pids, new->se_pids); 105119618Sjulian sep->se_maxchild = new->se_maxchild; 105219618Sjulian sep->se_numchild = new->se_numchild; 105330847Sdima sep->se_maxcpm = new->se_maxcpm; 1054101474Sume resize_conn(sep, new->se_maxperip); 1055101474Sume sep->se_maxperip = new->se_maxperip; 105666544Sdwmalone sep->se_bi = new->se_bi; 105719618Sjulian /* might need to turn on or off service now */ 105819618Sjulian if (sep->se_fd >= 0) { 105964197Sdwmalone if (sep->se_maxchild > 0 106019618Sjulian && sep->se_numchild == sep->se_maxchild) { 106119618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 106219618Sjulian disable(sep); 106319618Sjulian } else { 106419618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 106519618Sjulian enable(sep); 106619618Sjulian } 106719618Sjulian } 106819618Sjulian sep->se_accept = new->se_accept; 106998611Sjmallett SWAP(char *, sep->se_user, new->se_user); 107098611Sjmallett SWAP(char *, sep->se_group, new->se_group); 107130792Sache#ifdef LOGIN_CAP 107298611Sjmallett SWAP(char *, sep->se_class, new->se_class); 107330792Sache#endif 107498611Sjmallett SWAP(char *, sep->se_server, new->se_server); 107598611Sjmallett SWAP(char *, sep->se_server_name, new->se_server_name); 10761553Srgrimes for (i = 0; i < MAXARGV; i++) 107798611Sjmallett SWAP(char *, sep->se_argv[i], new->se_argv[i]); 107856590Sshin#ifdef IPSEC 107998611Sjmallett SWAP(char *, sep->se_policy, new->se_policy); 108056590Sshin ipsecsetup(sep); 108156590Sshin#endif 108242122Sdes sigsetmask(omask); 108319618Sjulian freeconfig(new); 10841553Srgrimes if (debug) 10851553Srgrimes print_service("REDO", sep); 10861553Srgrimes } else { 108719618Sjulian sep = enter(new); 10881553Srgrimes if (debug) 10891553Srgrimes print_service("ADD ", sep); 10901553Srgrimes } 10911553Srgrimes sep->se_checked = 1; 10921553Srgrimes if (ISMUX(sep)) { 10931553Srgrimes sep->se_fd = -1; 10941553Srgrimes continue; 10951553Srgrimes } 109656590Sshin switch (sep->se_family) { 109756590Sshin case AF_INET: 1098102938Sdwmalone if (!v4bind_ok) { 109956590Sshin sep->se_fd = -1; 110056590Sshin continue; 110156590Sshin } 110256590Sshin break; 110356590Sshin#ifdef INET6 110456590Sshin case AF_INET6: 1105102938Sdwmalone if (!v6bind_ok) { 110656590Sshin sep->se_fd = -1; 110756590Sshin continue; 110856590Sshin } 110956590Sshin break; 111056590Sshin#endif 111156590Sshin } 11122657Scsgr if (!sep->se_rpc) { 111378356Sdwmalone if (sep->se_family != AF_UNIX) { 111478356Sdwmalone sp = getservbyname(sep->se_service, sep->se_proto); 111578356Sdwmalone if (sp == 0) { 111678356Sdwmalone syslog(LOG_ERR, "%s/%s: unknown service", 111778356Sdwmalone sep->se_service, sep->se_proto); 111878356Sdwmalone sep->se_checked = 0; 111978356Sdwmalone continue; 112078356Sdwmalone } 11212657Scsgr } 112256590Sshin switch (sep->se_family) { 112356590Sshin case AF_INET: 112456590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 112556590Sshin sep->se_ctrladdr4.sin_port = 112656590Sshin sp->s_port; 112756590Sshin sep->se_reset = 1; 112856590Sshin } 112956590Sshin break; 113056590Sshin#ifdef INET6 113156590Sshin case AF_INET6: 113256590Sshin if (sp->s_port != 113356590Sshin sep->se_ctrladdr6.sin6_port) { 113456590Sshin sep->se_ctrladdr6.sin6_port = 113556590Sshin sp->s_port; 113656590Sshin sep->se_reset = 1; 113756590Sshin } 113856590Sshin break; 113956590Sshin#endif 11402657Scsgr } 114156590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 114256590Sshin close_sep(sep); 11432657Scsgr } else { 11442657Scsgr rpc = getrpcbyname(sep->se_service); 11452657Scsgr if (rpc == 0) { 114652219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 11472657Scsgr sep->se_service, sep->se_proto); 11482657Scsgr if (sep->se_fd != -1) 11492657Scsgr (void) close(sep->se_fd); 11502657Scsgr sep->se_fd = -1; 11512657Scsgr continue; 11522657Scsgr } 1153100127Salfred if (sep->se_reset != 0 || 1154100127Salfred rpc->r_number != sep->se_rpc_prog) { 11552657Scsgr if (sep->se_rpc_prog) 11562657Scsgr unregisterrpc(sep); 11572657Scsgr sep->se_rpc_prog = rpc->r_number; 11582657Scsgr if (sep->se_fd != -1) 11592657Scsgr (void) close(sep->se_fd); 11602657Scsgr sep->se_fd = -1; 11612657Scsgr } 1162100127Salfred sep->se_nomapped = new_nomapped; 11631553Srgrimes } 1164100127Salfred sep->se_reset = 0; 11651553Srgrimes if (sep->se_fd == -1) 11661553Srgrimes setup(sep); 11671553Srgrimes } 11681553Srgrimes endconfig(); 11691553Srgrimes /* 11701553Srgrimes * Purge anything not looked at above. 11711553Srgrimes */ 117242122Sdes omask = sigblock(SIGBLOCK); 11731553Srgrimes sepp = &servtab; 117419617Sjulian while ((sep = *sepp)) { 11751553Srgrimes if (sep->se_checked) { 11761553Srgrimes sepp = &sep->se_next; 11771553Srgrimes continue; 11781553Srgrimes } 11791553Srgrimes *sepp = sep->se_next; 11801553Srgrimes if (sep->se_fd >= 0) 11811553Srgrimes close_sep(sep); 11821553Srgrimes if (debug) 11831553Srgrimes print_service("FREE", sep); 11842657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 11852657Scsgr unregisterrpc(sep); 11861553Srgrimes freeconfig(sep); 118771399Sdwmalone free(sep); 11881553Srgrimes } 118942122Sdes (void) sigsetmask(omask); 11901553Srgrimes} 11911553Srgrimes 11921553Srgrimesvoid 119398558Sjmallettunregisterrpc(struct servtab *sep) 11942657Scsgr{ 119578694Sdwmalone u_int i; 11962657Scsgr struct servtab *sepp; 119742122Sdes long omask; 1198100127Salfred struct netconfig *netid4, *netid6; 11992657Scsgr 120042122Sdes omask = sigblock(SIGBLOCK); 1201100127Salfred netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1202100127Salfred netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1203100127Salfred if (sep->se_family == AF_INET) 1204100127Salfred netid6 = NULL; 1205100127Salfred else if (sep->se_nomapped) 1206100127Salfred netid4 = NULL; 1207100127Salfred /* 1208100127Salfred * Conflict if same prog and protocol - In that case one should look 1209100127Salfred * to versions, but it is not interesting: having separate servers for 1210100127Salfred * different versions does not work well. 1211100127Salfred * Therefore one do not unregister if there is a conflict. 1212100127Salfred * There is also transport conflict if destroying INET when INET46 1213100127Salfred * exists, or destroying INET46 when INET exists 1214100127Salfred */ 12152657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 12162657Scsgr if (sepp == sep) 12172657Scsgr continue; 1218100127Salfred if (sepp->se_checked == 0 || 12192657Scsgr !sepp->se_rpc || 1220100127Salfred strcmp(sep->se_proto, sepp->se_proto) != 0 || 12212657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 12222657Scsgr continue; 1223100127Salfred if (sepp->se_family == AF_INET) 1224100127Salfred netid4 = NULL; 1225100127Salfred if (sepp->se_family == AF_INET6) { 1226100127Salfred netid6 = NULL; 1227100127Salfred if (!sep->se_nomapped) 1228100127Salfred netid4 = NULL; 1229100127Salfred } 1230100127Salfred if (netid4 == NULL && netid6 == NULL) 1231100127Salfred return; 12322657Scsgr } 12332657Scsgr if (debug) 12342657Scsgr print_service("UNREG", sep); 1235100127Salfred for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1236100127Salfred if (netid4) 1237100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid4); 1238100127Salfred if (netid6) 1239100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid6); 1240100127Salfred } 12412657Scsgr if (sep->se_fd != -1) 12422657Scsgr (void) close(sep->se_fd); 12432657Scsgr sep->se_fd = -1; 124442122Sdes (void) sigsetmask(omask); 12452657Scsgr} 12462657Scsgr 12472657Scsgrvoid 124898561Sjmallettflag_retry(int signo __unused) 12491553Srgrimes{ 125042250Sdes flag_signal('A'); 125142122Sdes} 125242122Sdes 125342122Sdesvoid 125498558Sjmallettretry(void) 125542122Sdes{ 12561553Srgrimes struct servtab *sep; 12571553Srgrimes 12581553Srgrimes timingout = 0; 12591553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 126019617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 12611553Srgrimes setup(sep); 12621553Srgrimes} 12631553Srgrimes 12641553Srgrimesvoid 126598558Sjmallettsetup(struct servtab *sep) 12661553Srgrimes{ 12671553Srgrimes int on = 1; 12681553Srgrimes 126956590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 12701553Srgrimes if (debug) 127129602Scharnier warn("socket failed on %s/%s", 127229602Scharnier sep->se_service, sep->se_proto); 12731553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 12741553Srgrimes sep->se_service, sep->se_proto); 12751553Srgrimes return; 12761553Srgrimes } 1277111324Sdwmalone /* Set all listening sockets to close-on-exec. */ 1278111324Sdwmalone if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) { 1279111324Sdwmalone syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m", 1280111324Sdwmalone sep->se_service, sep->se_proto); 1281111324Sdwmalone close(sep->se_fd); 1282111324Sdwmalone return; 1283111324Sdwmalone } 12841553Srgrimes#define turnon(fd, opt) \ 12851553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 12861553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 12871553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 12881553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 12891553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 12901553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 129125253Swollman#ifdef SO_PRIVSTATE 129213956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 129313956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 129425253Swollman#endif 129556590Sshin /* tftpd opens a new connection then needs more infos */ 129656590Sshin if ((sep->se_family == AF_INET6) && 129756590Sshin (strcmp(sep->se_proto, "udp") == 0) && 129856590Sshin (sep->se_accept == 0) && 1299121559Sume (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 130056590Sshin (char *)&on, sizeof (on)) < 0)) 130156590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 130258935Sume if (sep->se_family == AF_INET6) { 130358935Sume int flag = sep->se_nomapped ? 1 : 0; 1304100505Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 130558935Sume (char *)&flag, sizeof (flag)) < 0) 1306100505Sume syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 130758935Sume } 13081553Srgrimes#undef turnon 130936042Sguido if (sep->se_type == TTCP_TYPE) 131036042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 131136042Sguido (char *)&on, sizeof (on)) < 0) 131236042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 131356590Sshin#ifdef IPV6_FAITH 131456590Sshin if (sep->se_type == FAITH_TYPE) { 131556590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 131656590Sshin sizeof(on)) < 0) { 131756590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 131856590Sshin } 131956590Sshin } 132056590Sshin#endif 132156590Sshin#ifdef IPSEC 132256590Sshin ipsecsetup(sep); 132356590Sshin#endif 132478356Sdwmalone if (sep->se_family == AF_UNIX) { 132578356Sdwmalone (void) unlink(sep->se_ctrladdr_un.sun_path); 132678356Sdwmalone umask(0777); /* Make socket with conservative permissions */ 132778356Sdwmalone } 13281553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 132956590Sshin sep->se_ctrladdr_size) < 0) { 13301553Srgrimes if (debug) 133129602Scharnier warn("bind failed on %s/%s", 133229602Scharnier sep->se_service, sep->se_proto); 13331553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 13341553Srgrimes sep->se_service, sep->se_proto); 13351553Srgrimes (void) close(sep->se_fd); 13361553Srgrimes sep->se_fd = -1; 13371553Srgrimes if (!timingout) { 13381553Srgrimes timingout = 1; 13391553Srgrimes alarm(RETRYTIME); 13401553Srgrimes } 134178356Sdwmalone if (sep->se_family == AF_UNIX) 134278356Sdwmalone umask(mask); 13431553Srgrimes return; 13441553Srgrimes } 134578356Sdwmalone if (sep->se_family == AF_UNIX) { 134678356Sdwmalone /* Ick - fch{own,mod} don't work on Unix domain sockets */ 134778356Sdwmalone if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 134878356Sdwmalone syslog(LOG_ERR, "chown socket: %m"); 134978356Sdwmalone if (chmod(sep->se_service, sep->se_sockmode) < 0) 135078356Sdwmalone syslog(LOG_ERR, "chmod socket: %m"); 135178356Sdwmalone umask(mask); 135278356Sdwmalone } 13532657Scsgr if (sep->se_rpc) { 135478694Sdwmalone u_int i; 135571399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 1356100127Salfred struct netconfig *netid, *netid2 = NULL; 1357100127Salfred struct sockaddr_in sock; 1358100127Salfred struct netbuf nbuf, nbuf2; 13592657Scsgr 13608857Srgrimes if (getsockname(sep->se_fd, 13612657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 13622657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 13632657Scsgr sep->se_service, sep->se_proto); 13642657Scsgr (void) close(sep->se_fd); 13652657Scsgr sep->se_fd = -1; 13668857Srgrimes return; 13672657Scsgr } 1368100127Salfred nbuf.buf = &sep->se_ctrladdr; 1369100127Salfred nbuf.len = sep->se_ctrladdr.sa_len; 1370100127Salfred if (sep->se_family == AF_INET) 1371100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1372100127Salfred else { 1373100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1374100127Salfred if (!sep->se_nomapped) { /* INET and INET6 */ 1375100127Salfred netid2 = netid==udp6conf? udpconf:tcpconf; 1376100127Salfred memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1377100127Salfred nbuf2.buf = &sock; 1378100127Salfred nbuf2.len = sock.sin_len = sizeof sock; 1379100127Salfred sock.sin_family = AF_INET; 1380100127Salfred sock.sin_port = sep->se_ctrladdr6.sin6_port; 1381100127Salfred } 1382100127Salfred } 13832657Scsgr if (debug) 13842657Scsgr print_service("REG ", sep); 13852657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1386100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid); 1387100127Salfred rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1388100127Salfred if (netid2) { 1389100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid2); 1390100127Salfred rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1391100127Salfred } 13922657Scsgr } 13932657Scsgr } 13941553Srgrimes if (sep->se_socktype == SOCK_STREAM) 139517197Sdg listen(sep->se_fd, 64); 139619618Sjulian enable(sep); 13971553Srgrimes if (debug) { 139829602Scharnier warnx("registered %s on %d", 13991553Srgrimes sep->se_server, sep->se_fd); 14001553Srgrimes } 14011553Srgrimes} 14021553Srgrimes 140356590Sshin#ifdef IPSEC 140456590Sshinvoid 140556590Sshinipsecsetup(sep) 140656590Sshin struct servtab *sep; 140756590Sshin{ 140856590Sshin char *buf; 140956590Sshin char *policy_in = NULL; 141056590Sshin char *policy_out = NULL; 141156590Sshin int level; 141256590Sshin int opt; 141356590Sshin 141456590Sshin switch (sep->se_family) { 141556590Sshin case AF_INET: 141656590Sshin level = IPPROTO_IP; 141756590Sshin opt = IP_IPSEC_POLICY; 141856590Sshin break; 141956590Sshin#ifdef INET6 142056590Sshin case AF_INET6: 142156590Sshin level = IPPROTO_IPV6; 142256590Sshin opt = IPV6_IPSEC_POLICY; 142356590Sshin break; 142456590Sshin#endif 142556590Sshin default: 142656590Sshin return; 142756590Sshin } 142856590Sshin 142956590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 143078694Sdwmalone static char def_in[] = "in entrust", def_out[] = "out entrust"; 143178694Sdwmalone policy_in = def_in; 143278694Sdwmalone policy_out = def_out; 143356590Sshin } else { 143456590Sshin if (!strncmp("in", sep->se_policy, 2)) 143556590Sshin policy_in = sep->se_policy; 143656590Sshin else if (!strncmp("out", sep->se_policy, 3)) 143756590Sshin policy_out = sep->se_policy; 143856590Sshin else { 143956590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 144056590Sshin sep->se_policy); 144156590Sshin return; 144256590Sshin } 144356590Sshin } 144456590Sshin 144556590Sshin if (policy_in != NULL) { 144656590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 144756590Sshin if (buf != NULL) { 144856590Sshin if (setsockopt(sep->se_fd, level, opt, 144956675Sshin buf, ipsec_get_policylen(buf)) < 0 && 145056759Sshin debug != 0) 145156759Sshin warnx("%s/%s: ipsec initialization failed; %s", 145256759Sshin sep->se_service, sep->se_proto, 145356759Sshin policy_in); 145456590Sshin free(buf); 145556590Sshin } else 145656590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 145756590Sshin policy_in); 145856590Sshin } 145956590Sshin if (policy_out != NULL) { 146056590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 146156590Sshin if (buf != NULL) { 146256590Sshin if (setsockopt(sep->se_fd, level, opt, 146356675Sshin buf, ipsec_get_policylen(buf)) < 0 && 146456759Sshin debug != 0) 146556759Sshin warnx("%s/%s: ipsec initialization failed; %s", 146656759Sshin sep->se_service, sep->se_proto, 146756759Sshin policy_out); 146856590Sshin free(buf); 146956590Sshin } else 147056590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 147156590Sshin policy_out); 147256590Sshin } 147356590Sshin} 147456590Sshin#endif 147556590Sshin 14761553Srgrimes/* 14771553Srgrimes * Finish with a service and its socket. 14781553Srgrimes */ 14791553Srgrimesvoid 148098558Sjmallettclose_sep(struct servtab *sep) 14811553Srgrimes{ 14821553Srgrimes if (sep->se_fd >= 0) { 148319618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 148419618Sjulian disable(sep); 14851553Srgrimes (void) close(sep->se_fd); 14861553Srgrimes sep->se_fd = -1; 14871553Srgrimes } 14881553Srgrimes sep->se_count = 0; 148919618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 14901553Srgrimes} 14911553Srgrimes 149248467Ssheldonhint 149398558Sjmallettmatchservent(const char *name1, const char *name2, const char *proto) 149448467Ssheldonh{ 149578356Sdwmalone char **alias, *p; 149648467Ssheldonh struct servent *se; 149748467Ssheldonh 149878356Sdwmalone if (strcmp(proto, "unix") == 0) { 149978356Sdwmalone if ((p = strrchr(name1, '/')) != NULL) 150078356Sdwmalone name1 = p + 1; 150178356Sdwmalone if ((p = strrchr(name2, '/')) != NULL) 150278356Sdwmalone name2 = p + 1; 150378356Sdwmalone } 150449026Sdes if (strcmp(name1, name2) == 0) 150549026Sdes return(1); 150648467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 150748467Ssheldonh if (strcmp(name2, se->s_name) == 0) 150848467Ssheldonh return(1); 150948467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 151048467Ssheldonh if (strcmp(name2, *alias) == 0) 151148467Ssheldonh return(1); 151248467Ssheldonh } 151348467Ssheldonh return(0); 151448467Ssheldonh} 151548467Ssheldonh 15161553Srgrimesstruct servtab * 151798558Sjmallettenter(struct servtab *cp) 15181553Srgrimes{ 15191553Srgrimes struct servtab *sep; 152042122Sdes long omask; 15211553Srgrimes 15221553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 15231553Srgrimes if (sep == (struct servtab *)0) { 152449102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 152519617Sjulian exit(EX_OSERR); 15261553Srgrimes } 15271553Srgrimes *sep = *cp; 15281553Srgrimes sep->se_fd = -1; 152942122Sdes omask = sigblock(SIGBLOCK); 15301553Srgrimes sep->se_next = servtab; 15311553Srgrimes servtab = sep; 153242122Sdes sigsetmask(omask); 15331553Srgrimes return (sep); 15341553Srgrimes} 15351553Srgrimes 153619618Sjulianvoid 153798558Sjmallettenable(struct servtab *sep) 153819618Sjulian{ 153919618Sjulian if (debug) 154029602Scharnier warnx( 154119618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 154219618Sjulian#ifdef SANITY_CHECK 154319618Sjulian if (sep->se_fd < 0) { 154419618Sjulian syslog(LOG_ERR, 154519618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 154619618Sjulian exit(EX_SOFTWARE); 154719618Sjulian } 154819618Sjulian if (ISMUX(sep)) { 154919618Sjulian syslog(LOG_ERR, 155019618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 155119618Sjulian exit(EX_SOFTWARE); 155219618Sjulian } 155319618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 155419618Sjulian syslog(LOG_ERR, 155519618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 155619618Sjulian exit(EX_SOFTWARE); 155719618Sjulian } 155848991Ssheldonh nsock++; 155919618Sjulian#endif 156019618Sjulian FD_SET(sep->se_fd, &allsock); 156119618Sjulian if (sep->se_fd > maxsock) 156219618Sjulian maxsock = sep->se_fd; 156319618Sjulian} 156419618Sjulian 156519618Sjulianvoid 156698558Sjmallettdisable(struct servtab *sep) 156719618Sjulian{ 156819618Sjulian if (debug) 156929602Scharnier warnx( 157019618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 157119618Sjulian#ifdef SANITY_CHECK 157219618Sjulian if (sep->se_fd < 0) { 157319618Sjulian syslog(LOG_ERR, 157419618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 157519618Sjulian exit(EX_SOFTWARE); 157619618Sjulian } 157719618Sjulian if (ISMUX(sep)) { 157819618Sjulian syslog(LOG_ERR, 157919618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 158019618Sjulian exit(EX_SOFTWARE); 158119618Sjulian } 158219618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 158319618Sjulian syslog(LOG_ERR, 158419618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 158519618Sjulian exit(EX_SOFTWARE); 158619618Sjulian } 158719618Sjulian if (nsock == 0) { 158819618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 158919618Sjulian exit(EX_SOFTWARE); 159019618Sjulian } 159148991Ssheldonh nsock--; 159219618Sjulian#endif 159319618Sjulian FD_CLR(sep->se_fd, &allsock); 159419618Sjulian if (sep->se_fd == maxsock) 159519618Sjulian maxsock--; 159619618Sjulian} 159719618Sjulian 15981553SrgrimesFILE *fconfig = NULL; 15991553Srgrimesstruct servtab serv; 16001553Srgrimeschar line[LINE_MAX]; 16011553Srgrimes 16021553Srgrimesint 160398558Sjmallettsetconfig(void) 16041553Srgrimes{ 16051553Srgrimes 16061553Srgrimes if (fconfig != NULL) { 16071553Srgrimes fseek(fconfig, 0L, SEEK_SET); 16081553Srgrimes return (1); 16091553Srgrimes } 16101553Srgrimes fconfig = fopen(CONFIG, "r"); 16111553Srgrimes return (fconfig != NULL); 16121553Srgrimes} 16131553Srgrimes 16141553Srgrimesvoid 161598558Sjmallettendconfig(void) 16161553Srgrimes{ 16171553Srgrimes if (fconfig) { 16181553Srgrimes (void) fclose(fconfig); 16191553Srgrimes fconfig = NULL; 16201553Srgrimes } 16211553Srgrimes} 16221553Srgrimes 16231553Srgrimesstruct servtab * 162498558Sjmallettgetconfigent(void) 16251553Srgrimes{ 16261553Srgrimes struct servtab *sep = &serv; 16271553Srgrimes int argc; 162819618Sjulian char *cp, *arg, *s; 16292657Scsgr char *versp; 16301553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 16311553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 163256590Sshin#ifdef IPSEC 1633102861Sdwmalone char *policy; 163456590Sshin#endif 1635102861Sdwmalone int v4bind; 163656590Sshin#ifdef INET6 1637102861Sdwmalone int v6bind; 163856590Sshin#endif 1639101474Sume int i; 16401553Srgrimes 1641102861Sdwmalone#ifdef IPSEC 1642102861Sdwmalone policy = NULL; 1643102861Sdwmalone#endif 16441553Srgrimesmore: 1645102861Sdwmalone v4bind = 0; 1646102861Sdwmalone#ifdef INET6 1647102861Sdwmalone v6bind = 0; 1648102861Sdwmalone#endif 164956590Sshin while ((cp = nextline(fconfig)) != NULL) { 165056590Sshin#ifdef IPSEC 165156590Sshin /* lines starting with #@ is not a comment, but the policy */ 165256590Sshin if (cp[0] == '#' && cp[1] == '@') { 165356590Sshin char *p; 165456590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 165556590Sshin ; 165656590Sshin if (*p == '\0') { 165756590Sshin if (policy) 165856590Sshin free(policy); 165956590Sshin policy = NULL; 166056590Sshin } else if (ipsec_get_policylen(p) >= 0) { 166156590Sshin if (policy) 166256590Sshin free(policy); 166356590Sshin policy = newstr(p); 166456590Sshin } else { 166556590Sshin syslog(LOG_ERR, 166656590Sshin "%s: invalid ipsec policy \"%s\"", 166756590Sshin CONFIG, p); 166856590Sshin exit(EX_CONFIG); 166956590Sshin } 167056590Sshin } 167156590Sshin#endif 167256590Sshin if (*cp == '#' || *cp == '\0') 167356590Sshin continue; 167456590Sshin break; 167556590Sshin } 16761553Srgrimes if (cp == NULL) 16771553Srgrimes return ((struct servtab *)0); 16781553Srgrimes /* 16791553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 16801553Srgrimes * for example) don't get initialized here. 16811553Srgrimes */ 168271399Sdwmalone memset(sep, 0, sizeof *sep); 16831553Srgrimes arg = skip(&cp); 16841553Srgrimes if (cp == NULL) { 16851553Srgrimes /* got an empty line containing just blanks/tabs. */ 16861553Srgrimes goto more; 16871553Srgrimes } 168878356Sdwmalone if (arg[0] == ':') { /* :user:group:perm: */ 168978356Sdwmalone char *user, *group, *perm; 169078356Sdwmalone struct passwd *pw; 169178356Sdwmalone struct group *gr; 169278356Sdwmalone user = arg+1; 169378356Sdwmalone if ((group = strchr(user, ':')) == NULL) { 169478356Sdwmalone syslog(LOG_ERR, "no group after user '%s'", user); 169578356Sdwmalone goto more; 169678356Sdwmalone } 169778356Sdwmalone *group++ = '\0'; 169878356Sdwmalone if ((perm = strchr(group, ':')) == NULL) { 169978356Sdwmalone syslog(LOG_ERR, "no mode after group '%s'", group); 170078356Sdwmalone goto more; 170178356Sdwmalone } 170278356Sdwmalone *perm++ = '\0'; 170378356Sdwmalone if ((pw = getpwnam(user)) == NULL) { 170478356Sdwmalone syslog(LOG_ERR, "no such user '%s'", user); 170578356Sdwmalone goto more; 170678356Sdwmalone } 170778356Sdwmalone sep->se_sockuid = pw->pw_uid; 170878356Sdwmalone if ((gr = getgrnam(group)) == NULL) { 170978356Sdwmalone syslog(LOG_ERR, "no such user '%s'", group); 171078356Sdwmalone goto more; 171178356Sdwmalone } 171278356Sdwmalone sep->se_sockgid = gr->gr_gid; 171378356Sdwmalone sep->se_sockmode = strtol(perm, &arg, 8); 171478356Sdwmalone if (*arg != ':') { 171578356Sdwmalone syslog(LOG_ERR, "bad mode '%s'", perm); 171678356Sdwmalone goto more; 171778356Sdwmalone } 171878356Sdwmalone *arg++ = '\0'; 171978356Sdwmalone } else { 172078356Sdwmalone sep->se_sockuid = euid; 172178356Sdwmalone sep->se_sockgid = egid; 172278356Sdwmalone sep->se_sockmode = 0200; 172378356Sdwmalone } 17241553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 17251553Srgrimes char *c = arg + MUX_LEN; 17261553Srgrimes if (*c == '+') { 17271553Srgrimes sep->se_type = MUXPLUS_TYPE; 17281553Srgrimes c++; 17291553Srgrimes } else 17301553Srgrimes sep->se_type = MUX_TYPE; 17311553Srgrimes sep->se_service = newstr(c); 17321553Srgrimes } else { 17331553Srgrimes sep->se_service = newstr(arg); 17341553Srgrimes sep->se_type = NORM_TYPE; 17351553Srgrimes } 17361553Srgrimes arg = sskip(&cp); 17371553Srgrimes if (strcmp(arg, "stream") == 0) 17381553Srgrimes sep->se_socktype = SOCK_STREAM; 17391553Srgrimes else if (strcmp(arg, "dgram") == 0) 17401553Srgrimes sep->se_socktype = SOCK_DGRAM; 17411553Srgrimes else if (strcmp(arg, "rdm") == 0) 17421553Srgrimes sep->se_socktype = SOCK_RDM; 17431553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 17441553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 17451553Srgrimes else if (strcmp(arg, "raw") == 0) 17461553Srgrimes sep->se_socktype = SOCK_RAW; 17471553Srgrimes else 17481553Srgrimes sep->se_socktype = -1; 174936042Sguido 175036042Sguido arg = sskip(&cp); 175156590Sshin if (strncmp(arg, "tcp", 3) == 0) { 175256590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 175356590Sshin if (arg != NULL) { 175456590Sshin if (strcmp(arg, "ttcp") == 0) 175556590Sshin sep->se_type = TTCP_TYPE; 175656590Sshin else if (strcmp(arg, "faith") == 0) 175756590Sshin sep->se_type = FAITH_TYPE; 175856590Sshin } 175977518Sume } else { 176077518Sume if (sep->se_type == NORM_TYPE && 176177518Sume strncmp(arg, "faith/", 6) == 0) { 176277518Sume arg += 6; 176377518Sume sep->se_type = FAITH_TYPE; 176477518Sume } 176536042Sguido sep->se_proto = newstr(arg); 176677518Sume } 17672657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 176819237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 176919237Sjoerg strlen(sep->se_proto) + 1 - 4); 17702657Scsgr sep->se_rpc = 1; 17712657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 17722657Scsgr sep->se_rpc_lowvers = 0; 177356590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 177456590Sshin sizeof(sep->se_ctrladdr4)); 17752657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 17762657Scsgr *versp++ = '\0'; 1777102859Sdwmalone switch (sscanf(versp, "%u-%u", 17782657Scsgr &sep->se_rpc_lowvers, 17792657Scsgr &sep->se_rpc_highvers)) { 17802657Scsgr case 2: 17812657Scsgr break; 17822657Scsgr case 1: 17832657Scsgr sep->se_rpc_highvers = 17842657Scsgr sep->se_rpc_lowvers; 17852657Scsgr break; 17862657Scsgr default: 17878857Srgrimes syslog(LOG_ERR, 178852219Scharnier "bad RPC version specifier; %s", 17892657Scsgr sep->se_service); 17902657Scsgr freeconfig(sep); 17912657Scsgr goto more; 17922657Scsgr } 17932657Scsgr } 17942657Scsgr else { 17952657Scsgr sep->se_rpc_lowvers = 17962657Scsgr sep->se_rpc_highvers = 1; 17972657Scsgr } 17982657Scsgr } 179956590Sshin sep->se_nomapped = 0; 180078356Sdwmalone if (strcmp(sep->se_proto, "unix") == 0) { 180178356Sdwmalone sep->se_family = AF_UNIX; 1802102937Sdwmalone } else { 1803102937Sdwmalone while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 180456590Sshin#ifdef INET6 1805102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1806102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1807102937Sdwmalone v6bind = 1; 1808102937Sdwmalone continue; 1809102937Sdwmalone } 1810102937Sdwmalone#endif 1811102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1812102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1813102937Sdwmalone v4bind = 1; 1814102937Sdwmalone continue; 1815102937Sdwmalone } 1816102937Sdwmalone /* illegal version num */ 1817102937Sdwmalone syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1818100127Salfred freeconfig(sep); 1819100127Salfred goto more; 1820100127Salfred } 1821102937Sdwmalone#ifdef INET6 1822102938Sdwmalone if (v6bind && !v6bind_ok) { 1823102937Sdwmalone syslog(LOG_INFO, "IPv6 bind is ignored for %s", 182456590Sshin sep->se_service); 1825102938Sdwmalone if (v4bind && v4bind_ok) 1826102937Sdwmalone v6bind = 0; 1827102937Sdwmalone else { 1828102937Sdwmalone freeconfig(sep); 1829102937Sdwmalone goto more; 1830102937Sdwmalone } 183156590Sshin } 1832102938Sdwmalone if (v6bind) { 1833102937Sdwmalone sep->se_family = AF_INET6; 1834102938Sdwmalone if (!v4bind || !v4bind_ok) 1835102937Sdwmalone sep->se_nomapped = 1; 1836102937Sdwmalone } else 1837102937Sdwmalone#endif 1838102937Sdwmalone { /* default to v4 bind if not v6 bind */ 1839102938Sdwmalone if (!v4bind_ok) { 1840102937Sdwmalone syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1841102937Sdwmalone sep->se_service); 1842102937Sdwmalone freeconfig(sep); 1843102937Sdwmalone goto more; 1844102937Sdwmalone } 1845102937Sdwmalone sep->se_family = AF_INET; 1846102937Sdwmalone } 184756590Sshin } 184856590Sshin /* init ctladdr */ 184956590Sshin switch(sep->se_family) { 185056590Sshin case AF_INET: 185156590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 185256590Sshin sizeof(sep->se_ctrladdr4)); 185356590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 185456590Sshin break; 185556590Sshin#ifdef INET6 185656590Sshin case AF_INET6: 185756590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 185856590Sshin sizeof(sep->se_ctrladdr6)); 185956590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 186056590Sshin break; 186156590Sshin#endif 186278356Sdwmalone case AF_UNIX: 186378356Sdwmalone if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 186478356Sdwmalone syslog(LOG_ERR, 186578356Sdwmalone "domain socket pathname too long for service %s", 186678356Sdwmalone sep->se_service); 186778356Sdwmalone goto more; 186878356Sdwmalone } 186978356Sdwmalone memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 187078356Sdwmalone sep->se_ctrladdr_un.sun_family = sep->se_family; 187178356Sdwmalone sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 187278356Sdwmalone strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 187378356Sdwmalone sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 187456590Sshin } 18751553Srgrimes arg = sskip(&cp); 187619618Sjulian if (!strncmp(arg, "wait", 4)) 187719618Sjulian sep->se_accept = 0; 187819618Sjulian else if (!strncmp(arg, "nowait", 6)) 187919618Sjulian sep->se_accept = 1; 188019618Sjulian else { 188119618Sjulian syslog(LOG_ERR, 188219618Sjulian "%s: bad wait/nowait for service %s", 188319618Sjulian CONFIG, sep->se_service); 188419618Sjulian goto more; 188519618Sjulian } 188648069Ssheldonh sep->se_maxchild = -1; 188748069Ssheldonh sep->se_maxcpm = -1; 1888101474Sume sep->se_maxperip = -1; 188919618Sjulian if ((s = strchr(arg, '/')) != NULL) { 189019618Sjulian char *eptr; 189119618Sjulian u_long val; 189219618Sjulian 189319618Sjulian val = strtoul(s + 1, &eptr, 10); 189430847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 189519618Sjulian syslog(LOG_ERR, 189619618Sjulian "%s: bad max-child for service %s", 189719618Sjulian CONFIG, sep->se_service); 189819618Sjulian goto more; 189919618Sjulian } 190048069Ssheldonh if (debug) 190148069Ssheldonh if (!sep->se_accept && val != 1) 190248069Ssheldonh warnx("maxchild=%lu for wait service %s" 190348069Ssheldonh " not recommended", val, sep->se_service); 190419618Sjulian sep->se_maxchild = val; 190530847Sdima if (*eptr == '/') 190630847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1907101474Sume if (*eptr == '/') 1908101474Sume sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 190930847Sdima /* 191030847Sdima * explicitly do not check for \0 for future expansion / 191130847Sdima * backwards compatibility 191230847Sdima */ 191319618Sjulian } 19141553Srgrimes if (ISMUX(sep)) { 19151553Srgrimes /* 191619618Sjulian * Silently enforce "nowait" mode for TCPMUX services 191719618Sjulian * since they don't have an assigned port to listen on. 19181553Srgrimes */ 191919618Sjulian sep->se_accept = 1; 19201553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 19218857Srgrimes syslog(LOG_ERR, 19221553Srgrimes "%s: bad protocol for tcpmux service %s", 19231553Srgrimes CONFIG, sep->se_service); 19241553Srgrimes goto more; 19251553Srgrimes } 19261553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 19278857Srgrimes syslog(LOG_ERR, 19281553Srgrimes "%s: bad socket type for tcpmux service %s", 19291553Srgrimes CONFIG, sep->se_service); 19301553Srgrimes goto more; 19311553Srgrimes } 19321553Srgrimes } 19331553Srgrimes sep->se_user = newstr(sskip(&cp)); 193430792Sache#ifdef LOGIN_CAP 193530792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 193630792Sache *s = '\0'; 193730792Sache sep->se_class = newstr(s + 1); 193830792Sache } else 193930792Sache sep->se_class = newstr(RESOURCE_RC); 194030792Sache#endif 194130807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 194230807Sache *s = '\0'; 194330807Sache sep->se_group = newstr(s + 1); 194430807Sache } else 194530807Sache sep->se_group = NULL; 19461553Srgrimes sep->se_server = newstr(sskip(&cp)); 194745588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 194845588Smarkm sep->se_server_name++; 19491553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 19501553Srgrimes struct biltin *bi; 19511553Srgrimes 19521553Srgrimes for (bi = biltins; bi->bi_service; bi++) 195349026Sdes if (bi->bi_socktype == sep->se_socktype && 195448467Ssheldonh matchservent(bi->bi_service, sep->se_service, 195548467Ssheldonh sep->se_proto)) 19561553Srgrimes break; 19571553Srgrimes if (bi->bi_service == 0) { 19581553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 19591553Srgrimes sep->se_service); 19601553Srgrimes goto more; 19611553Srgrimes } 196219618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 19631553Srgrimes sep->se_bi = bi; 19641553Srgrimes } else 19651553Srgrimes sep->se_bi = NULL; 1966101474Sume if (sep->se_maxperip < 0) 1967101474Sume sep->se_maxperip = maxperip; 196848069Ssheldonh if (sep->se_maxcpm < 0) 196948069Ssheldonh sep->se_maxcpm = maxcpm; 197045588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 197148069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 197219618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 197348069Ssheldonh else if (sep->se_accept) 197448069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 197519618Sjulian else 197648069Ssheldonh sep->se_maxchild = 1; 197745588Smarkm } 197864197Sdwmalone if (sep->se_maxchild > 0) { 197919618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 198019618Sjulian if (sep->se_pids == NULL) { 198149102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 198219618Sjulian exit(EX_OSERR); 198319618Sjulian } 198419618Sjulian } 19851553Srgrimes argc = 0; 19861553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 198719618Sjulian if (argc < MAXARGV) { 19881553Srgrimes sep->se_argv[argc++] = newstr(arg); 198919618Sjulian } else { 199019618Sjulian syslog(LOG_ERR, 199119618Sjulian "%s: too many arguments for service %s", 199219618Sjulian CONFIG, sep->se_service); 199319618Sjulian goto more; 199419618Sjulian } 19951553Srgrimes while (argc <= MAXARGV) 19961553Srgrimes sep->se_argv[argc++] = NULL; 1997101474Sume for (i = 0; i < PERIPSIZE; ++i) 1998101474Sume LIST_INIT(&sep->se_conn[i]); 199956590Sshin#ifdef IPSEC 200056590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 200156590Sshin#endif 20021553Srgrimes return (sep); 20031553Srgrimes} 20041553Srgrimes 20051553Srgrimesvoid 200698558Sjmallettfreeconfig(struct servtab *cp) 20071553Srgrimes{ 20081553Srgrimes int i; 20091553Srgrimes 20101553Srgrimes if (cp->se_service) 20111553Srgrimes free(cp->se_service); 20121553Srgrimes if (cp->se_proto) 20131553Srgrimes free(cp->se_proto); 20141553Srgrimes if (cp->se_user) 20151553Srgrimes free(cp->se_user); 201630807Sache if (cp->se_group) 201730807Sache free(cp->se_group); 201830792Sache#ifdef LOGIN_CAP 201930792Sache if (cp->se_class) 202030792Sache free(cp->se_class); 202130792Sache#endif 20221553Srgrimes if (cp->se_server) 20231553Srgrimes free(cp->se_server); 202419618Sjulian if (cp->se_pids) 202519618Sjulian free(cp->se_pids); 20261553Srgrimes for (i = 0; i < MAXARGV; i++) 20271553Srgrimes if (cp->se_argv[i]) 20281553Srgrimes free(cp->se_argv[i]); 2029101474Sume free_connlist(cp); 203056590Sshin#ifdef IPSEC 203156590Sshin if (cp->se_policy) 203256590Sshin free(cp->se_policy); 203356590Sshin#endif 20341553Srgrimes} 20351553Srgrimes 20361553Srgrimes 20371553Srgrimes/* 20381553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 20391553Srgrimes * configuration file and exit. 20401553Srgrimes */ 20411553Srgrimeschar * 204298558Sjmallettsskip(char **cpp) 20431553Srgrimes{ 20441553Srgrimes char *cp; 20451553Srgrimes 20461553Srgrimes cp = skip(cpp); 20471553Srgrimes if (cp == NULL) { 20481553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 204919617Sjulian exit(EX_DATAERR); 20501553Srgrimes } 20511553Srgrimes return (cp); 20521553Srgrimes} 20531553Srgrimes 20541553Srgrimeschar * 205598558Sjmallettskip(char **cpp) 20561553Srgrimes{ 20571553Srgrimes char *cp = *cpp; 20581553Srgrimes char *start; 205911933Sadam char quote = '\0'; 20601553Srgrimes 20611553Srgrimesagain: 20621553Srgrimes while (*cp == ' ' || *cp == '\t') 20631553Srgrimes cp++; 20641553Srgrimes if (*cp == '\0') { 20651553Srgrimes int c; 20661553Srgrimes 20671553Srgrimes c = getc(fconfig); 20681553Srgrimes (void) ungetc(c, fconfig); 20691553Srgrimes if (c == ' ' || c == '\t') 207019617Sjulian if ((cp = nextline(fconfig))) 20711553Srgrimes goto again; 20721553Srgrimes *cpp = (char *)0; 20731553Srgrimes return ((char *)0); 20741553Srgrimes } 207511933Sadam if (*cp == '"' || *cp == '\'') 207611933Sadam quote = *cp++; 20771553Srgrimes start = cp; 207811933Sadam if (quote) 207911933Sadam while (*cp && *cp != quote) 208011933Sadam cp++; 208111933Sadam else 208211933Sadam while (*cp && *cp != ' ' && *cp != '\t') 208311933Sadam cp++; 20841553Srgrimes if (*cp != '\0') 20851553Srgrimes *cp++ = '\0'; 20861553Srgrimes *cpp = cp; 20871553Srgrimes return (start); 20881553Srgrimes} 20891553Srgrimes 20901553Srgrimeschar * 209198558Sjmallettnextline(FILE *fd) 20921553Srgrimes{ 20931553Srgrimes char *cp; 20941553Srgrimes 20951553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 20961553Srgrimes return ((char *)0); 20971553Srgrimes cp = strchr(line, '\n'); 20981553Srgrimes if (cp) 20991553Srgrimes *cp = '\0'; 21001553Srgrimes return (line); 21011553Srgrimes} 21021553Srgrimes 21031553Srgrimeschar * 210498558Sjmallettnewstr(const char *cp) 21051553Srgrimes{ 210678694Sdwmalone char *cr; 210778694Sdwmalone 210878694Sdwmalone if ((cr = strdup(cp != NULL ? cp : ""))) 210978694Sdwmalone return (cr); 21101553Srgrimes syslog(LOG_ERR, "strdup: %m"); 211119617Sjulian exit(EX_OSERR); 21121553Srgrimes} 21131553Srgrimes 21141553Srgrimesvoid 211598558Sjmallettinetd_setproctitle(const char *a, int s) 21161553Srgrimes{ 211771399Sdwmalone socklen_t size; 211856590Sshin struct sockaddr_storage ss; 211956590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 21201553Srgrimes 212156590Sshin size = sizeof(ss); 212256590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 212356590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 212456590Sshin NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 212556590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 212656590Sshin } else 212713142Speter (void) sprintf(buf, "%s", a); 212813142Speter setproctitle("%s", buf); 212913142Speter} 213013142Speter 213178694Sdwmaloneint 213298558Sjmallettcheck_loop(const struct sockaddr *sa, const struct servtab *sep) 21335182Swollman{ 21345182Swollman struct servtab *se2; 213556590Sshin char pname[INET6_ADDRSTRLEN]; 21365182Swollman 21375182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 21385182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 21395182Swollman continue; 21405182Swollman 214156590Sshin switch (se2->se_family) { 214256590Sshin case AF_INET: 214378694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214456590Sshin se2->se_ctrladdr4.sin_port) 214556590Sshin goto isloop; 214656590Sshin continue; 214756590Sshin#ifdef INET6 214856590Sshin case AF_INET6: 214978694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 215056590Sshin se2->se_ctrladdr4.sin_port) 215156590Sshin goto isloop; 215256590Sshin continue; 215356590Sshin#endif 215456590Sshin default: 215556590Sshin continue; 21565182Swollman } 215756590Sshin isloop: 215856590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 215956590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 216056590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 216156590Sshin sep->se_service, sep->se_proto, 216256590Sshin se2->se_service, se2->se_proto, 216356590Sshin pname); 216456590Sshin return 1; 21655182Swollman } 21665182Swollman return 0; 21675182Swollman} 21685182Swollman 21691553Srgrimes/* 21701553Srgrimes * print_service: 21711553Srgrimes * Dump relevant information to stderr 21721553Srgrimes */ 21731553Srgrimesvoid 217498558Sjmallettprint_service(const char *action, const struct servtab *sep) 21751553Srgrimes{ 217619617Sjulian fprintf(stderr, 217756590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 217830792Sache#ifdef LOGIN_CAP 217956590Sshin "class=%s" 218030792Sache#endif 218156590Sshin " builtin=%p server=%s" 218256590Sshin#ifdef IPSEC 218356590Sshin " policy=\"%s\"" 218456590Sshin#endif 218556590Sshin "\n", 218619617Sjulian action, sep->se_service, sep->se_proto, 218730807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 218830792Sache#ifdef LOGIN_CAP 218930792Sache sep->se_class, 219030792Sache#endif 219156590Sshin (void *) sep->se_bi, sep->se_server 219256590Sshin#ifdef IPSEC 219356590Sshin , (sep->se_policy ? sep->se_policy : "") 219456590Sshin#endif 219556590Sshin ); 21961553Srgrimes} 21971553Srgrimes 219830847Sdima#define CPMHSIZE 256 219930847Sdima#define CPMHMASK (CPMHSIZE-1) 220030847Sdima#define CHTGRAN 10 220130847Sdima#define CHTSIZE 6 220230847Sdima 220330847Sdimatypedef struct CTime { 220430847Sdima unsigned long ct_Ticks; 220530847Sdima int ct_Count; 220630847Sdima} CTime; 220730847Sdima 220830847Sdimatypedef struct CHash { 220956590Sshin union { 221056590Sshin struct in_addr c4_Addr; 221156590Sshin struct in6_addr c6_Addr; 221256590Sshin } cu_Addr; 221356590Sshin#define ch_Addr4 cu_Addr.c4_Addr 221456590Sshin#define ch_Addr6 cu_Addr.c6_Addr 221556590Sshin int ch_Family; 221630847Sdima time_t ch_LTime; 221730847Sdima char *ch_Service; 221830847Sdima CTime ch_Times[CHTSIZE]; 221930847Sdima} CHash; 222030847Sdima 222130847SdimaCHash CHashAry[CPMHSIZE]; 222230847Sdima 222330847Sdimaint 222498558Sjmallettcpmip(const struct servtab *sep, int ctrl) 222530847Sdima{ 222656590Sshin struct sockaddr_storage rss; 222771399Sdwmalone socklen_t rssLen = sizeof(rss); 222830847Sdima int r = 0; 222930847Sdima 223030847Sdima /* 223130847Sdima * If getpeername() fails, just let it through (if logging is 223230847Sdima * enabled the condition is caught elsewhere) 223330847Sdima */ 223430847Sdima 223530847Sdima if (sep->se_maxcpm > 0 && 223656590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 223730847Sdima time_t t = time(NULL); 223830847Sdima int hv = 0xABC3D20F; 223930847Sdima int i; 224030847Sdima int cnt = 0; 224130847Sdima CHash *chBest = NULL; 224230847Sdima unsigned int ticks = t / CHTGRAN; 224378694Sdwmalone struct sockaddr_in *sin4; 224456590Sshin#ifdef INET6 224556590Sshin struct sockaddr_in6 *sin6; 224656590Sshin#endif 224730847Sdima 224878694Sdwmalone sin4 = (struct sockaddr_in *)&rss; 224956590Sshin#ifdef INET6 225056590Sshin sin6 = (struct sockaddr_in6 *)&rss; 225156590Sshin#endif 225230847Sdima { 225330847Sdima char *p; 225478694Sdwmalone int addrlen; 225530847Sdima 225656590Sshin switch (rss.ss_family) { 225756590Sshin case AF_INET: 225878694Sdwmalone p = (char *)&sin4->sin_addr; 225956590Sshin addrlen = sizeof(struct in_addr); 226056590Sshin break; 226156590Sshin#ifdef INET6 226256590Sshin case AF_INET6: 226356590Sshin p = (char *)&sin6->sin6_addr; 226456590Sshin addrlen = sizeof(struct in6_addr); 226556590Sshin break; 226656590Sshin#endif 226756590Sshin default: 226856590Sshin /* should not happen */ 226956590Sshin return -1; 227056590Sshin } 227156590Sshin 227256590Sshin for (i = 0; i < addrlen; ++i, ++p) { 227330847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 227430847Sdima } 227530847Sdima hv = (hv ^ (hv >> 16)); 227630847Sdima } 227730847Sdima for (i = 0; i < 5; ++i) { 227830847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 227930847Sdima 228056590Sshin if (rss.ss_family == AF_INET && 228156590Sshin ch->ch_Family == AF_INET && 228278694Sdwmalone sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 228330847Sdima ch->ch_Service && strcmp(sep->se_service, 228430847Sdima ch->ch_Service) == 0) { 228530847Sdima chBest = ch; 228630847Sdima break; 228730847Sdima } 228856590Sshin#ifdef INET6 228956590Sshin if (rss.ss_family == AF_INET6 && 229056590Sshin ch->ch_Family == AF_INET6 && 229156590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 229256590Sshin &ch->ch_Addr6) != 0 && 229356590Sshin ch->ch_Service && strcmp(sep->se_service, 229456590Sshin ch->ch_Service) == 0) { 229556590Sshin chBest = ch; 229656590Sshin break; 229756590Sshin } 229856590Sshin#endif 229930847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 230030847Sdima ch->ch_LTime < chBest->ch_LTime) { 230130847Sdima chBest = ch; 230230847Sdima } 230330847Sdima } 230456590Sshin if ((rss.ss_family == AF_INET && 230556590Sshin (chBest->ch_Family != AF_INET || 230678694Sdwmalone sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 230730847Sdima chBest->ch_Service == NULL || 230830847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 230978694Sdwmalone chBest->ch_Family = sin4->sin_family; 231078694Sdwmalone chBest->ch_Addr4 = sin4->sin_addr; 231130847Sdima if (chBest->ch_Service) 231230847Sdima free(chBest->ch_Service); 231330847Sdima chBest->ch_Service = strdup(sep->se_service); 231430847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 231530847Sdima } 231656590Sshin#ifdef INET6 231756590Sshin if ((rss.ss_family == AF_INET6 && 231856590Sshin (chBest->ch_Family != AF_INET6 || 231956590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 232056590Sshin &chBest->ch_Addr6) == 0)) || 232156590Sshin chBest->ch_Service == NULL || 232256590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 232356590Sshin chBest->ch_Family = sin6->sin6_family; 232456590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 232556590Sshin if (chBest->ch_Service) 232656590Sshin free(chBest->ch_Service); 232756590Sshin chBest->ch_Service = strdup(sep->se_service); 232856590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 232956590Sshin } 233056590Sshin#endif 233130847Sdima chBest->ch_LTime = t; 233230847Sdima { 233330847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 233430847Sdima if (ct->ct_Ticks != ticks) { 233530847Sdima ct->ct_Ticks = ticks; 233630847Sdima ct->ct_Count = 0; 233730847Sdima } 233830847Sdima ++ct->ct_Count; 233930847Sdima } 234030847Sdima for (i = 0; i < CHTSIZE; ++i) { 234130847Sdima CTime *ct = &chBest->ch_Times[i]; 234230847Sdima if (ct->ct_Ticks <= ticks && 234330847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 234430847Sdima cnt += ct->ct_Count; 234530847Sdima } 234630847Sdima } 2347117644Sdwmalone if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 234856590Sshin char pname[INET6_ADDRSTRLEN]; 234956590Sshin 235056590Sshin getnameinfo((struct sockaddr *)&rss, 235156590Sshin ((struct sockaddr *)&rss)->sa_len, 235256590Sshin pname, sizeof(pname), NULL, 0, 235356590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 235430847Sdima r = -1; 235530847Sdima syslog(LOG_ERR, 235633794Spst "%s from %s exceeded counts/min (limit %d/min)", 235756590Sshin sep->se_service, pname, 235833794Spst sep->se_maxcpm); 235930847Sdima } 236030847Sdima } 236130847Sdima return(r); 236230847Sdima} 2363101474Sume 2364101474Sumestatic struct conninfo * 2365101474Sumesearch_conn(struct servtab *sep, int ctrl) 2366101474Sume{ 2367101474Sume struct sockaddr_storage ss; 2368101474Sume socklen_t sslen = sizeof(ss); 2369101474Sume struct conninfo *conn; 2370101474Sume int hv; 2371101474Sume char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2372101474Sume 2373101474Sume if (sep->se_maxperip <= 0) 2374101474Sume return NULL; 2375101474Sume 2376101474Sume /* 2377101474Sume * If getpeername() fails, just let it through (if logging is 2378101474Sume * enabled the condition is caught elsewhere) 2379101474Sume */ 2380101474Sume if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2381101474Sume return NULL; 2382101474Sume 2383101474Sume switch (ss.ss_family) { 2384101474Sume case AF_INET: 2385101474Sume hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2386101474Sume sizeof(struct in_addr)); 2387101474Sume break; 2388101474Sume#ifdef INET6 2389101474Sume case AF_INET6: 2390101474Sume hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2391101474Sume sizeof(struct in6_addr)); 2392101474Sume break; 2393101474Sume#endif 2394101474Sume default: 2395101474Sume /* 2396101474Sume * Since we only support AF_INET and AF_INET6, just 2397101474Sume * let other than AF_INET and AF_INET6 through. 2398101474Sume */ 2399101474Sume return NULL; 2400101474Sume } 2401101474Sume 2402101474Sume if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2403101474Sume NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0) 2404101474Sume return NULL; 2405101474Sume 2406101474Sume LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2407101474Sume if (getnameinfo((struct sockaddr *)&conn->co_addr, 2408101474Sume conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2409101474Sume NI_NUMERICHOST | NI_WITHSCOPEID) == 0 && 2410101474Sume strcmp(pname, pname2) == 0) 2411101474Sume break; 2412101474Sume } 2413101474Sume 2414101474Sume if (conn == NULL) { 2415101474Sume if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2416101474Sume syslog(LOG_ERR, "malloc: %m"); 2417101474Sume exit(EX_OSERR); 2418101474Sume } 2419101474Sume conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2420101474Sume if (conn->co_proc == NULL) { 2421101474Sume syslog(LOG_ERR, "malloc: %m"); 2422101474Sume exit(EX_OSERR); 2423101474Sume } 2424101474Sume memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2425101474Sume conn->co_numchild = 0; 2426101474Sume LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2427101474Sume } 2428101474Sume 2429101474Sume /* 2430101474Sume * Since a child process is not invoked yet, we cannot 2431101474Sume * determine a pid of a child. So, co_proc and co_numchild 2432101474Sume * should be filled leter. 2433101474Sume */ 2434101474Sume 2435101474Sume return conn; 2436101474Sume} 2437101474Sume 2438101474Sumestatic int 2439101474Sumeroom_conn(struct servtab *sep, struct conninfo *conn) 2440101474Sume{ 2441101474Sume char pname[NI_MAXHOST]; 2442101474Sume 2443101474Sume if (conn->co_numchild >= sep->se_maxperip) { 2444101474Sume getnameinfo((struct sockaddr *)&conn->co_addr, 2445101474Sume conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2446101474Sume NI_NUMERICHOST | NI_WITHSCOPEID); 2447101474Sume syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2448101474Sume sep->se_service, pname, sep->se_maxperip); 2449101474Sume return 0; 2450101474Sume } 2451101474Sume return 1; 2452101474Sume} 2453101474Sume 2454101474Sumestatic void 2455101474Sumeaddchild_conn(struct conninfo *conn, pid_t pid) 2456101474Sume{ 2457101474Sume struct procinfo *proc; 2458101474Sume 2459101474Sume if (conn == NULL) 2460101474Sume return; 2461101474Sume 2462101474Sume if ((proc = search_proc(pid, 1)) != NULL) { 2463101474Sume if (proc->pr_conn != NULL) { 2464101474Sume syslog(LOG_ERR, 2465101474Sume "addchild_conn: child already on process list"); 2466101474Sume exit(EX_OSERR); 2467101474Sume } 2468101474Sume proc->pr_conn = conn; 2469101474Sume } 2470101474Sume 2471101474Sume conn->co_proc[conn->co_numchild++] = proc; 2472101474Sume} 2473101474Sume 2474101474Sumestatic void 2475101474Sumereapchild_conn(pid_t pid) 2476101474Sume{ 2477101474Sume struct procinfo *proc; 2478101474Sume struct conninfo *conn; 2479101474Sume int i; 2480101474Sume 2481101474Sume if ((proc = search_proc(pid, 0)) == NULL) 2482101474Sume return; 2483101474Sume if ((conn = proc->pr_conn) == NULL) 2484101474Sume return; 2485101474Sume for (i = 0; i < conn->co_numchild; ++i) 2486101474Sume if (conn->co_proc[i] == proc) { 2487101474Sume conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2488101474Sume break; 2489101474Sume } 2490101474Sume free_proc(proc); 2491101474Sume free_conn(conn); 2492101474Sume} 2493101474Sume 2494101474Sumestatic void 2495102859Sdwmaloneresize_conn(struct servtab *sep, int maxpip) 2496101474Sume{ 2497101474Sume struct conninfo *conn; 2498101474Sume int i, j; 2499101474Sume 2500101474Sume if (sep->se_maxperip <= 0) 2501101474Sume return; 2502102859Sdwmalone if (maxpip <= 0) { 2503101474Sume free_connlist(sep); 2504101474Sume return; 2505101474Sume } 2506101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2507101474Sume LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2508102859Sdwmalone for (j = maxpip; j < conn->co_numchild; ++j) 2509101474Sume free_proc(conn->co_proc[j]); 2510101474Sume conn->co_proc = realloc(conn->co_proc, 2511102859Sdwmalone maxpip * sizeof(*conn->co_proc)); 2512101474Sume if (conn->co_proc == NULL) { 2513101474Sume syslog(LOG_ERR, "realloc: %m"); 2514101474Sume exit(EX_OSERR); 2515101474Sume } 2516102859Sdwmalone if (conn->co_numchild > maxpip) 2517102859Sdwmalone conn->co_numchild = maxpip; 2518101474Sume } 2519101474Sume } 2520101474Sume} 2521101474Sume 2522101474Sumestatic void 2523101474Sumefree_connlist(struct servtab *sep) 2524101474Sume{ 2525101474Sume struct conninfo *conn; 2526101474Sume int i, j; 2527101474Sume 2528101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2529101474Sume while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2530101474Sume for (j = 0; j < conn->co_numchild; ++j) 2531101474Sume free_proc(conn->co_proc[j]); 2532101474Sume conn->co_numchild = 0; 2533101474Sume free_conn(conn); 2534101474Sume } 2535101474Sume } 2536101474Sume} 2537101474Sume 2538101474Sumestatic void 2539101474Sumefree_conn(struct conninfo *conn) 2540101474Sume{ 2541101474Sume if (conn == NULL) 2542101474Sume return; 2543101474Sume if (conn->co_numchild <= 0) { 2544101474Sume LIST_REMOVE(conn, co_link); 2545101474Sume free(conn->co_proc); 2546101474Sume free(conn); 2547101474Sume } 2548101474Sume} 2549101474Sume 2550101474Sumestatic struct procinfo * 2551101474Sumesearch_proc(pid_t pid, int add) 2552101474Sume{ 2553101474Sume struct procinfo *proc; 2554101474Sume int hv; 2555101474Sume 2556101474Sume hv = hashval((char *)&pid, sizeof(pid)); 2557101474Sume LIST_FOREACH(proc, &proctable[hv], pr_link) { 2558101474Sume if (proc->pr_pid == pid) 2559101474Sume break; 2560101474Sume } 2561101474Sume if (proc == NULL && add) { 2562101474Sume if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2563101474Sume syslog(LOG_ERR, "malloc: %m"); 2564101474Sume exit(EX_OSERR); 2565101474Sume } 2566101474Sume proc->pr_pid = pid; 2567101474Sume proc->pr_conn = NULL; 2568101474Sume LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2569101474Sume } 2570101474Sume return proc; 2571101474Sume} 2572101474Sume 2573101474Sumestatic void 2574101474Sumefree_proc(struct procinfo *proc) 2575101474Sume{ 2576101474Sume if (proc == NULL) 2577101474Sume return; 2578101474Sume LIST_REMOVE(proc, pr_link); 2579101474Sume free(proc); 2580101474Sume} 2581101474Sume 2582101474Sumestatic int 2583101474Sumehashval(char *p, int len) 2584101474Sume{ 2585101474Sume int i, hv = 0xABC3D20F; 2586101474Sume 2587101474Sume for (i = 0; i < len; ++i, ++p) 2588101474Sume hv = (hv << 5) ^ (hv >> 23) ^ *p; 2589101474Sume hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2590101474Sume return hv; 2591101474Sume} 2592