inetd.c revision 121559
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 121559 2003-10-26 06:11:31Z ume $"); 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; 2552659Scsgrint log = 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': 3622659Scsgr log = 1; 3632659Scsgr break; 36433794Spst case 'R': 36533794Spst getvalue(optarg, &toomany, 36633794Spst "-R %s: bad value for service invocation rate"); 3671553Srgrimes break; 36833794Spst case 'c': 36933794Spst getvalue(optarg, &maxchild, 37033794Spst "-c %s: bad value for maximum children"); 37133794Spst break; 37233794Spst case 'C': 37333794Spst getvalue(optarg, &maxcpm, 37433794Spst "-C %s: bad value for maximum children/minute"); 37533794Spst break; 37617482Sjulian case 'a': 37756590Sshin hostname = optarg; 37817482Sjulian break; 37917482Sjulian case 'p': 38017482Sjulian pid_file = optarg; 38117482Sjulian break; 382101474Sume case 's': 383101474Sume getvalue(optarg, &maxperip, 384101474Sume "-s %s: bad value for maximum children per source address"); 385101474Sume break; 38648279Ssheldonh case 'w': 38748697Ssheldonh wrap_ex++; 38848279Ssheldonh break; 38948697Ssheldonh case 'W': 39048697Ssheldonh wrap_bi++; 39148697Ssheldonh break; 3921553Srgrimes case '?': 3931553Srgrimes default: 3941553Srgrimes syslog(LOG_ERR, 39548697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 39633794Spst " [-c maximum] [-C rate]" 39717482Sjulian " [-p pidfile] [conf-file]"); 39819617Sjulian exit(EX_USAGE); 3991553Srgrimes } 40056590Sshin /* 40156590Sshin * Initialize Bind Addrs. 40256590Sshin * When hostname is NULL, wild card bind addrs are obtained from 40356590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 40456590Sshin * hostname or servname is non NULL. 40556590Sshin * So when hostname is NULL, set dummy value to servname. 40656590Sshin */ 40756590Sshin servname = (hostname == NULL) ? "discard" /* dummy */ : NULL; 40856590Sshin 40956590Sshin bzero(&hints, sizeof(struct addrinfo)); 41056590Sshin hints.ai_flags = AI_PASSIVE; 41156590Sshin hints.ai_family = AF_UNSPEC; 41256590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 41356590Sshin if (error != 0) { 41456590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 41556590Sshin if (error == EAI_SYSTEM) 41656590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 41756590Sshin exit(EX_USAGE); 41856590Sshin } 41956590Sshin do { 42056590Sshin if (res->ai_addr == NULL) { 42156590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 42256590Sshin exit(EX_USAGE); 42356590Sshin } 42456590Sshin switch (res->ai_addr->sa_family) { 42556590Sshin case AF_INET: 426102938Sdwmalone if (v4bind_ok) 42756590Sshin continue; 42856590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 42956590Sshin /* init port num in case servname is dummy */ 43056590Sshin bind_sa4->sin_port = 0; 431102938Sdwmalone v4bind_ok = 1; 43256590Sshin continue; 43356590Sshin#ifdef INET6 43456590Sshin case AF_INET6: 435102938Sdwmalone if (v6bind_ok) 43656590Sshin continue; 43756590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 43856590Sshin /* init port num in case servname is dummy */ 43956590Sshin bind_sa6->sin6_port = 0; 440102938Sdwmalone v6bind_ok = 1; 44156590Sshin continue; 44256590Sshin#endif 44356590Sshin } 444102938Sdwmalone if (v4bind_ok 44556590Sshin#ifdef INET6 446102938Sdwmalone && v6bind_ok 44756590Sshin#endif 44856590Sshin ) 44956590Sshin break; 45056590Sshin } while ((res = res->ai_next) != NULL); 451102938Sdwmalone if (!v4bind_ok 45256590Sshin#ifdef INET6 453102938Sdwmalone && !v6bind_ok 45456590Sshin#endif 45556590Sshin ) { 45656590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 45756590Sshin exit(EX_USAGE); 45856590Sshin } 45956590Sshin 46078356Sdwmalone euid = geteuid(); 46178356Sdwmalone egid = getegid(); 46278356Sdwmalone umask(mask = umask(0777)); 46378356Sdwmalone 4641553Srgrimes argc -= optind; 4651553Srgrimes argv += optind; 4661553Srgrimes 4671553Srgrimes if (argc > 0) 4681553Srgrimes CONFIG = argv[0]; 4691553Srgrimes if (debug == 0) { 47011447Swollman FILE *fp; 47112024Speter if (daemon(0, 0) < 0) { 47212024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 47312024Speter } 47497293Sjwd /* From now on we don't want syslog messages going to stderr. */ 47597293Sjwd closelog(); 47697293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 47712024Speter /* 47812024Speter * In case somebody has started inetd manually, we need to 47912024Speter * clear the logname, so that old servers run as root do not 48012024Speter * get the user's logname.. 48112024Speter */ 48212024Speter if (setlogin("") < 0) { 48312024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 48412024Speter /* no big deal if it fails.. */ 48512024Speter } 48611447Swollman pid = getpid(); 48717482Sjulian fp = fopen(pid_file, "w"); 48811447Swollman if (fp) { 48911447Swollman fprintf(fp, "%ld\n", (long)pid); 49011447Swollman fclose(fp); 49111447Swollman } else { 49217482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 49311447Swollman } 4941553Srgrimes } 495100127Salfred 496101474Sume for (i = 0; i < PERIPSIZE; ++i) 497101474Sume LIST_INIT(&proctable[i]); 498101474Sume 499102938Sdwmalone if (v4bind_ok) { 500100127Salfred udpconf = getnetconfigent("udp"); 501100127Salfred tcpconf = getnetconfigent("tcp"); 502100127Salfred if (udpconf == NULL || tcpconf == NULL) { 503102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 504100127Salfred exit(EX_USAGE); 505100127Salfred } 506100127Salfred } 507100127Salfred#ifdef INET6 508102938Sdwmalone if (v6bind_ok) { 509100127Salfred udp6conf = getnetconfigent("udp6"); 510100127Salfred tcp6conf = getnetconfigent("tcp6"); 511100127Salfred if (udp6conf == NULL || tcp6conf == NULL) { 512102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 513100127Salfred exit(EX_USAGE); 514100127Salfred } 515100127Salfred } 516100127Salfred#endif 517100127Salfred 51835948Sbde sa.sa_flags = 0; 51935948Sbde sigemptyset(&sa.sa_mask); 52035948Sbde sigaddset(&sa.sa_mask, SIGALRM); 52135948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 52235948Sbde sigaddset(&sa.sa_mask, SIGHUP); 52342122Sdes sa.sa_handler = flag_retry; 52448962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 52542122Sdes config(); 52642122Sdes sa.sa_handler = flag_config; 52748962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 52842122Sdes sa.sa_handler = flag_reapchild; 52948962Ssheldonh sigaction(SIGCHLD, &sa, &sachld); 53035848Sguido sa.sa_handler = SIG_IGN; 53135948Sbde sigaction(SIGPIPE, &sa, &sapipe); 5321553Srgrimes 5331553Srgrimes { 5341553Srgrimes /* space for daemons to overwrite environment for ps */ 5351553Srgrimes#define DUMMYSIZE 100 5361553Srgrimes char dummy[DUMMYSIZE]; 5371553Srgrimes 53819298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 5391553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 5401553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 5411553Srgrimes } 5421553Srgrimes 54342250Sdes if (pipe(signalpipe) != 0) { 54452219Scharnier syslog(LOG_ERR, "pipe: %m"); 54542250Sdes exit(EX_OSERR); 54642122Sdes } 547111324Sdwmalone if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 || 548111324Sdwmalone fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) { 549111324Sdwmalone syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m"); 550111324Sdwmalone exit(EX_OSERR); 551111324Sdwmalone } 55242122Sdes FD_SET(signalpipe[0], &allsock); 55348991Ssheldonh#ifdef SANITY_CHECK 55447015Sdes nsock++; 55548991Ssheldonh#endif 55648989Ssheldonh if (signalpipe[0] > maxsock) 55748989Ssheldonh maxsock = signalpipe[0]; 55848989Ssheldonh if (signalpipe[1] > maxsock) 55948989Ssheldonh maxsock = signalpipe[1]; 56041685Sdillon 5611553Srgrimes for (;;) { 5621553Srgrimes int n, ctrl; 5631553Srgrimes fd_set readable; 5641553Srgrimes 56548991Ssheldonh#ifdef SANITY_CHECK 5661553Srgrimes if (nsock == 0) { 56747015Sdes syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 56847015Sdes exit(EX_SOFTWARE); 5691553Srgrimes } 57048991Ssheldonh#endif 5711553Srgrimes readable = allsock; 57242122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 57342122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 57442122Sdes if (n < 0 && errno != EINTR) { 5751553Srgrimes syslog(LOG_WARNING, "select: %m"); 57628907Simp sleep(1); 57728907Simp } 5781553Srgrimes continue; 5791553Srgrimes } 58042122Sdes /* handle any queued signal flags */ 58142250Sdes if (FD_ISSET(signalpipe[0], &readable)) { 58271399Sdwmalone int nsig; 58371399Sdwmalone if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 58442122Sdes syslog(LOG_ERR, "ioctl: %m"); 58542122Sdes exit(EX_OSERR); 58642122Sdes } 58771399Sdwmalone while (--nsig >= 0) { 58842250Sdes char c; 58942250Sdes if (read(signalpipe[0], &c, 1) != 1) { 59042250Sdes syslog(LOG_ERR, "read: %m"); 59142250Sdes exit(EX_OSERR); 59242250Sdes } 59342250Sdes if (debug) 59456482Scharnier warnx("handling signal flag %c", c); 59542250Sdes switch(c) { 59642250Sdes case 'A': /* sigalrm */ 59742250Sdes retry(); 59842250Sdes break; 59942250Sdes case 'C': /* sigchld */ 60042250Sdes reapchild(); 60142250Sdes break; 60242250Sdes case 'H': /* sighup */ 60342250Sdes config(); 60442250Sdes break; 60542250Sdes } 60642250Sdes } 60742122Sdes } 6081553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 6091553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 6101553Srgrimes n--; 6111553Srgrimes if (debug) 61229602Scharnier warnx("someone wants %s", sep->se_service); 613101474Sume dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 614101474Sume conn = NULL; 61519618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 61653256Speter i = 1; 61753256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 61853256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 6191553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62071399Sdwmalone (socklen_t *)0); 6211553Srgrimes if (debug) 62229602Scharnier warnx("accept, ctrl %d", ctrl); 6231553Srgrimes if (ctrl < 0) { 6241553Srgrimes if (errno != EINTR) 6251553Srgrimes syslog(LOG_WARNING, 6261553Srgrimes "accept (for %s): %m", 62737844Sphk sep->se_service); 62837816Sphk if (sep->se_accept && 62937816Sphk sep->se_socktype == SOCK_STREAM) 63037816Sphk close(ctrl); 6311553Srgrimes continue; 6321553Srgrimes } 63353256Speter i = 0; 63453256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 63553256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 63653256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 63753256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 63830847Sdima if (cpmip(sep, ctrl) < 0) { 63930847Sdima close(ctrl); 64030847Sdima continue; 64130847Sdima } 642101474Sume if (dofork && 643101474Sume (conn = search_conn(sep, ctrl)) != NULL && 644101474Sume !room_conn(sep, conn)) { 645101474Sume close(ctrl); 646101474Sume continue; 647101474Sume } 6481553Srgrimes } else 6491553Srgrimes ctrl = sep->se_fd; 65048382Ssheldonh if (log && !ISWRAP(sep)) { 65171399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 65271399Sdwmalone socklen_t sl; 65371399Sdwmalone sl = sizeof peermax; 65448382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 65571399Sdwmalone &peermax, &sl)) { 65671399Sdwmalone sl = sizeof peermax; 65748382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 65848382Ssheldonh MSG_PEEK, 65956590Sshin (struct sockaddr *)&peermax, 66071399Sdwmalone &sl) >= 0) { 66156590Sshin getnameinfo((struct sockaddr *)&peermax, 66257383Sshin peer.sa_len, 66356590Sshin pname, sizeof(pname), 66456590Sshin NULL, 0, 66556590Sshin NI_NUMERICHOST| 66656590Sshin NI_WITHSCOPEID); 66756590Sshin } 66856590Sshin } else { 66956590Sshin getnameinfo((struct sockaddr *)&peermax, 67057383Sshin peer.sa_len, 67156590Sshin pname, sizeof(pname), 67256590Sshin NULL, 0, 67356590Sshin NI_NUMERICHOST| 67456590Sshin NI_WITHSCOPEID); 67548382Ssheldonh } 67671399Sdwmalone syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 67748382Ssheldonh } 67842122Sdes (void) sigblock(SIGBLOCK); 6791553Srgrimes pid = 0; 68047972Ssheldonh /* 68148958Ssheldonh * Fork for all external services, builtins which need to 68248958Ssheldonh * fork and anything we're wrapping (as wrapping might 68348958Ssheldonh * block or use hosts_options(5) twist). 68447972Ssheldonh */ 6851553Srgrimes if (dofork) { 6861553Srgrimes if (sep->se_count++ == 0) 68737856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 68864197Sdwmalone else if (toomany > 0 && sep->se_count >= toomany) { 6891553Srgrimes struct timeval now; 6901553Srgrimes 69137856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 6921553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 6931553Srgrimes CNT_INTVL) { 6941553Srgrimes sep->se_time = now; 6951553Srgrimes sep->se_count = 1; 6961553Srgrimes } else { 6971553Srgrimes syslog(LOG_ERR, 6981553Srgrimes "%s/%s server failing (looping), service terminated", 6991553Srgrimes sep->se_service, sep->se_proto); 70067415Sdwmalone if (sep->se_accept && 70167415Sdwmalone sep->se_socktype == SOCK_STREAM) 70267415Sdwmalone close(ctrl); 7031553Srgrimes close_sep(sep); 704101474Sume free_conn(conn); 70542122Sdes sigsetmask(0L); 7061553Srgrimes if (!timingout) { 7071553Srgrimes timingout = 1; 7081553Srgrimes alarm(RETRYTIME); 7091553Srgrimes } 7101553Srgrimes continue; 7111553Srgrimes } 7121553Srgrimes } 7131553Srgrimes pid = fork(); 7141553Srgrimes } 7151553Srgrimes if (pid < 0) { 7161553Srgrimes syslog(LOG_ERR, "fork: %m"); 71719618Sjulian if (sep->se_accept && 7181553Srgrimes sep->se_socktype == SOCK_STREAM) 7191553Srgrimes close(ctrl); 720101474Sume free_conn(conn); 72142122Sdes sigsetmask(0L); 7221553Srgrimes sleep(1); 7231553Srgrimes continue; 7241553Srgrimes } 725101474Sume if (pid) { 726101474Sume addchild_conn(conn, pid); 72719618Sjulian addchild(sep, pid); 728101474Sume } 72942122Sdes sigsetmask(0L); 7301553Srgrimes if (pid == 0) { 7311553Srgrimes if (dofork) { 73248962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73348962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 73448962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 73548962Ssheldonh /* SIGPIPE reset before exec */ 7361553Srgrimes } 73735829Sguido /* 73835829Sguido * Call tcpmux to find the real service to exec. 73935829Sguido */ 74035829Sguido if (sep->se_bi && 74178694Sdwmalone sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 74235829Sguido sep = tcpmux(ctrl); 74335829Sguido if (sep == NULL) { 74435829Sguido close(ctrl); 74535829Sguido _exit(0); 74635829Sguido } 74735829Sguido } 74848382Ssheldonh if (ISWRAP(sep)) { 74948698Ssheldonh inetd_setproctitle("wrapping", ctrl); 75047972Ssheldonh service = sep->se_server_name ? 75147972Ssheldonh sep->se_server_name : sep->se_service; 75247972Ssheldonh request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL); 75345089Smarkm fromhost(&req); 75447972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 75547972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 75645089Smarkm denied = !hosts_access(&req); 75745089Smarkm if (denied) { 75845089Smarkm syslog(deny_severity, 75996224Sume "refused connection from %.500s, service %s (%s%s)", 76096224Sume eval_client(&req), service, sep->se_proto, 761110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 76248382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 76348382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 76464059Sdwmalone if (dofork) { 76564059Sdwmalone sleep(1); 76648382Ssheldonh _exit(0); 76764059Sdwmalone } 76845089Smarkm } 76945089Smarkm if (log) { 77045089Smarkm syslog(allow_severity, 77196224Sume "connection from %.500s, service %s (%s%s)", 77296224Sume eval_client(&req), service, sep->se_proto, 773110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 77445089Smarkm } 77545089Smarkm } 77619617Sjulian if (sep->se_bi) { 7771553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 77819617Sjulian } else { 7791553Srgrimes if (debug) 78029602Scharnier warnx("%d execl %s", 78129602Scharnier getpid(), sep->se_server); 782111324Sdwmalone /* Clear close-on-exec. */ 783111324Sdwmalone if (fcntl(ctrl, F_SETFD, 0) < 0) { 784111324Sdwmalone syslog(LOG_ERR, 785111324Sdwmalone "%s/%s: fcntl (F_SETFD, 0): %m", 786111324Sdwmalone sep->se_service, sep->se_proto); 787111324Sdwmalone _exit(EX_OSERR); 788111324Sdwmalone } 789111324Sdwmalone if (ctrl != 0) { 790111324Sdwmalone dup2(ctrl, 0); 791111324Sdwmalone close(ctrl); 792111324Sdwmalone } 7931553Srgrimes dup2(0, 1); 7941553Srgrimes dup2(0, 2); 7951553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 7961553Srgrimes syslog(LOG_ERR, 79756482Scharnier "%s/%s: %s: no such user", 7981553Srgrimes sep->se_service, sep->se_proto, 7991553Srgrimes sep->se_user); 8001553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8011553Srgrimes recv(0, buf, sizeof (buf), 0); 80219617Sjulian _exit(EX_NOUSER); 8031553Srgrimes } 80430807Sache grp = NULL; 80530807Sache if ( sep->se_group != NULL 80630807Sache && (grp = getgrnam(sep->se_group)) == NULL 80730807Sache ) { 80830807Sache syslog(LOG_ERR, 80956482Scharnier "%s/%s: %s: no such group", 81030807Sache sep->se_service, sep->se_proto, 81130807Sache sep->se_group); 81230807Sache if (sep->se_socktype != SOCK_STREAM) 81330807Sache recv(0, buf, sizeof (buf), 0); 81430807Sache _exit(EX_NOUSER); 81530807Sache } 81630807Sache if (grp != NULL) 81730807Sache pwd->pw_gid = grp->gr_gid; 81821640Speter#ifdef LOGIN_CAP 81930792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 82030792Sache /* error syslogged by getclass */ 82130792Sache syslog(LOG_ERR, 82230792Sache "%s/%s: %s: login class error", 82337850Sache sep->se_service, sep->se_proto, 82437850Sache sep->se_class); 82530792Sache if (sep->se_socktype != SOCK_STREAM) 82630792Sache recv(0, buf, sizeof (buf), 0); 82730792Sache _exit(EX_NOUSER); 82830792Sache } 82921640Speter#endif 83012024Speter if (setsid() < 0) { 83112024Speter syslog(LOG_ERR, 83212024Speter "%s: can't setsid(): %m", 83312024Speter sep->se_service); 83419617Sjulian /* _exit(EX_OSERR); not fatal yet */ 83512024Speter } 83621640Speter#ifdef LOGIN_CAP 83721640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 838109349Srwatson LOGIN_SETALL & ~LOGIN_SETMAC) 839108951Srwatson != 0) { 84021640Speter syslog(LOG_ERR, 84121640Speter "%s: can't setusercontext(..%s..): %m", 84221640Speter sep->se_service, sep->se_user); 84321640Speter _exit(EX_OSERR); 84421640Speter } 845111323Sdwmalone login_close(lc); 84621640Speter#else 8471553Srgrimes if (pwd->pw_uid) { 84812024Speter if (setlogin(sep->se_user) < 0) { 84912024Speter syslog(LOG_ERR, 85012024Speter "%s: can't setlogin(%s): %m", 85112024Speter sep->se_service, sep->se_user); 85219617Sjulian /* _exit(EX_OSERR); not yet */ 85312024Speter } 8541553Srgrimes if (setgid(pwd->pw_gid) < 0) { 8551553Srgrimes syslog(LOG_ERR, 8568857Srgrimes "%s: can't set gid %d: %m", 8571553Srgrimes sep->se_service, pwd->pw_gid); 85819617Sjulian _exit(EX_OSERR); 8591553Srgrimes } 8601553Srgrimes (void) initgroups(pwd->pw_name, 8611553Srgrimes pwd->pw_gid); 8621553Srgrimes if (setuid(pwd->pw_uid) < 0) { 8631553Srgrimes syslog(LOG_ERR, 8648857Srgrimes "%s: can't set uid %d: %m", 8651553Srgrimes sep->se_service, pwd->pw_uid); 86619617Sjulian _exit(EX_OSERR); 8671553Srgrimes } 8681553Srgrimes } 86921640Speter#endif 87035948Sbde sigaction(SIGPIPE, &sapipe, 87135948Sbde (struct sigaction *)0); 8721553Srgrimes execv(sep->se_server, sep->se_argv); 87345089Smarkm syslog(LOG_ERR, 87445089Smarkm "cannot execute %s: %m", sep->se_server); 8751553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8761553Srgrimes recv(0, buf, sizeof (buf), 0); 8771553Srgrimes } 87847972Ssheldonh if (dofork) 87947972Ssheldonh _exit(0); 8801553Srgrimes } 88119618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 8821553Srgrimes close(ctrl); 8831553Srgrimes } 8841553Srgrimes } 8851553Srgrimes} 8861553Srgrimes 88719618Sjulian/* 88842122Sdes * Add a signal flag to the signal flag queue for later handling 88942122Sdes */ 89042122Sdes 89178694Sdwmalonevoid 89298558Sjmallettflag_signal(int c) 89342122Sdes{ 89469546Sdwmalone char ch = c; 89569546Sdwmalone 89669546Sdwmalone if (write(signalpipe[1], &ch, 1) != 1) { 89742250Sdes syslog(LOG_ERR, "write: %m"); 89848985Ssheldonh _exit(EX_OSERR); 89942250Sdes } 90042122Sdes} 90142122Sdes 90242122Sdes/* 90319618Sjulian * Record a new child pid for this service. If we've reached the 90419618Sjulian * limit on children, then stop accepting incoming requests. 90519618Sjulian */ 90619618Sjulian 9071553Srgrimesvoid 90819618Sjulianaddchild(struct servtab *sep, pid_t pid) 90919618Sjulian{ 91064197Sdwmalone if (sep->se_maxchild <= 0) 91164197Sdwmalone return; 91219618Sjulian#ifdef SANITY_CHECK 91319618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 91419618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 91519618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 91619618Sjulian exit(EX_SOFTWARE); 91719618Sjulian } 91819618Sjulian#endif 91919618Sjulian sep->se_pids[sep->se_numchild++] = pid; 92019618Sjulian if (sep->se_numchild == sep->se_maxchild) 92119618Sjulian disable(sep); 92219618Sjulian} 92319618Sjulian 92419618Sjulian/* 92519618Sjulian * Some child process has exited. See if it's on somebody's list. 92619618Sjulian */ 92719618Sjulian 92819618Sjulianvoid 92998561Sjmallettflag_reapchild(int signo __unused) 9301553Srgrimes{ 93142250Sdes flag_signal('C'); 93242122Sdes} 93342122Sdes 93442122Sdesvoid 93598558Sjmallettreapchild(void) 93642122Sdes{ 93719618Sjulian int k, status; 9381553Srgrimes pid_t pid; 9391553Srgrimes struct servtab *sep; 9401553Srgrimes 9411553Srgrimes for (;;) { 9421553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 9431553Srgrimes if (pid <= 0) 9441553Srgrimes break; 9451553Srgrimes if (debug) 946102939Sdwmalone warnx("%d reaped, %s %u", pid, 947102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 948102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 949102939Sdwmalone : WTERMSIG(status)); 95019618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 95119618Sjulian for (k = 0; k < sep->se_numchild; k++) 95219618Sjulian if (sep->se_pids[k] == pid) 95319618Sjulian break; 95419618Sjulian if (k == sep->se_numchild) 95519618Sjulian continue; 95619618Sjulian if (sep->se_numchild == sep->se_maxchild) 95719618Sjulian enable(sep); 95819618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 959102939Sdwmalone if (WIFSIGNALED(status) || WEXITSTATUS(status)) 96019618Sjulian syslog(LOG_WARNING, 961102939Sdwmalone "%s[%d]: exited, %s %u", 962102939Sdwmalone sep->se_server, pid, 963102939Sdwmalone WIFEXITED(status) ? "status" : "signal", 964102939Sdwmalone WIFEXITED(status) ? WEXITSTATUS(status) 965102939Sdwmalone : WTERMSIG(status)); 96619618Sjulian break; 96719618Sjulian } 968101474Sume reapchild_conn(pid); 9691553Srgrimes } 9701553Srgrimes} 9711553Srgrimes 9721553Srgrimesvoid 97398561Sjmallettflag_config(int signo __unused) 9741553Srgrimes{ 97542250Sdes flag_signal('H'); 97642122Sdes} 97742122Sdes 97878694Sdwmalonevoid 97998558Sjmallettconfig(void) 98042122Sdes{ 98119618Sjulian struct servtab *sep, *new, **sepp; 98242122Sdes long omask; 983100127Salfred int new_nomapped; 984111323Sdwmalone#ifdef LOGIN_CAP 985111323Sdwmalone login_cap_t *lc = NULL; 986111323Sdwmalone#endif 9871553Srgrimes 9881553Srgrimes if (!setconfig()) { 9891553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 9901553Srgrimes return; 9911553Srgrimes } 9921553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 9931553Srgrimes sep->se_checked = 0; 99419618Sjulian while ((new = getconfigent())) { 99530807Sache if (getpwnam(new->se_user) == NULL) { 9961553Srgrimes syslog(LOG_ERR, 99756482Scharnier "%s/%s: no such user '%s', service ignored", 99819618Sjulian new->se_service, new->se_proto, new->se_user); 9991553Srgrimes continue; 10001553Srgrimes } 100130807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 100230807Sache syslog(LOG_ERR, 100356482Scharnier "%s/%s: no such group '%s', service ignored", 100430807Sache new->se_service, new->se_proto, new->se_group); 100530807Sache continue; 100630807Sache } 100730792Sache#ifdef LOGIN_CAP 1008111323Sdwmalone if ((lc = login_getclass(new->se_class)) == NULL) { 100930792Sache /* error syslogged by getclass */ 101030792Sache syslog(LOG_ERR, 101137850Sache "%s/%s: %s: login class error, service ignored", 101237850Sache new->se_service, new->se_proto, new->se_class); 101330792Sache continue; 101430792Sache } 1015111323Sdwmalone login_close(lc); 101630792Sache#endif 1017100127Salfred new_nomapped = new->se_nomapped; 10181553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 101919618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 102056590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 1021100127Salfred sep->se_rpc == new->se_rpc && 102278356Sdwmalone sep->se_socktype == new->se_socktype && 102356590Sshin sep->se_family == new->se_family) 10241553Srgrimes break; 10251553Srgrimes if (sep != 0) { 10261553Srgrimes int i; 10271553Srgrimes 102898611Sjmallett#define SWAP(t,a, b) { t c = a; a = b; b = c; } 102942122Sdes omask = sigblock(SIGBLOCK); 103056590Sshin if (sep->se_nomapped != new->se_nomapped) { 1031100127Salfred /* for rpc keep old nommaped till unregister */ 1032100127Salfred if (!sep->se_rpc) 1033100127Salfred sep->se_nomapped = new->se_nomapped; 103456590Sshin sep->se_reset = 1; 103556590Sshin } 103619618Sjulian /* copy over outstanding child pids */ 103764197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 103819618Sjulian new->se_numchild = sep->se_numchild; 103919618Sjulian if (new->se_numchild > new->se_maxchild) 104019618Sjulian new->se_numchild = new->se_maxchild; 104119618Sjulian memcpy(new->se_pids, sep->se_pids, 104219618Sjulian new->se_numchild * sizeof(*new->se_pids)); 104319618Sjulian } 104498611Sjmallett SWAP(pid_t *, sep->se_pids, new->se_pids); 104519618Sjulian sep->se_maxchild = new->se_maxchild; 104619618Sjulian sep->se_numchild = new->se_numchild; 104730847Sdima sep->se_maxcpm = new->se_maxcpm; 1048101474Sume resize_conn(sep, new->se_maxperip); 1049101474Sume sep->se_maxperip = new->se_maxperip; 105066544Sdwmalone sep->se_bi = new->se_bi; 105119618Sjulian /* might need to turn on or off service now */ 105219618Sjulian if (sep->se_fd >= 0) { 105364197Sdwmalone if (sep->se_maxchild > 0 105419618Sjulian && sep->se_numchild == sep->se_maxchild) { 105519618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 105619618Sjulian disable(sep); 105719618Sjulian } else { 105819618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 105919618Sjulian enable(sep); 106019618Sjulian } 106119618Sjulian } 106219618Sjulian sep->se_accept = new->se_accept; 106398611Sjmallett SWAP(char *, sep->se_user, new->se_user); 106498611Sjmallett SWAP(char *, sep->se_group, new->se_group); 106530792Sache#ifdef LOGIN_CAP 106698611Sjmallett SWAP(char *, sep->se_class, new->se_class); 106730792Sache#endif 106898611Sjmallett SWAP(char *, sep->se_server, new->se_server); 106998611Sjmallett SWAP(char *, sep->se_server_name, new->se_server_name); 10701553Srgrimes for (i = 0; i < MAXARGV; i++) 107198611Sjmallett SWAP(char *, sep->se_argv[i], new->se_argv[i]); 107256590Sshin#ifdef IPSEC 107398611Sjmallett SWAP(char *, sep->se_policy, new->se_policy); 107456590Sshin ipsecsetup(sep); 107556590Sshin#endif 107642122Sdes sigsetmask(omask); 107719618Sjulian freeconfig(new); 10781553Srgrimes if (debug) 10791553Srgrimes print_service("REDO", sep); 10801553Srgrimes } else { 108119618Sjulian sep = enter(new); 10821553Srgrimes if (debug) 10831553Srgrimes print_service("ADD ", sep); 10841553Srgrimes } 10851553Srgrimes sep->se_checked = 1; 10861553Srgrimes if (ISMUX(sep)) { 10871553Srgrimes sep->se_fd = -1; 10881553Srgrimes continue; 10891553Srgrimes } 109056590Sshin switch (sep->se_family) { 109156590Sshin case AF_INET: 1092102938Sdwmalone if (!v4bind_ok) { 109356590Sshin sep->se_fd = -1; 109456590Sshin continue; 109556590Sshin } 109656590Sshin break; 109756590Sshin#ifdef INET6 109856590Sshin case AF_INET6: 1099102938Sdwmalone if (!v6bind_ok) { 110056590Sshin sep->se_fd = -1; 110156590Sshin continue; 110256590Sshin } 110356590Sshin break; 110456590Sshin#endif 110556590Sshin } 11062657Scsgr if (!sep->se_rpc) { 110778356Sdwmalone if (sep->se_family != AF_UNIX) { 110878356Sdwmalone sp = getservbyname(sep->se_service, sep->se_proto); 110978356Sdwmalone if (sp == 0) { 111078356Sdwmalone syslog(LOG_ERR, "%s/%s: unknown service", 111178356Sdwmalone sep->se_service, sep->se_proto); 111278356Sdwmalone sep->se_checked = 0; 111378356Sdwmalone continue; 111478356Sdwmalone } 11152657Scsgr } 111656590Sshin switch (sep->se_family) { 111756590Sshin case AF_INET: 111856590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 111956590Sshin sep->se_ctrladdr4.sin_port = 112056590Sshin sp->s_port; 112156590Sshin sep->se_reset = 1; 112256590Sshin } 112356590Sshin break; 112456590Sshin#ifdef INET6 112556590Sshin case AF_INET6: 112656590Sshin if (sp->s_port != 112756590Sshin sep->se_ctrladdr6.sin6_port) { 112856590Sshin sep->se_ctrladdr6.sin6_port = 112956590Sshin sp->s_port; 113056590Sshin sep->se_reset = 1; 113156590Sshin } 113256590Sshin break; 113356590Sshin#endif 11342657Scsgr } 113556590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 113656590Sshin close_sep(sep); 11372657Scsgr } else { 11382657Scsgr rpc = getrpcbyname(sep->se_service); 11392657Scsgr if (rpc == 0) { 114052219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 11412657Scsgr sep->se_service, sep->se_proto); 11422657Scsgr if (sep->se_fd != -1) 11432657Scsgr (void) close(sep->se_fd); 11442657Scsgr sep->se_fd = -1; 11452657Scsgr continue; 11462657Scsgr } 1147100127Salfred if (sep->se_reset != 0 || 1148100127Salfred rpc->r_number != sep->se_rpc_prog) { 11492657Scsgr if (sep->se_rpc_prog) 11502657Scsgr unregisterrpc(sep); 11512657Scsgr sep->se_rpc_prog = rpc->r_number; 11522657Scsgr if (sep->se_fd != -1) 11532657Scsgr (void) close(sep->se_fd); 11542657Scsgr sep->se_fd = -1; 11552657Scsgr } 1156100127Salfred sep->se_nomapped = new_nomapped; 11571553Srgrimes } 1158100127Salfred sep->se_reset = 0; 11591553Srgrimes if (sep->se_fd == -1) 11601553Srgrimes setup(sep); 11611553Srgrimes } 11621553Srgrimes endconfig(); 11631553Srgrimes /* 11641553Srgrimes * Purge anything not looked at above. 11651553Srgrimes */ 116642122Sdes omask = sigblock(SIGBLOCK); 11671553Srgrimes sepp = &servtab; 116819617Sjulian while ((sep = *sepp)) { 11691553Srgrimes if (sep->se_checked) { 11701553Srgrimes sepp = &sep->se_next; 11711553Srgrimes continue; 11721553Srgrimes } 11731553Srgrimes *sepp = sep->se_next; 11741553Srgrimes if (sep->se_fd >= 0) 11751553Srgrimes close_sep(sep); 11761553Srgrimes if (debug) 11771553Srgrimes print_service("FREE", sep); 11782657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 11792657Scsgr unregisterrpc(sep); 11801553Srgrimes freeconfig(sep); 118171399Sdwmalone free(sep); 11821553Srgrimes } 118342122Sdes (void) sigsetmask(omask); 11841553Srgrimes} 11851553Srgrimes 11861553Srgrimesvoid 118798558Sjmallettunregisterrpc(struct servtab *sep) 11882657Scsgr{ 118978694Sdwmalone u_int i; 11902657Scsgr struct servtab *sepp; 119142122Sdes long omask; 1192100127Salfred struct netconfig *netid4, *netid6; 11932657Scsgr 119442122Sdes omask = sigblock(SIGBLOCK); 1195100127Salfred netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1196100127Salfred netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1197100127Salfred if (sep->se_family == AF_INET) 1198100127Salfred netid6 = NULL; 1199100127Salfred else if (sep->se_nomapped) 1200100127Salfred netid4 = NULL; 1201100127Salfred /* 1202100127Salfred * Conflict if same prog and protocol - In that case one should look 1203100127Salfred * to versions, but it is not interesting: having separate servers for 1204100127Salfred * different versions does not work well. 1205100127Salfred * Therefore one do not unregister if there is a conflict. 1206100127Salfred * There is also transport conflict if destroying INET when INET46 1207100127Salfred * exists, or destroying INET46 when INET exists 1208100127Salfred */ 12092657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 12102657Scsgr if (sepp == sep) 12112657Scsgr continue; 1212100127Salfred if (sepp->se_checked == 0 || 12132657Scsgr !sepp->se_rpc || 1214100127Salfred strcmp(sep->se_proto, sepp->se_proto) != 0 || 12152657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 12162657Scsgr continue; 1217100127Salfred if (sepp->se_family == AF_INET) 1218100127Salfred netid4 = NULL; 1219100127Salfred if (sepp->se_family == AF_INET6) { 1220100127Salfred netid6 = NULL; 1221100127Salfred if (!sep->se_nomapped) 1222100127Salfred netid4 = NULL; 1223100127Salfred } 1224100127Salfred if (netid4 == NULL && netid6 == NULL) 1225100127Salfred return; 12262657Scsgr } 12272657Scsgr if (debug) 12282657Scsgr print_service("UNREG", sep); 1229100127Salfred for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1230100127Salfred if (netid4) 1231100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid4); 1232100127Salfred if (netid6) 1233100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid6); 1234100127Salfred } 12352657Scsgr if (sep->se_fd != -1) 12362657Scsgr (void) close(sep->se_fd); 12372657Scsgr sep->se_fd = -1; 123842122Sdes (void) sigsetmask(omask); 12392657Scsgr} 12402657Scsgr 12412657Scsgrvoid 124298561Sjmallettflag_retry(int signo __unused) 12431553Srgrimes{ 124442250Sdes flag_signal('A'); 124542122Sdes} 124642122Sdes 124742122Sdesvoid 124898558Sjmallettretry(void) 124942122Sdes{ 12501553Srgrimes struct servtab *sep; 12511553Srgrimes 12521553Srgrimes timingout = 0; 12531553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 125419617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 12551553Srgrimes setup(sep); 12561553Srgrimes} 12571553Srgrimes 12581553Srgrimesvoid 125998558Sjmallettsetup(struct servtab *sep) 12601553Srgrimes{ 12611553Srgrimes int on = 1; 12621553Srgrimes 126356590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 12641553Srgrimes if (debug) 126529602Scharnier warn("socket failed on %s/%s", 126629602Scharnier sep->se_service, sep->se_proto); 12671553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 12681553Srgrimes sep->se_service, sep->se_proto); 12691553Srgrimes return; 12701553Srgrimes } 1271111324Sdwmalone /* Set all listening sockets to close-on-exec. */ 1272111324Sdwmalone if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) { 1273111324Sdwmalone syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m", 1274111324Sdwmalone sep->se_service, sep->se_proto); 1275111324Sdwmalone close(sep->se_fd); 1276111324Sdwmalone return; 1277111324Sdwmalone } 12781553Srgrimes#define turnon(fd, opt) \ 12791553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 12801553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 12811553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 12821553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 12831553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 12841553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 128525253Swollman#ifdef SO_PRIVSTATE 128613956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 128713956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 128825253Swollman#endif 128956590Sshin /* tftpd opens a new connection then needs more infos */ 129056590Sshin if ((sep->se_family == AF_INET6) && 129156590Sshin (strcmp(sep->se_proto, "udp") == 0) && 129256590Sshin (sep->se_accept == 0) && 1293121559Sume (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 129456590Sshin (char *)&on, sizeof (on)) < 0)) 129556590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 129658935Sume if (sep->se_family == AF_INET6) { 129758935Sume int flag = sep->se_nomapped ? 1 : 0; 1298100505Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 129958935Sume (char *)&flag, sizeof (flag)) < 0) 1300100505Sume syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 130158935Sume } 13021553Srgrimes#undef turnon 130336042Sguido if (sep->se_type == TTCP_TYPE) 130436042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 130536042Sguido (char *)&on, sizeof (on)) < 0) 130636042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 130756590Sshin#ifdef IPV6_FAITH 130856590Sshin if (sep->se_type == FAITH_TYPE) { 130956590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 131056590Sshin sizeof(on)) < 0) { 131156590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 131256590Sshin } 131356590Sshin } 131456590Sshin#endif 131556590Sshin#ifdef IPSEC 131656590Sshin ipsecsetup(sep); 131756590Sshin#endif 131878356Sdwmalone if (sep->se_family == AF_UNIX) { 131978356Sdwmalone (void) unlink(sep->se_ctrladdr_un.sun_path); 132078356Sdwmalone umask(0777); /* Make socket with conservative permissions */ 132178356Sdwmalone } 13221553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 132356590Sshin sep->se_ctrladdr_size) < 0) { 13241553Srgrimes if (debug) 132529602Scharnier warn("bind failed on %s/%s", 132629602Scharnier sep->se_service, sep->se_proto); 13271553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 13281553Srgrimes sep->se_service, sep->se_proto); 13291553Srgrimes (void) close(sep->se_fd); 13301553Srgrimes sep->se_fd = -1; 13311553Srgrimes if (!timingout) { 13321553Srgrimes timingout = 1; 13331553Srgrimes alarm(RETRYTIME); 13341553Srgrimes } 133578356Sdwmalone if (sep->se_family == AF_UNIX) 133678356Sdwmalone umask(mask); 13371553Srgrimes return; 13381553Srgrimes } 133978356Sdwmalone if (sep->se_family == AF_UNIX) { 134078356Sdwmalone /* Ick - fch{own,mod} don't work on Unix domain sockets */ 134178356Sdwmalone if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 134278356Sdwmalone syslog(LOG_ERR, "chown socket: %m"); 134378356Sdwmalone if (chmod(sep->se_service, sep->se_sockmode) < 0) 134478356Sdwmalone syslog(LOG_ERR, "chmod socket: %m"); 134578356Sdwmalone umask(mask); 134678356Sdwmalone } 13472657Scsgr if (sep->se_rpc) { 134878694Sdwmalone u_int i; 134971399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 1350100127Salfred struct netconfig *netid, *netid2 = NULL; 1351100127Salfred struct sockaddr_in sock; 1352100127Salfred struct netbuf nbuf, nbuf2; 13532657Scsgr 13548857Srgrimes if (getsockname(sep->se_fd, 13552657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 13562657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 13572657Scsgr sep->se_service, sep->se_proto); 13582657Scsgr (void) close(sep->se_fd); 13592657Scsgr sep->se_fd = -1; 13608857Srgrimes return; 13612657Scsgr } 1362100127Salfred nbuf.buf = &sep->se_ctrladdr; 1363100127Salfred nbuf.len = sep->se_ctrladdr.sa_len; 1364100127Salfred if (sep->se_family == AF_INET) 1365100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1366100127Salfred else { 1367100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1368100127Salfred if (!sep->se_nomapped) { /* INET and INET6 */ 1369100127Salfred netid2 = netid==udp6conf? udpconf:tcpconf; 1370100127Salfred memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1371100127Salfred nbuf2.buf = &sock; 1372100127Salfred nbuf2.len = sock.sin_len = sizeof sock; 1373100127Salfred sock.sin_family = AF_INET; 1374100127Salfred sock.sin_port = sep->se_ctrladdr6.sin6_port; 1375100127Salfred } 1376100127Salfred } 13772657Scsgr if (debug) 13782657Scsgr print_service("REG ", sep); 13792657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1380100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid); 1381100127Salfred rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1382100127Salfred if (netid2) { 1383100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid2); 1384100127Salfred rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1385100127Salfred } 13862657Scsgr } 13872657Scsgr } 13881553Srgrimes if (sep->se_socktype == SOCK_STREAM) 138917197Sdg listen(sep->se_fd, 64); 139019618Sjulian enable(sep); 13911553Srgrimes if (debug) { 139229602Scharnier warnx("registered %s on %d", 13931553Srgrimes sep->se_server, sep->se_fd); 13941553Srgrimes } 13951553Srgrimes} 13961553Srgrimes 139756590Sshin#ifdef IPSEC 139856590Sshinvoid 139956590Sshinipsecsetup(sep) 140056590Sshin struct servtab *sep; 140156590Sshin{ 140256590Sshin char *buf; 140356590Sshin char *policy_in = NULL; 140456590Sshin char *policy_out = NULL; 140556590Sshin int level; 140656590Sshin int opt; 140756590Sshin 140856590Sshin switch (sep->se_family) { 140956590Sshin case AF_INET: 141056590Sshin level = IPPROTO_IP; 141156590Sshin opt = IP_IPSEC_POLICY; 141256590Sshin break; 141356590Sshin#ifdef INET6 141456590Sshin case AF_INET6: 141556590Sshin level = IPPROTO_IPV6; 141656590Sshin opt = IPV6_IPSEC_POLICY; 141756590Sshin break; 141856590Sshin#endif 141956590Sshin default: 142056590Sshin return; 142156590Sshin } 142256590Sshin 142356590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 142478694Sdwmalone static char def_in[] = "in entrust", def_out[] = "out entrust"; 142578694Sdwmalone policy_in = def_in; 142678694Sdwmalone policy_out = def_out; 142756590Sshin } else { 142856590Sshin if (!strncmp("in", sep->se_policy, 2)) 142956590Sshin policy_in = sep->se_policy; 143056590Sshin else if (!strncmp("out", sep->se_policy, 3)) 143156590Sshin policy_out = sep->se_policy; 143256590Sshin else { 143356590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 143456590Sshin sep->se_policy); 143556590Sshin return; 143656590Sshin } 143756590Sshin } 143856590Sshin 143956590Sshin if (policy_in != NULL) { 144056590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 144156590Sshin if (buf != NULL) { 144256590Sshin if (setsockopt(sep->se_fd, level, opt, 144356675Sshin buf, ipsec_get_policylen(buf)) < 0 && 144456759Sshin debug != 0) 144556759Sshin warnx("%s/%s: ipsec initialization failed; %s", 144656759Sshin sep->se_service, sep->se_proto, 144756759Sshin policy_in); 144856590Sshin free(buf); 144956590Sshin } else 145056590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 145156590Sshin policy_in); 145256590Sshin } 145356590Sshin if (policy_out != NULL) { 145456590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 145556590Sshin if (buf != NULL) { 145656590Sshin if (setsockopt(sep->se_fd, level, opt, 145756675Sshin buf, ipsec_get_policylen(buf)) < 0 && 145856759Sshin debug != 0) 145956759Sshin warnx("%s/%s: ipsec initialization failed; %s", 146056759Sshin sep->se_service, sep->se_proto, 146156759Sshin policy_out); 146256590Sshin free(buf); 146356590Sshin } else 146456590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 146556590Sshin policy_out); 146656590Sshin } 146756590Sshin} 146856590Sshin#endif 146956590Sshin 14701553Srgrimes/* 14711553Srgrimes * Finish with a service and its socket. 14721553Srgrimes */ 14731553Srgrimesvoid 147498558Sjmallettclose_sep(struct servtab *sep) 14751553Srgrimes{ 14761553Srgrimes if (sep->se_fd >= 0) { 147719618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 147819618Sjulian disable(sep); 14791553Srgrimes (void) close(sep->se_fd); 14801553Srgrimes sep->se_fd = -1; 14811553Srgrimes } 14821553Srgrimes sep->se_count = 0; 148319618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 14841553Srgrimes} 14851553Srgrimes 148648467Ssheldonhint 148798558Sjmallettmatchservent(const char *name1, const char *name2, const char *proto) 148848467Ssheldonh{ 148978356Sdwmalone char **alias, *p; 149048467Ssheldonh struct servent *se; 149148467Ssheldonh 149278356Sdwmalone if (strcmp(proto, "unix") == 0) { 149378356Sdwmalone if ((p = strrchr(name1, '/')) != NULL) 149478356Sdwmalone name1 = p + 1; 149578356Sdwmalone if ((p = strrchr(name2, '/')) != NULL) 149678356Sdwmalone name2 = p + 1; 149778356Sdwmalone } 149849026Sdes if (strcmp(name1, name2) == 0) 149949026Sdes return(1); 150048467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 150148467Ssheldonh if (strcmp(name2, se->s_name) == 0) 150248467Ssheldonh return(1); 150348467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 150448467Ssheldonh if (strcmp(name2, *alias) == 0) 150548467Ssheldonh return(1); 150648467Ssheldonh } 150748467Ssheldonh return(0); 150848467Ssheldonh} 150948467Ssheldonh 15101553Srgrimesstruct servtab * 151198558Sjmallettenter(struct servtab *cp) 15121553Srgrimes{ 15131553Srgrimes struct servtab *sep; 151442122Sdes long omask; 15151553Srgrimes 15161553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 15171553Srgrimes if (sep == (struct servtab *)0) { 151849102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 151919617Sjulian exit(EX_OSERR); 15201553Srgrimes } 15211553Srgrimes *sep = *cp; 15221553Srgrimes sep->se_fd = -1; 152342122Sdes omask = sigblock(SIGBLOCK); 15241553Srgrimes sep->se_next = servtab; 15251553Srgrimes servtab = sep; 152642122Sdes sigsetmask(omask); 15271553Srgrimes return (sep); 15281553Srgrimes} 15291553Srgrimes 153019618Sjulianvoid 153198558Sjmallettenable(struct servtab *sep) 153219618Sjulian{ 153319618Sjulian if (debug) 153429602Scharnier warnx( 153519618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 153619618Sjulian#ifdef SANITY_CHECK 153719618Sjulian if (sep->se_fd < 0) { 153819618Sjulian syslog(LOG_ERR, 153919618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 154019618Sjulian exit(EX_SOFTWARE); 154119618Sjulian } 154219618Sjulian if (ISMUX(sep)) { 154319618Sjulian syslog(LOG_ERR, 154419618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 154519618Sjulian exit(EX_SOFTWARE); 154619618Sjulian } 154719618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 154819618Sjulian syslog(LOG_ERR, 154919618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 155019618Sjulian exit(EX_SOFTWARE); 155119618Sjulian } 155248991Ssheldonh nsock++; 155319618Sjulian#endif 155419618Sjulian FD_SET(sep->se_fd, &allsock); 155519618Sjulian if (sep->se_fd > maxsock) 155619618Sjulian maxsock = sep->se_fd; 155719618Sjulian} 155819618Sjulian 155919618Sjulianvoid 156098558Sjmallettdisable(struct servtab *sep) 156119618Sjulian{ 156219618Sjulian if (debug) 156329602Scharnier warnx( 156419618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 156519618Sjulian#ifdef SANITY_CHECK 156619618Sjulian if (sep->se_fd < 0) { 156719618Sjulian syslog(LOG_ERR, 156819618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 156919618Sjulian exit(EX_SOFTWARE); 157019618Sjulian } 157119618Sjulian if (ISMUX(sep)) { 157219618Sjulian syslog(LOG_ERR, 157319618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 157419618Sjulian exit(EX_SOFTWARE); 157519618Sjulian } 157619618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 157719618Sjulian syslog(LOG_ERR, 157819618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 157919618Sjulian exit(EX_SOFTWARE); 158019618Sjulian } 158119618Sjulian if (nsock == 0) { 158219618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 158319618Sjulian exit(EX_SOFTWARE); 158419618Sjulian } 158548991Ssheldonh nsock--; 158619618Sjulian#endif 158719618Sjulian FD_CLR(sep->se_fd, &allsock); 158819618Sjulian if (sep->se_fd == maxsock) 158919618Sjulian maxsock--; 159019618Sjulian} 159119618Sjulian 15921553SrgrimesFILE *fconfig = NULL; 15931553Srgrimesstruct servtab serv; 15941553Srgrimeschar line[LINE_MAX]; 15951553Srgrimes 15961553Srgrimesint 159798558Sjmallettsetconfig(void) 15981553Srgrimes{ 15991553Srgrimes 16001553Srgrimes if (fconfig != NULL) { 16011553Srgrimes fseek(fconfig, 0L, SEEK_SET); 16021553Srgrimes return (1); 16031553Srgrimes } 16041553Srgrimes fconfig = fopen(CONFIG, "r"); 16051553Srgrimes return (fconfig != NULL); 16061553Srgrimes} 16071553Srgrimes 16081553Srgrimesvoid 160998558Sjmallettendconfig(void) 16101553Srgrimes{ 16111553Srgrimes if (fconfig) { 16121553Srgrimes (void) fclose(fconfig); 16131553Srgrimes fconfig = NULL; 16141553Srgrimes } 16151553Srgrimes} 16161553Srgrimes 16171553Srgrimesstruct servtab * 161898558Sjmallettgetconfigent(void) 16191553Srgrimes{ 16201553Srgrimes struct servtab *sep = &serv; 16211553Srgrimes int argc; 162219618Sjulian char *cp, *arg, *s; 16232657Scsgr char *versp; 16241553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 16251553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 162656590Sshin#ifdef IPSEC 1627102861Sdwmalone char *policy; 162856590Sshin#endif 1629102861Sdwmalone int v4bind; 163056590Sshin#ifdef INET6 1631102861Sdwmalone int v6bind; 163256590Sshin#endif 1633101474Sume int i; 16341553Srgrimes 1635102861Sdwmalone#ifdef IPSEC 1636102861Sdwmalone policy = NULL; 1637102861Sdwmalone#endif 16381553Srgrimesmore: 1639102861Sdwmalone v4bind = 0; 1640102861Sdwmalone#ifdef INET6 1641102861Sdwmalone v6bind = 0; 1642102861Sdwmalone#endif 164356590Sshin while ((cp = nextline(fconfig)) != NULL) { 164456590Sshin#ifdef IPSEC 164556590Sshin /* lines starting with #@ is not a comment, but the policy */ 164656590Sshin if (cp[0] == '#' && cp[1] == '@') { 164756590Sshin char *p; 164856590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 164956590Sshin ; 165056590Sshin if (*p == '\0') { 165156590Sshin if (policy) 165256590Sshin free(policy); 165356590Sshin policy = NULL; 165456590Sshin } else if (ipsec_get_policylen(p) >= 0) { 165556590Sshin if (policy) 165656590Sshin free(policy); 165756590Sshin policy = newstr(p); 165856590Sshin } else { 165956590Sshin syslog(LOG_ERR, 166056590Sshin "%s: invalid ipsec policy \"%s\"", 166156590Sshin CONFIG, p); 166256590Sshin exit(EX_CONFIG); 166356590Sshin } 166456590Sshin } 166556590Sshin#endif 166656590Sshin if (*cp == '#' || *cp == '\0') 166756590Sshin continue; 166856590Sshin break; 166956590Sshin } 16701553Srgrimes if (cp == NULL) 16711553Srgrimes return ((struct servtab *)0); 16721553Srgrimes /* 16731553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 16741553Srgrimes * for example) don't get initialized here. 16751553Srgrimes */ 167671399Sdwmalone memset(sep, 0, sizeof *sep); 16771553Srgrimes arg = skip(&cp); 16781553Srgrimes if (cp == NULL) { 16791553Srgrimes /* got an empty line containing just blanks/tabs. */ 16801553Srgrimes goto more; 16811553Srgrimes } 168278356Sdwmalone if (arg[0] == ':') { /* :user:group:perm: */ 168378356Sdwmalone char *user, *group, *perm; 168478356Sdwmalone struct passwd *pw; 168578356Sdwmalone struct group *gr; 168678356Sdwmalone user = arg+1; 168778356Sdwmalone if ((group = strchr(user, ':')) == NULL) { 168878356Sdwmalone syslog(LOG_ERR, "no group after user '%s'", user); 168978356Sdwmalone goto more; 169078356Sdwmalone } 169178356Sdwmalone *group++ = '\0'; 169278356Sdwmalone if ((perm = strchr(group, ':')) == NULL) { 169378356Sdwmalone syslog(LOG_ERR, "no mode after group '%s'", group); 169478356Sdwmalone goto more; 169578356Sdwmalone } 169678356Sdwmalone *perm++ = '\0'; 169778356Sdwmalone if ((pw = getpwnam(user)) == NULL) { 169878356Sdwmalone syslog(LOG_ERR, "no such user '%s'", user); 169978356Sdwmalone goto more; 170078356Sdwmalone } 170178356Sdwmalone sep->se_sockuid = pw->pw_uid; 170278356Sdwmalone if ((gr = getgrnam(group)) == NULL) { 170378356Sdwmalone syslog(LOG_ERR, "no such user '%s'", group); 170478356Sdwmalone goto more; 170578356Sdwmalone } 170678356Sdwmalone sep->se_sockgid = gr->gr_gid; 170778356Sdwmalone sep->se_sockmode = strtol(perm, &arg, 8); 170878356Sdwmalone if (*arg != ':') { 170978356Sdwmalone syslog(LOG_ERR, "bad mode '%s'", perm); 171078356Sdwmalone goto more; 171178356Sdwmalone } 171278356Sdwmalone *arg++ = '\0'; 171378356Sdwmalone } else { 171478356Sdwmalone sep->se_sockuid = euid; 171578356Sdwmalone sep->se_sockgid = egid; 171678356Sdwmalone sep->se_sockmode = 0200; 171778356Sdwmalone } 17181553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 17191553Srgrimes char *c = arg + MUX_LEN; 17201553Srgrimes if (*c == '+') { 17211553Srgrimes sep->se_type = MUXPLUS_TYPE; 17221553Srgrimes c++; 17231553Srgrimes } else 17241553Srgrimes sep->se_type = MUX_TYPE; 17251553Srgrimes sep->se_service = newstr(c); 17261553Srgrimes } else { 17271553Srgrimes sep->se_service = newstr(arg); 17281553Srgrimes sep->se_type = NORM_TYPE; 17291553Srgrimes } 17301553Srgrimes arg = sskip(&cp); 17311553Srgrimes if (strcmp(arg, "stream") == 0) 17321553Srgrimes sep->se_socktype = SOCK_STREAM; 17331553Srgrimes else if (strcmp(arg, "dgram") == 0) 17341553Srgrimes sep->se_socktype = SOCK_DGRAM; 17351553Srgrimes else if (strcmp(arg, "rdm") == 0) 17361553Srgrimes sep->se_socktype = SOCK_RDM; 17371553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 17381553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 17391553Srgrimes else if (strcmp(arg, "raw") == 0) 17401553Srgrimes sep->se_socktype = SOCK_RAW; 17411553Srgrimes else 17421553Srgrimes sep->se_socktype = -1; 174336042Sguido 174436042Sguido arg = sskip(&cp); 174556590Sshin if (strncmp(arg, "tcp", 3) == 0) { 174656590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 174756590Sshin if (arg != NULL) { 174856590Sshin if (strcmp(arg, "ttcp") == 0) 174956590Sshin sep->se_type = TTCP_TYPE; 175056590Sshin else if (strcmp(arg, "faith") == 0) 175156590Sshin sep->se_type = FAITH_TYPE; 175256590Sshin } 175377518Sume } else { 175477518Sume if (sep->se_type == NORM_TYPE && 175577518Sume strncmp(arg, "faith/", 6) == 0) { 175677518Sume arg += 6; 175777518Sume sep->se_type = FAITH_TYPE; 175877518Sume } 175936042Sguido sep->se_proto = newstr(arg); 176077518Sume } 17612657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 176219237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 176319237Sjoerg strlen(sep->se_proto) + 1 - 4); 17642657Scsgr sep->se_rpc = 1; 17652657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 17662657Scsgr sep->se_rpc_lowvers = 0; 176756590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 176856590Sshin sizeof(sep->se_ctrladdr4)); 17692657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 17702657Scsgr *versp++ = '\0'; 1771102859Sdwmalone switch (sscanf(versp, "%u-%u", 17722657Scsgr &sep->se_rpc_lowvers, 17732657Scsgr &sep->se_rpc_highvers)) { 17742657Scsgr case 2: 17752657Scsgr break; 17762657Scsgr case 1: 17772657Scsgr sep->se_rpc_highvers = 17782657Scsgr sep->se_rpc_lowvers; 17792657Scsgr break; 17802657Scsgr default: 17818857Srgrimes syslog(LOG_ERR, 178252219Scharnier "bad RPC version specifier; %s", 17832657Scsgr sep->se_service); 17842657Scsgr freeconfig(sep); 17852657Scsgr goto more; 17862657Scsgr } 17872657Scsgr } 17882657Scsgr else { 17892657Scsgr sep->se_rpc_lowvers = 17902657Scsgr sep->se_rpc_highvers = 1; 17912657Scsgr } 17922657Scsgr } 179356590Sshin sep->se_nomapped = 0; 179478356Sdwmalone if (strcmp(sep->se_proto, "unix") == 0) { 179578356Sdwmalone sep->se_family = AF_UNIX; 1796102937Sdwmalone } else { 1797102937Sdwmalone while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 179856590Sshin#ifdef INET6 1799102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1800102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1801102937Sdwmalone v6bind = 1; 1802102937Sdwmalone continue; 1803102937Sdwmalone } 1804102937Sdwmalone#endif 1805102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1806102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1807102937Sdwmalone v4bind = 1; 1808102937Sdwmalone continue; 1809102937Sdwmalone } 1810102937Sdwmalone /* illegal version num */ 1811102937Sdwmalone syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1812100127Salfred freeconfig(sep); 1813100127Salfred goto more; 1814100127Salfred } 1815102937Sdwmalone#ifdef INET6 1816102938Sdwmalone if (v6bind && !v6bind_ok) { 1817102937Sdwmalone syslog(LOG_INFO, "IPv6 bind is ignored for %s", 181856590Sshin sep->se_service); 1819102938Sdwmalone if (v4bind && v4bind_ok) 1820102937Sdwmalone v6bind = 0; 1821102937Sdwmalone else { 1822102937Sdwmalone freeconfig(sep); 1823102937Sdwmalone goto more; 1824102937Sdwmalone } 182556590Sshin } 1826102938Sdwmalone if (v6bind) { 1827102937Sdwmalone sep->se_family = AF_INET6; 1828102938Sdwmalone if (!v4bind || !v4bind_ok) 1829102937Sdwmalone sep->se_nomapped = 1; 1830102937Sdwmalone } else 1831102937Sdwmalone#endif 1832102937Sdwmalone { /* default to v4 bind if not v6 bind */ 1833102938Sdwmalone if (!v4bind_ok) { 1834102937Sdwmalone syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1835102937Sdwmalone sep->se_service); 1836102937Sdwmalone freeconfig(sep); 1837102937Sdwmalone goto more; 1838102937Sdwmalone } 1839102937Sdwmalone sep->se_family = AF_INET; 1840102937Sdwmalone } 184156590Sshin } 184256590Sshin /* init ctladdr */ 184356590Sshin switch(sep->se_family) { 184456590Sshin case AF_INET: 184556590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 184656590Sshin sizeof(sep->se_ctrladdr4)); 184756590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 184856590Sshin break; 184956590Sshin#ifdef INET6 185056590Sshin case AF_INET6: 185156590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 185256590Sshin sizeof(sep->se_ctrladdr6)); 185356590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 185456590Sshin break; 185556590Sshin#endif 185678356Sdwmalone case AF_UNIX: 185778356Sdwmalone if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 185878356Sdwmalone syslog(LOG_ERR, 185978356Sdwmalone "domain socket pathname too long for service %s", 186078356Sdwmalone sep->se_service); 186178356Sdwmalone goto more; 186278356Sdwmalone } 186378356Sdwmalone memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 186478356Sdwmalone sep->se_ctrladdr_un.sun_family = sep->se_family; 186578356Sdwmalone sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 186678356Sdwmalone strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 186778356Sdwmalone sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 186856590Sshin } 18691553Srgrimes arg = sskip(&cp); 187019618Sjulian if (!strncmp(arg, "wait", 4)) 187119618Sjulian sep->se_accept = 0; 187219618Sjulian else if (!strncmp(arg, "nowait", 6)) 187319618Sjulian sep->se_accept = 1; 187419618Sjulian else { 187519618Sjulian syslog(LOG_ERR, 187619618Sjulian "%s: bad wait/nowait for service %s", 187719618Sjulian CONFIG, sep->se_service); 187819618Sjulian goto more; 187919618Sjulian } 188048069Ssheldonh sep->se_maxchild = -1; 188148069Ssheldonh sep->se_maxcpm = -1; 1882101474Sume sep->se_maxperip = -1; 188319618Sjulian if ((s = strchr(arg, '/')) != NULL) { 188419618Sjulian char *eptr; 188519618Sjulian u_long val; 188619618Sjulian 188719618Sjulian val = strtoul(s + 1, &eptr, 10); 188830847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 188919618Sjulian syslog(LOG_ERR, 189019618Sjulian "%s: bad max-child for service %s", 189119618Sjulian CONFIG, sep->se_service); 189219618Sjulian goto more; 189319618Sjulian } 189448069Ssheldonh if (debug) 189548069Ssheldonh if (!sep->se_accept && val != 1) 189648069Ssheldonh warnx("maxchild=%lu for wait service %s" 189748069Ssheldonh " not recommended", val, sep->se_service); 189819618Sjulian sep->se_maxchild = val; 189930847Sdima if (*eptr == '/') 190030847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1901101474Sume if (*eptr == '/') 1902101474Sume sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 190330847Sdima /* 190430847Sdima * explicitly do not check for \0 for future expansion / 190530847Sdima * backwards compatibility 190630847Sdima */ 190719618Sjulian } 19081553Srgrimes if (ISMUX(sep)) { 19091553Srgrimes /* 191019618Sjulian * Silently enforce "nowait" mode for TCPMUX services 191119618Sjulian * since they don't have an assigned port to listen on. 19121553Srgrimes */ 191319618Sjulian sep->se_accept = 1; 19141553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 19158857Srgrimes syslog(LOG_ERR, 19161553Srgrimes "%s: bad protocol for tcpmux service %s", 19171553Srgrimes CONFIG, sep->se_service); 19181553Srgrimes goto more; 19191553Srgrimes } 19201553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 19218857Srgrimes syslog(LOG_ERR, 19221553Srgrimes "%s: bad socket type for tcpmux service %s", 19231553Srgrimes CONFIG, sep->se_service); 19241553Srgrimes goto more; 19251553Srgrimes } 19261553Srgrimes } 19271553Srgrimes sep->se_user = newstr(sskip(&cp)); 192830792Sache#ifdef LOGIN_CAP 192930792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 193030792Sache *s = '\0'; 193130792Sache sep->se_class = newstr(s + 1); 193230792Sache } else 193330792Sache sep->se_class = newstr(RESOURCE_RC); 193430792Sache#endif 193530807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 193630807Sache *s = '\0'; 193730807Sache sep->se_group = newstr(s + 1); 193830807Sache } else 193930807Sache sep->se_group = NULL; 19401553Srgrimes sep->se_server = newstr(sskip(&cp)); 194145588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 194245588Smarkm sep->se_server_name++; 19431553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 19441553Srgrimes struct biltin *bi; 19451553Srgrimes 19461553Srgrimes for (bi = biltins; bi->bi_service; bi++) 194749026Sdes if (bi->bi_socktype == sep->se_socktype && 194848467Ssheldonh matchservent(bi->bi_service, sep->se_service, 194948467Ssheldonh sep->se_proto)) 19501553Srgrimes break; 19511553Srgrimes if (bi->bi_service == 0) { 19521553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 19531553Srgrimes sep->se_service); 19541553Srgrimes goto more; 19551553Srgrimes } 195619618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 19571553Srgrimes sep->se_bi = bi; 19581553Srgrimes } else 19591553Srgrimes sep->se_bi = NULL; 1960101474Sume if (sep->se_maxperip < 0) 1961101474Sume sep->se_maxperip = maxperip; 196248069Ssheldonh if (sep->se_maxcpm < 0) 196348069Ssheldonh sep->se_maxcpm = maxcpm; 196445588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 196548069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 196619618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 196748069Ssheldonh else if (sep->se_accept) 196848069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 196919618Sjulian else 197048069Ssheldonh sep->se_maxchild = 1; 197145588Smarkm } 197264197Sdwmalone if (sep->se_maxchild > 0) { 197319618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 197419618Sjulian if (sep->se_pids == NULL) { 197549102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 197619618Sjulian exit(EX_OSERR); 197719618Sjulian } 197819618Sjulian } 19791553Srgrimes argc = 0; 19801553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 198119618Sjulian if (argc < MAXARGV) { 19821553Srgrimes sep->se_argv[argc++] = newstr(arg); 198319618Sjulian } else { 198419618Sjulian syslog(LOG_ERR, 198519618Sjulian "%s: too many arguments for service %s", 198619618Sjulian CONFIG, sep->se_service); 198719618Sjulian goto more; 198819618Sjulian } 19891553Srgrimes while (argc <= MAXARGV) 19901553Srgrimes sep->se_argv[argc++] = NULL; 1991101474Sume for (i = 0; i < PERIPSIZE; ++i) 1992101474Sume LIST_INIT(&sep->se_conn[i]); 199356590Sshin#ifdef IPSEC 199456590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 199556590Sshin#endif 19961553Srgrimes return (sep); 19971553Srgrimes} 19981553Srgrimes 19991553Srgrimesvoid 200098558Sjmallettfreeconfig(struct servtab *cp) 20011553Srgrimes{ 20021553Srgrimes int i; 20031553Srgrimes 20041553Srgrimes if (cp->se_service) 20051553Srgrimes free(cp->se_service); 20061553Srgrimes if (cp->se_proto) 20071553Srgrimes free(cp->se_proto); 20081553Srgrimes if (cp->se_user) 20091553Srgrimes free(cp->se_user); 201030807Sache if (cp->se_group) 201130807Sache free(cp->se_group); 201230792Sache#ifdef LOGIN_CAP 201330792Sache if (cp->se_class) 201430792Sache free(cp->se_class); 201530792Sache#endif 20161553Srgrimes if (cp->se_server) 20171553Srgrimes free(cp->se_server); 201819618Sjulian if (cp->se_pids) 201919618Sjulian free(cp->se_pids); 20201553Srgrimes for (i = 0; i < MAXARGV; i++) 20211553Srgrimes if (cp->se_argv[i]) 20221553Srgrimes free(cp->se_argv[i]); 2023101474Sume free_connlist(cp); 202456590Sshin#ifdef IPSEC 202556590Sshin if (cp->se_policy) 202656590Sshin free(cp->se_policy); 202756590Sshin#endif 20281553Srgrimes} 20291553Srgrimes 20301553Srgrimes 20311553Srgrimes/* 20321553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 20331553Srgrimes * configuration file and exit. 20341553Srgrimes */ 20351553Srgrimeschar * 203698558Sjmallettsskip(char **cpp) 20371553Srgrimes{ 20381553Srgrimes char *cp; 20391553Srgrimes 20401553Srgrimes cp = skip(cpp); 20411553Srgrimes if (cp == NULL) { 20421553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 204319617Sjulian exit(EX_DATAERR); 20441553Srgrimes } 20451553Srgrimes return (cp); 20461553Srgrimes} 20471553Srgrimes 20481553Srgrimeschar * 204998558Sjmallettskip(char **cpp) 20501553Srgrimes{ 20511553Srgrimes char *cp = *cpp; 20521553Srgrimes char *start; 205311933Sadam char quote = '\0'; 20541553Srgrimes 20551553Srgrimesagain: 20561553Srgrimes while (*cp == ' ' || *cp == '\t') 20571553Srgrimes cp++; 20581553Srgrimes if (*cp == '\0') { 20591553Srgrimes int c; 20601553Srgrimes 20611553Srgrimes c = getc(fconfig); 20621553Srgrimes (void) ungetc(c, fconfig); 20631553Srgrimes if (c == ' ' || c == '\t') 206419617Sjulian if ((cp = nextline(fconfig))) 20651553Srgrimes goto again; 20661553Srgrimes *cpp = (char *)0; 20671553Srgrimes return ((char *)0); 20681553Srgrimes } 206911933Sadam if (*cp == '"' || *cp == '\'') 207011933Sadam quote = *cp++; 20711553Srgrimes start = cp; 207211933Sadam if (quote) 207311933Sadam while (*cp && *cp != quote) 207411933Sadam cp++; 207511933Sadam else 207611933Sadam while (*cp && *cp != ' ' && *cp != '\t') 207711933Sadam cp++; 20781553Srgrimes if (*cp != '\0') 20791553Srgrimes *cp++ = '\0'; 20801553Srgrimes *cpp = cp; 20811553Srgrimes return (start); 20821553Srgrimes} 20831553Srgrimes 20841553Srgrimeschar * 208598558Sjmallettnextline(FILE *fd) 20861553Srgrimes{ 20871553Srgrimes char *cp; 20881553Srgrimes 20891553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 20901553Srgrimes return ((char *)0); 20911553Srgrimes cp = strchr(line, '\n'); 20921553Srgrimes if (cp) 20931553Srgrimes *cp = '\0'; 20941553Srgrimes return (line); 20951553Srgrimes} 20961553Srgrimes 20971553Srgrimeschar * 209898558Sjmallettnewstr(const char *cp) 20991553Srgrimes{ 210078694Sdwmalone char *cr; 210178694Sdwmalone 210278694Sdwmalone if ((cr = strdup(cp != NULL ? cp : ""))) 210378694Sdwmalone return (cr); 21041553Srgrimes syslog(LOG_ERR, "strdup: %m"); 210519617Sjulian exit(EX_OSERR); 21061553Srgrimes} 21071553Srgrimes 21081553Srgrimesvoid 210998558Sjmallettinetd_setproctitle(const char *a, int s) 21101553Srgrimes{ 211171399Sdwmalone socklen_t size; 211256590Sshin struct sockaddr_storage ss; 211356590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 21141553Srgrimes 211556590Sshin size = sizeof(ss); 211656590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 211756590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 211856590Sshin NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 211956590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 212056590Sshin } else 212113142Speter (void) sprintf(buf, "%s", a); 212213142Speter setproctitle("%s", buf); 212313142Speter} 212413142Speter 212578694Sdwmaloneint 212698558Sjmallettcheck_loop(const struct sockaddr *sa, const struct servtab *sep) 21275182Swollman{ 21285182Swollman struct servtab *se2; 212956590Sshin char pname[INET6_ADDRSTRLEN]; 21305182Swollman 21315182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 21325182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 21335182Swollman continue; 21345182Swollman 213556590Sshin switch (se2->se_family) { 213656590Sshin case AF_INET: 213778694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 213856590Sshin se2->se_ctrladdr4.sin_port) 213956590Sshin goto isloop; 214056590Sshin continue; 214156590Sshin#ifdef INET6 214256590Sshin case AF_INET6: 214378694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214456590Sshin se2->se_ctrladdr4.sin_port) 214556590Sshin goto isloop; 214656590Sshin continue; 214756590Sshin#endif 214856590Sshin default: 214956590Sshin continue; 21505182Swollman } 215156590Sshin isloop: 215256590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 215356590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 215456590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 215556590Sshin sep->se_service, sep->se_proto, 215656590Sshin se2->se_service, se2->se_proto, 215756590Sshin pname); 215856590Sshin return 1; 21595182Swollman } 21605182Swollman return 0; 21615182Swollman} 21625182Swollman 21631553Srgrimes/* 21641553Srgrimes * print_service: 21651553Srgrimes * Dump relevant information to stderr 21661553Srgrimes */ 21671553Srgrimesvoid 216898558Sjmallettprint_service(const char *action, const struct servtab *sep) 21691553Srgrimes{ 217019617Sjulian fprintf(stderr, 217156590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 217230792Sache#ifdef LOGIN_CAP 217356590Sshin "class=%s" 217430792Sache#endif 217556590Sshin " builtin=%p server=%s" 217656590Sshin#ifdef IPSEC 217756590Sshin " policy=\"%s\"" 217856590Sshin#endif 217956590Sshin "\n", 218019617Sjulian action, sep->se_service, sep->se_proto, 218130807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 218230792Sache#ifdef LOGIN_CAP 218330792Sache sep->se_class, 218430792Sache#endif 218556590Sshin (void *) sep->se_bi, sep->se_server 218656590Sshin#ifdef IPSEC 218756590Sshin , (sep->se_policy ? sep->se_policy : "") 218856590Sshin#endif 218956590Sshin ); 21901553Srgrimes} 21911553Srgrimes 219230847Sdima#define CPMHSIZE 256 219330847Sdima#define CPMHMASK (CPMHSIZE-1) 219430847Sdima#define CHTGRAN 10 219530847Sdima#define CHTSIZE 6 219630847Sdima 219730847Sdimatypedef struct CTime { 219830847Sdima unsigned long ct_Ticks; 219930847Sdima int ct_Count; 220030847Sdima} CTime; 220130847Sdima 220230847Sdimatypedef struct CHash { 220356590Sshin union { 220456590Sshin struct in_addr c4_Addr; 220556590Sshin struct in6_addr c6_Addr; 220656590Sshin } cu_Addr; 220756590Sshin#define ch_Addr4 cu_Addr.c4_Addr 220856590Sshin#define ch_Addr6 cu_Addr.c6_Addr 220956590Sshin int ch_Family; 221030847Sdima time_t ch_LTime; 221130847Sdima char *ch_Service; 221230847Sdima CTime ch_Times[CHTSIZE]; 221330847Sdima} CHash; 221430847Sdima 221530847SdimaCHash CHashAry[CPMHSIZE]; 221630847Sdima 221730847Sdimaint 221898558Sjmallettcpmip(const struct servtab *sep, int ctrl) 221930847Sdima{ 222056590Sshin struct sockaddr_storage rss; 222171399Sdwmalone socklen_t rssLen = sizeof(rss); 222230847Sdima int r = 0; 222330847Sdima 222430847Sdima /* 222530847Sdima * If getpeername() fails, just let it through (if logging is 222630847Sdima * enabled the condition is caught elsewhere) 222730847Sdima */ 222830847Sdima 222930847Sdima if (sep->se_maxcpm > 0 && 223056590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 223130847Sdima time_t t = time(NULL); 223230847Sdima int hv = 0xABC3D20F; 223330847Sdima int i; 223430847Sdima int cnt = 0; 223530847Sdima CHash *chBest = NULL; 223630847Sdima unsigned int ticks = t / CHTGRAN; 223778694Sdwmalone struct sockaddr_in *sin4; 223856590Sshin#ifdef INET6 223956590Sshin struct sockaddr_in6 *sin6; 224056590Sshin#endif 224130847Sdima 224278694Sdwmalone sin4 = (struct sockaddr_in *)&rss; 224356590Sshin#ifdef INET6 224456590Sshin sin6 = (struct sockaddr_in6 *)&rss; 224556590Sshin#endif 224630847Sdima { 224730847Sdima char *p; 224878694Sdwmalone int addrlen; 224930847Sdima 225056590Sshin switch (rss.ss_family) { 225156590Sshin case AF_INET: 225278694Sdwmalone p = (char *)&sin4->sin_addr; 225356590Sshin addrlen = sizeof(struct in_addr); 225456590Sshin break; 225556590Sshin#ifdef INET6 225656590Sshin case AF_INET6: 225756590Sshin p = (char *)&sin6->sin6_addr; 225856590Sshin addrlen = sizeof(struct in6_addr); 225956590Sshin break; 226056590Sshin#endif 226156590Sshin default: 226256590Sshin /* should not happen */ 226356590Sshin return -1; 226456590Sshin } 226556590Sshin 226656590Sshin for (i = 0; i < addrlen; ++i, ++p) { 226730847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 226830847Sdima } 226930847Sdima hv = (hv ^ (hv >> 16)); 227030847Sdima } 227130847Sdima for (i = 0; i < 5; ++i) { 227230847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 227330847Sdima 227456590Sshin if (rss.ss_family == AF_INET && 227556590Sshin ch->ch_Family == AF_INET && 227678694Sdwmalone sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 227730847Sdima ch->ch_Service && strcmp(sep->se_service, 227830847Sdima ch->ch_Service) == 0) { 227930847Sdima chBest = ch; 228030847Sdima break; 228130847Sdima } 228256590Sshin#ifdef INET6 228356590Sshin if (rss.ss_family == AF_INET6 && 228456590Sshin ch->ch_Family == AF_INET6 && 228556590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 228656590Sshin &ch->ch_Addr6) != 0 && 228756590Sshin ch->ch_Service && strcmp(sep->se_service, 228856590Sshin ch->ch_Service) == 0) { 228956590Sshin chBest = ch; 229056590Sshin break; 229156590Sshin } 229256590Sshin#endif 229330847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 229430847Sdima ch->ch_LTime < chBest->ch_LTime) { 229530847Sdima chBest = ch; 229630847Sdima } 229730847Sdima } 229856590Sshin if ((rss.ss_family == AF_INET && 229956590Sshin (chBest->ch_Family != AF_INET || 230078694Sdwmalone sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 230130847Sdima chBest->ch_Service == NULL || 230230847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 230378694Sdwmalone chBest->ch_Family = sin4->sin_family; 230478694Sdwmalone chBest->ch_Addr4 = sin4->sin_addr; 230530847Sdima if (chBest->ch_Service) 230630847Sdima free(chBest->ch_Service); 230730847Sdima chBest->ch_Service = strdup(sep->se_service); 230830847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 230930847Sdima } 231056590Sshin#ifdef INET6 231156590Sshin if ((rss.ss_family == AF_INET6 && 231256590Sshin (chBest->ch_Family != AF_INET6 || 231356590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 231456590Sshin &chBest->ch_Addr6) == 0)) || 231556590Sshin chBest->ch_Service == NULL || 231656590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 231756590Sshin chBest->ch_Family = sin6->sin6_family; 231856590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 231956590Sshin if (chBest->ch_Service) 232056590Sshin free(chBest->ch_Service); 232156590Sshin chBest->ch_Service = strdup(sep->se_service); 232256590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 232356590Sshin } 232456590Sshin#endif 232530847Sdima chBest->ch_LTime = t; 232630847Sdima { 232730847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 232830847Sdima if (ct->ct_Ticks != ticks) { 232930847Sdima ct->ct_Ticks = ticks; 233030847Sdima ct->ct_Count = 0; 233130847Sdima } 233230847Sdima ++ct->ct_Count; 233330847Sdima } 233430847Sdima for (i = 0; i < CHTSIZE; ++i) { 233530847Sdima CTime *ct = &chBest->ch_Times[i]; 233630847Sdima if (ct->ct_Ticks <= ticks && 233730847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 233830847Sdima cnt += ct->ct_Count; 233930847Sdima } 234030847Sdima } 2341117644Sdwmalone if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 234256590Sshin char pname[INET6_ADDRSTRLEN]; 234356590Sshin 234456590Sshin getnameinfo((struct sockaddr *)&rss, 234556590Sshin ((struct sockaddr *)&rss)->sa_len, 234656590Sshin pname, sizeof(pname), NULL, 0, 234756590Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 234830847Sdima r = -1; 234930847Sdima syslog(LOG_ERR, 235033794Spst "%s from %s exceeded counts/min (limit %d/min)", 235156590Sshin sep->se_service, pname, 235233794Spst sep->se_maxcpm); 235330847Sdima } 235430847Sdima } 235530847Sdima return(r); 235630847Sdima} 2357101474Sume 2358101474Sumestatic struct conninfo * 2359101474Sumesearch_conn(struct servtab *sep, int ctrl) 2360101474Sume{ 2361101474Sume struct sockaddr_storage ss; 2362101474Sume socklen_t sslen = sizeof(ss); 2363101474Sume struct conninfo *conn; 2364101474Sume int hv; 2365101474Sume char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2366101474Sume 2367101474Sume if (sep->se_maxperip <= 0) 2368101474Sume return NULL; 2369101474Sume 2370101474Sume /* 2371101474Sume * If getpeername() fails, just let it through (if logging is 2372101474Sume * enabled the condition is caught elsewhere) 2373101474Sume */ 2374101474Sume if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2375101474Sume return NULL; 2376101474Sume 2377101474Sume switch (ss.ss_family) { 2378101474Sume case AF_INET: 2379101474Sume hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2380101474Sume sizeof(struct in_addr)); 2381101474Sume break; 2382101474Sume#ifdef INET6 2383101474Sume case AF_INET6: 2384101474Sume hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2385101474Sume sizeof(struct in6_addr)); 2386101474Sume break; 2387101474Sume#endif 2388101474Sume default: 2389101474Sume /* 2390101474Sume * Since we only support AF_INET and AF_INET6, just 2391101474Sume * let other than AF_INET and AF_INET6 through. 2392101474Sume */ 2393101474Sume return NULL; 2394101474Sume } 2395101474Sume 2396101474Sume if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2397101474Sume NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0) 2398101474Sume return NULL; 2399101474Sume 2400101474Sume LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2401101474Sume if (getnameinfo((struct sockaddr *)&conn->co_addr, 2402101474Sume conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2403101474Sume NI_NUMERICHOST | NI_WITHSCOPEID) == 0 && 2404101474Sume strcmp(pname, pname2) == 0) 2405101474Sume break; 2406101474Sume } 2407101474Sume 2408101474Sume if (conn == NULL) { 2409101474Sume if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2410101474Sume syslog(LOG_ERR, "malloc: %m"); 2411101474Sume exit(EX_OSERR); 2412101474Sume } 2413101474Sume conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2414101474Sume if (conn->co_proc == NULL) { 2415101474Sume syslog(LOG_ERR, "malloc: %m"); 2416101474Sume exit(EX_OSERR); 2417101474Sume } 2418101474Sume memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2419101474Sume conn->co_numchild = 0; 2420101474Sume LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2421101474Sume } 2422101474Sume 2423101474Sume /* 2424101474Sume * Since a child process is not invoked yet, we cannot 2425101474Sume * determine a pid of a child. So, co_proc and co_numchild 2426101474Sume * should be filled leter. 2427101474Sume */ 2428101474Sume 2429101474Sume return conn; 2430101474Sume} 2431101474Sume 2432101474Sumestatic int 2433101474Sumeroom_conn(struct servtab *sep, struct conninfo *conn) 2434101474Sume{ 2435101474Sume char pname[NI_MAXHOST]; 2436101474Sume 2437101474Sume if (conn->co_numchild >= sep->se_maxperip) { 2438101474Sume getnameinfo((struct sockaddr *)&conn->co_addr, 2439101474Sume conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2440101474Sume NI_NUMERICHOST | NI_WITHSCOPEID); 2441101474Sume syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2442101474Sume sep->se_service, pname, sep->se_maxperip); 2443101474Sume return 0; 2444101474Sume } 2445101474Sume return 1; 2446101474Sume} 2447101474Sume 2448101474Sumestatic void 2449101474Sumeaddchild_conn(struct conninfo *conn, pid_t pid) 2450101474Sume{ 2451101474Sume struct procinfo *proc; 2452101474Sume 2453101474Sume if (conn == NULL) 2454101474Sume return; 2455101474Sume 2456101474Sume if ((proc = search_proc(pid, 1)) != NULL) { 2457101474Sume if (proc->pr_conn != NULL) { 2458101474Sume syslog(LOG_ERR, 2459101474Sume "addchild_conn: child already on process list"); 2460101474Sume exit(EX_OSERR); 2461101474Sume } 2462101474Sume proc->pr_conn = conn; 2463101474Sume } 2464101474Sume 2465101474Sume conn->co_proc[conn->co_numchild++] = proc; 2466101474Sume} 2467101474Sume 2468101474Sumestatic void 2469101474Sumereapchild_conn(pid_t pid) 2470101474Sume{ 2471101474Sume struct procinfo *proc; 2472101474Sume struct conninfo *conn; 2473101474Sume int i; 2474101474Sume 2475101474Sume if ((proc = search_proc(pid, 0)) == NULL) 2476101474Sume return; 2477101474Sume if ((conn = proc->pr_conn) == NULL) 2478101474Sume return; 2479101474Sume for (i = 0; i < conn->co_numchild; ++i) 2480101474Sume if (conn->co_proc[i] == proc) { 2481101474Sume conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2482101474Sume break; 2483101474Sume } 2484101474Sume free_proc(proc); 2485101474Sume free_conn(conn); 2486101474Sume} 2487101474Sume 2488101474Sumestatic void 2489102859Sdwmaloneresize_conn(struct servtab *sep, int maxpip) 2490101474Sume{ 2491101474Sume struct conninfo *conn; 2492101474Sume int i, j; 2493101474Sume 2494101474Sume if (sep->se_maxperip <= 0) 2495101474Sume return; 2496102859Sdwmalone if (maxpip <= 0) { 2497101474Sume free_connlist(sep); 2498101474Sume return; 2499101474Sume } 2500101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2501101474Sume LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2502102859Sdwmalone for (j = maxpip; j < conn->co_numchild; ++j) 2503101474Sume free_proc(conn->co_proc[j]); 2504101474Sume conn->co_proc = realloc(conn->co_proc, 2505102859Sdwmalone maxpip * sizeof(*conn->co_proc)); 2506101474Sume if (conn->co_proc == NULL) { 2507101474Sume syslog(LOG_ERR, "realloc: %m"); 2508101474Sume exit(EX_OSERR); 2509101474Sume } 2510102859Sdwmalone if (conn->co_numchild > maxpip) 2511102859Sdwmalone conn->co_numchild = maxpip; 2512101474Sume } 2513101474Sume } 2514101474Sume} 2515101474Sume 2516101474Sumestatic void 2517101474Sumefree_connlist(struct servtab *sep) 2518101474Sume{ 2519101474Sume struct conninfo *conn; 2520101474Sume int i, j; 2521101474Sume 2522101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2523101474Sume while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2524101474Sume for (j = 0; j < conn->co_numchild; ++j) 2525101474Sume free_proc(conn->co_proc[j]); 2526101474Sume conn->co_numchild = 0; 2527101474Sume free_conn(conn); 2528101474Sume } 2529101474Sume } 2530101474Sume} 2531101474Sume 2532101474Sumestatic void 2533101474Sumefree_conn(struct conninfo *conn) 2534101474Sume{ 2535101474Sume if (conn == NULL) 2536101474Sume return; 2537101474Sume if (conn->co_numchild <= 0) { 2538101474Sume LIST_REMOVE(conn, co_link); 2539101474Sume free(conn->co_proc); 2540101474Sume free(conn); 2541101474Sume } 2542101474Sume} 2543101474Sume 2544101474Sumestatic struct procinfo * 2545101474Sumesearch_proc(pid_t pid, int add) 2546101474Sume{ 2547101474Sume struct procinfo *proc; 2548101474Sume int hv; 2549101474Sume 2550101474Sume hv = hashval((char *)&pid, sizeof(pid)); 2551101474Sume LIST_FOREACH(proc, &proctable[hv], pr_link) { 2552101474Sume if (proc->pr_pid == pid) 2553101474Sume break; 2554101474Sume } 2555101474Sume if (proc == NULL && add) { 2556101474Sume if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2557101474Sume syslog(LOG_ERR, "malloc: %m"); 2558101474Sume exit(EX_OSERR); 2559101474Sume } 2560101474Sume proc->pr_pid = pid; 2561101474Sume proc->pr_conn = NULL; 2562101474Sume LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2563101474Sume } 2564101474Sume return proc; 2565101474Sume} 2566101474Sume 2567101474Sumestatic void 2568101474Sumefree_proc(struct procinfo *proc) 2569101474Sume{ 2570101474Sume if (proc == NULL) 2571101474Sume return; 2572101474Sume LIST_REMOVE(proc, pr_link); 2573101474Sume free(proc); 2574101474Sume} 2575101474Sume 2576101474Sumestatic int 2577101474Sumehashval(char *p, int len) 2578101474Sume{ 2579101474Sume int i, hv = 0xABC3D20F; 2580101474Sume 2581101474Sume for (i = 0; i < len; ++i, ++p) 2582101474Sume hv = (hv << 5) ^ (hv >> 23) ^ *p; 2583101474Sume hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2584101474Sume return hv; 2585101474Sume} 2586