inetd.c revision 154530
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1991, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 301553Srgrimes#ifndef lint 3129602Scharnierstatic const char copyright[] = 321553Srgrimes"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 331553Srgrimes The Regents of the University of California. All rights reserved.\n"; 341553Srgrimes#endif /* not lint */ 351553Srgrimes 361553Srgrimes#ifndef lint 3729602Scharnier#if 0 3829602Scharnierstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 3929602Scharnier#endif 401553Srgrimes#endif /* not lint */ 411553Srgrimes 4298563Sjmallett#include <sys/cdefs.h> 4398563Sjmallett__FBSDID("$FreeBSD: head/usr.sbin/inetd/inetd.c 154530 2006-01-18 19:38:43Z delphij $"); 4498563Sjmallett 451553Srgrimes/* 461553Srgrimes * Inetd - Internet super-server 471553Srgrimes * 481553Srgrimes * This program invokes all internet services as needed. Connection-oriented 491553Srgrimes * services are invoked each time a connection is made, by creating a process. 501553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 511553Srgrimes * to do a getpeername to find out the source host and port. 521553Srgrimes * 531553Srgrimes * Datagram oriented services are invoked when a datagram 541553Srgrimes * arrives; a process is created and passed a pending message 551553Srgrimes * on file descriptor 0. Datagram servers may either connect 561553Srgrimes * to their peer, freeing up the original socket for inetd 571553Srgrimes * to receive further messages on, or ``take over the socket'', 581553Srgrimes * processing all arriving datagrams and, eventually, timing 591553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 608857Srgrimes * the second type of server ``single-threaded''. 611553Srgrimes * 621553Srgrimes * Inetd uses a configuration file which is read at startup 631553Srgrimes * and, possibly, at some later time in response to a hangup signal. 641553Srgrimes * The configuration file is ``free format'' with fields given in the 6567514Sdwmalone * order shown below. Continuation lines for an entry must begin with 661553Srgrimes * a space or tab. All fields must be present in each entry. 671553Srgrimes * 6878356Sdwmalone * service name must be in /etc/services 6978356Sdwmalone * or name a tcpmux service 7078356Sdwmalone * or specify a unix domain socket 711553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 7278356Sdwmalone * protocol tcp[4][6][/faith,ttcp], udp[4][6], unix 731553Srgrimes * wait/nowait single-threaded/multi-threaded 741553Srgrimes * user user to run daemon as 751553Srgrimes * server program full path name 761553Srgrimes * server program arguments maximum of MAXARGS (20) 771553Srgrimes * 781553Srgrimes * TCP services without official port numbers are handled with the 791553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 801553Srgrimes * requests. When a connection is made from a foreign host, the service 811553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 821553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 831553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 841553Srgrimes * server is expected to return the positive reply if the service type in 851553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 861553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 871553Srgrimes * process; this is for compatibility with older server code, and also 881553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 891553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 901553Srgrimes * because they do not have a well-known port and hence cannot listen 911553Srgrimes * for new requests. 921553Srgrimes * 932657Scsgr * For RPC services 942657Scsgr * service name/version must be in /etc/rpc 952657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 96100127Salfred * protocol rpc/tcp[4][6], rpc/udp[4][6] 972657Scsgr * wait/nowait single-threaded/multi-threaded 982657Scsgr * user user to run daemon as 992657Scsgr * server program full path name 1002657Scsgr * server program arguments maximum of MAXARGS 1012657Scsgr * 1021553Srgrimes * Comment lines are indicated by a `#' in column 1. 10356590Sshin * 10456590Sshin * #ifdef IPSEC 10556590Sshin * Comment lines that start with "#@" denote IPsec policy string, as described 10656590Sshin * in ipsec_set_policy(3). This will affect all the following items in 10756590Sshin * inetd.conf(8). To reset the policy, just use "#@" line. By default, 10856590Sshin * there's no IPsec policy. 10956590Sshin * #endif 1101553Srgrimes */ 1111553Srgrimes#include <sys/param.h> 1121553Srgrimes#include <sys/ioctl.h> 1131553Srgrimes#include <sys/wait.h> 1141553Srgrimes#include <sys/time.h> 1151553Srgrimes#include <sys/resource.h> 11678356Sdwmalone#include <sys/stat.h> 11778356Sdwmalone#include <sys/un.h> 1181553Srgrimes 1191553Srgrimes#include <netinet/in.h> 12036042Sguido#include <netinet/tcp.h> 1211553Srgrimes#include <arpa/inet.h> 1222657Scsgr#include <rpc/rpc.h> 12319617Sjulian#include <rpc/pmap_clnt.h> 1241553Srgrimes 125106054Swollman#include <ctype.h> 1261553Srgrimes#include <errno.h> 12729602Scharnier#include <err.h> 1281553Srgrimes#include <fcntl.h> 12930807Sache#include <grp.h> 130106054Swollman#include <libutil.h> 131106054Swollman#include <limits.h> 1321553Srgrimes#include <netdb.h> 1331553Srgrimes#include <pwd.h> 1341553Srgrimes#include <signal.h> 1351553Srgrimes#include <stdio.h> 1361553Srgrimes#include <stdlib.h> 1371553Srgrimes#include <string.h> 138106054Swollman#include <sysexits.h> 1391553Srgrimes#include <syslog.h> 14048279Ssheldonh#include <tcpd.h> 1411553Srgrimes#include <unistd.h> 1421553Srgrimes 14348981Ssheldonh#include "inetd.h" 14448981Ssheldonh#include "pathnames.h" 14548981Ssheldonh 14656590Sshin#ifdef IPSEC 14756590Sshin#include <netinet6/ipsec.h> 14856590Sshin#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 14956590Sshin#undef IPSEC 15056590Sshin#endif 15156590Sshin#endif 15256590Sshin 15345089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 15445089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 15545089Smarkm#endif 15645089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 15745089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 15845089Smarkm#endif 15945089Smarkm#ifndef LIBWRAP_DENY_FACILITY 16045089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 16145089Smarkm#endif 16245089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 16345089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 16445089Smarkm#endif 16545089Smarkm 16648382Ssheldonh#define ISWRAP(sep) \ 16748697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 16878356Sdwmalone && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 16948382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17048382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 17148382Ssheldonh 17221640Speter#ifdef LOGIN_CAP 17321640Speter#include <login_cap.h> 17430792Sache 17530792Sache/* see init.c */ 17630792Sache#define RESOURCE_RC "daemon" 17730792Sache 17821640Speter#endif 17921640Speter 18033794Spst#ifndef MAXCHILD 18133794Spst#define MAXCHILD -1 /* maximum number of this service 18233794Spst < 0 = no limit */ 18333794Spst#endif 18433794Spst 18533794Spst#ifndef MAXCPM 18633794Spst#define MAXCPM -1 /* rate limit invocations from a 18733794Spst single remote address, 18833794Spst < 0 = no limit */ 18933794Spst#endif 19033794Spst 191101474Sume#ifndef MAXPERIP 192101474Sume#define MAXPERIP -1 /* maximum number of this service 193101474Sume from a single remote address, 194101474Sume < 0 = no limit */ 195101474Sume#endif 196101474Sume 19764197Sdwmalone#ifndef TOOMANY 1982659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 19964197Sdwmalone#endif 2001553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 2011553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 20219618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 2031553Srgrimes 2041553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2051553Srgrimes 20698562Sjmallettvoid close_sep(struct servtab *); 207154530Sdelphijvoid flag_signal(int); 208154530Sdelphijvoid flag_config(int); 20998562Sjmallettvoid config(void); 21098562Sjmallettint cpmip(const struct servtab *, int); 21198562Sjmallettvoid endconfig(void); 21298562Sjmallettstruct servtab *enter(struct servtab *); 21398562Sjmallettvoid freeconfig(struct servtab *); 21498562Sjmallettstruct servtab *getconfigent(void); 21598562Sjmallettint matchservent(const char *, const char *, const char *); 21698562Sjmallettchar *nextline(FILE *); 21798562Sjmallettvoid addchild(struct servtab *, int); 218154530Sdelphijvoid flag_reapchild(int); 219154530Sdelphijvoid reapchild(void); 22098562Sjmallettvoid enable(struct servtab *); 22198562Sjmallettvoid disable(struct servtab *); 222154530Sdelphijvoid flag_retry(int); 22398562Sjmallettvoid retry(void); 22498562Sjmallettint setconfig(void); 22598562Sjmallettvoid setup(struct servtab *); 22678694Sdwmalone#ifdef IPSEC 22798562Sjmallettvoid ipsecsetup(struct servtab *); 22878694Sdwmalone#endif 22998562Sjmallettvoid unregisterrpc(register struct servtab *sep); 230101474Sumestatic struct conninfo *search_conn(struct servtab *sep, int ctrl); 231101474Sumestatic int room_conn(struct servtab *sep, struct conninfo *conn); 232101474Sumestatic void addchild_conn(struct conninfo *conn, pid_t pid); 233154530Sdelphijstatic void reapchild_conn(pid_t pid); 234101474Sumestatic void free_conn(struct conninfo *conn); 235101474Sumestatic void resize_conn(struct servtab *sep, int maxperip); 236101474Sumestatic void free_connlist(struct servtab *sep); 237101474Sumestatic void free_proc(struct procinfo *); 238101474Sumestatic struct procinfo *search_proc(pid_t pid, int add); 239101474Sumestatic int hashval(char *p, int len); 24078694Sdwmalone 24148279Ssheldonhint allow_severity; 24248279Ssheldonhint deny_severity; 24348697Ssheldonhint wrap_ex = 0; 24448279Ssheldonhint wrap_bi = 0; 2451553Srgrimesint debug = 0; 246121766Speterint dolog = 0; 24748988Ssheldonhint maxsock; /* highest-numbered descriptor */ 248154530Sdelphijfd_set allsock; 2491553Srgrimesint options; 2501553Srgrimesint timingout; 2511553Srgrimesint toomany = TOOMANY; 25248069Ssheldonhint maxchild = MAXCHILD; 25348069Ssheldonhint maxcpm = MAXCPM; 254101474Sumeint maxperip = MAXPERIP; 2551553Srgrimesstruct servent *sp; 2562657Scsgrstruct rpcent *rpc; 25756590Sshinchar *hostname = NULL; 25856590Sshinstruct sockaddr_in *bind_sa4; 259102938Sdwmaloneint v4bind_ok = 0; 26056590Sshin#ifdef INET6 26156590Sshinstruct sockaddr_in6 *bind_sa6; 262102938Sdwmaloneint v6bind_ok = 0; 26356590Sshin#endif 264154530Sdelphijint signalpipe[2]; 26548991Ssheldonh#ifdef SANITY_CHECK 26648991Ssheldonhint nsock; 26748991Ssheldonh#endif 26878356Sdwmaloneuid_t euid; 26978356Sdwmalonegid_t egid; 27078356Sdwmalonemode_t mask; 2711553Srgrimes 27248981Ssheldonhstruct servtab *servtab; 2731553Srgrimes 27448981Ssheldonhextern struct biltin biltins[]; 2751553Srgrimes 27678694Sdwmaloneconst char *CONFIG = _PATH_INETDCONF; 27778694Sdwmaloneconst char *pid_file = _PATH_INETDPID; 278149432Spjdstruct pidfh *pfh = NULL; 27913142Speter 280100127Salfredstruct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 281100127Salfred 282101474Sumestatic LIST_HEAD(, procinfo) proctable[PERIPSIZE]; 283101474Sume 2841553Srgrimesint 28598558Sjmallettgetvalue(const char *arg, int *value, const char *whine) 28633794Spst{ 28733794Spst int tmp; 28833794Spst char *p; 28933794Spst 29033794Spst tmp = strtol(arg, &p, 0); 29164197Sdwmalone if (tmp < 0 || *p) { 29233794Spst syslog(LOG_ERR, whine, arg); 29333794Spst return 1; /* failure */ 29433794Spst } 29533794Spst *value = tmp; 29633794Spst return 0; /* success */ 29733794Spst} 29833794Spst 299110802Sumestatic sa_family_t 300110802Sumewhichaf(struct request_info *req) 301110802Sume{ 302110802Sume struct sockaddr *sa; 303110802Sume 304110802Sume sa = (struct sockaddr *)req->client->sin; 305110802Sume if (sa == NULL) 306110802Sume return AF_UNSPEC; 307110802Sume if (sa->sa_family == AF_INET6 && 308110802Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) 309110802Sume return AF_INET; 310110802Sume return sa->sa_family; 311110802Sume} 312110802Sume 31333794Spstint 31498558Sjmallettmain(int argc, char **argv) 3151553Srgrimes{ 3161553Srgrimes struct servtab *sep; 3171553Srgrimes struct passwd *pwd; 31830807Sache struct group *grp; 31948962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 320121555Speter int ch, dofork; 3211553Srgrimes pid_t pid; 3221553Srgrimes char buf[50]; 32321640Speter#ifdef LOGIN_CAP 32421640Speter login_cap_t *lc = NULL; 32521640Speter#endif 32645089Smarkm struct request_info req; 32745089Smarkm int denied; 32845089Smarkm char *service = NULL; 32956590Sshin union { 33056590Sshin struct sockaddr peer_un; 33156590Sshin struct sockaddr_in peer_un4; 33256590Sshin struct sockaddr_in6 peer_un6; 33356590Sshin struct sockaddr_storage peer_max; 33456590Sshin } p_un; 33556590Sshin#define peer p_un.peer_un 33656590Sshin#define peer4 p_un.peer_un4 33756590Sshin#define peer6 p_un.peer_un6 33856590Sshin#define peermax p_un.peer_max 339154530Sdelphij int i; 34056590Sshin struct addrinfo hints, *res; 34178694Sdwmalone const char *servname; 34256590Sshin int error; 343101474Sume struct conninfo *conn; 3441553Srgrimes 34597293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 3461553Srgrimes 347101474Sume while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1) 3481553Srgrimes switch(ch) { 3491553Srgrimes case 'd': 3501553Srgrimes debug = 1; 3511553Srgrimes options |= SO_DEBUG; 3521553Srgrimes break; 3532659Scsgr case 'l': 354121766Speter dolog = 1; 3552659Scsgr break; 35633794Spst case 'R': 35733794Spst getvalue(optarg, &toomany, 35833794Spst "-R %s: bad value for service invocation rate"); 3591553Srgrimes break; 36033794Spst case 'c': 36133794Spst getvalue(optarg, &maxchild, 36233794Spst "-c %s: bad value for maximum children"); 36333794Spst break; 36433794Spst case 'C': 36533794Spst getvalue(optarg, &maxcpm, 36633794Spst "-C %s: bad value for maximum children/minute"); 36733794Spst break; 36817482Sjulian case 'a': 36956590Sshin hostname = optarg; 37017482Sjulian break; 37117482Sjulian case 'p': 37217482Sjulian pid_file = optarg; 37317482Sjulian break; 374101474Sume case 's': 375101474Sume getvalue(optarg, &maxperip, 376101474Sume "-s %s: bad value for maximum children per source address"); 377101474Sume break; 37848279Ssheldonh case 'w': 37948697Ssheldonh wrap_ex++; 38048279Ssheldonh break; 38148697Ssheldonh case 'W': 38248697Ssheldonh wrap_bi++; 38348697Ssheldonh break; 3841553Srgrimes case '?': 3851553Srgrimes default: 3861553Srgrimes syslog(LOG_ERR, 38748697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 38833794Spst " [-c maximum] [-C rate]" 38917482Sjulian " [-p pidfile] [conf-file]"); 39019617Sjulian exit(EX_USAGE); 3911553Srgrimes } 39256590Sshin /* 39356590Sshin * Initialize Bind Addrs. 39456590Sshin * When hostname is NULL, wild card bind addrs are obtained from 39556590Sshin * getaddrinfo(). But getaddrinfo() requires at least one of 39656590Sshin * hostname or servname is non NULL. 39756590Sshin * So when hostname is NULL, set dummy value to servname. 398128501Sbrooks * Since getaddrinfo() doesn't accept numeric servname, and 399128501Sbrooks * we doesn't use ai_socktype of struct addrinfo returned 400128501Sbrooks * from getaddrinfo(), we set dummy value to ai_socktype. 40156590Sshin */ 402128501Sbrooks servname = (hostname == NULL) ? "0" /* dummy */ : NULL; 40356590Sshin 40456590Sshin bzero(&hints, sizeof(struct addrinfo)); 40556590Sshin hints.ai_flags = AI_PASSIVE; 40656590Sshin hints.ai_family = AF_UNSPEC; 407128501Sbrooks hints.ai_socktype = SOCK_STREAM; /* dummy */ 40856590Sshin error = getaddrinfo(hostname, servname, &hints, &res); 40956590Sshin if (error != 0) { 41056590Sshin syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 41156590Sshin if (error == EAI_SYSTEM) 41256590Sshin syslog(LOG_ERR, "%s", strerror(errno)); 41356590Sshin exit(EX_USAGE); 41456590Sshin } 41556590Sshin do { 41656590Sshin if (res->ai_addr == NULL) { 41756590Sshin syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 41856590Sshin exit(EX_USAGE); 41956590Sshin } 42056590Sshin switch (res->ai_addr->sa_family) { 42156590Sshin case AF_INET: 422102938Sdwmalone if (v4bind_ok) 42356590Sshin continue; 42456590Sshin bind_sa4 = (struct sockaddr_in *)res->ai_addr; 42556590Sshin /* init port num in case servname is dummy */ 42656590Sshin bind_sa4->sin_port = 0; 427102938Sdwmalone v4bind_ok = 1; 42856590Sshin continue; 42956590Sshin#ifdef INET6 43056590Sshin case AF_INET6: 431102938Sdwmalone if (v6bind_ok) 43256590Sshin continue; 43356590Sshin bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 43456590Sshin /* init port num in case servname is dummy */ 43556590Sshin bind_sa6->sin6_port = 0; 436102938Sdwmalone v6bind_ok = 1; 43756590Sshin continue; 43856590Sshin#endif 43956590Sshin } 440102938Sdwmalone if (v4bind_ok 44156590Sshin#ifdef INET6 442102938Sdwmalone && v6bind_ok 44356590Sshin#endif 44456590Sshin ) 44556590Sshin break; 44656590Sshin } while ((res = res->ai_next) != NULL); 447102938Sdwmalone if (!v4bind_ok 44856590Sshin#ifdef INET6 449102938Sdwmalone && !v6bind_ok 45056590Sshin#endif 45156590Sshin ) { 45256590Sshin syslog(LOG_ERR, "-a %s: unknown address family", hostname); 45356590Sshin exit(EX_USAGE); 45456590Sshin } 45556590Sshin 45678356Sdwmalone euid = geteuid(); 45778356Sdwmalone egid = getegid(); 45878356Sdwmalone umask(mask = umask(0777)); 45978356Sdwmalone 4601553Srgrimes argc -= optind; 4611553Srgrimes argv += optind; 4621553Srgrimes 4631553Srgrimes if (argc > 0) 4641553Srgrimes CONFIG = argv[0]; 465127301Sdwmalone if (access(CONFIG, R_OK) < 0) 466127301Sdwmalone syslog(LOG_ERR, "Accessing %s: %m, continuing anyway.", CONFIG); 4671553Srgrimes if (debug == 0) { 468149432Spjd pid_t otherpid; 469149432Spjd 470150214Spjd pfh = pidfile_open(pid_file, 0600, &otherpid); 471149432Spjd if (pfh == NULL) { 472149432Spjd if (errno == EEXIST) { 473149432Spjd syslog(LOG_ERR, "%s already running, pid: %d", 474149432Spjd getprogname(), otherpid); 475149432Spjd exit(EX_OSERR); 476149432Spjd } 477149432Spjd syslog(LOG_WARNING, "pidfile_open() failed: %m"); 478149432Spjd } 479149432Spjd 48012024Speter if (daemon(0, 0) < 0) { 48112024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 48212024Speter } 48397293Sjwd /* From now on we don't want syslog messages going to stderr. */ 48497293Sjwd closelog(); 48597293Sjwd openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 48612024Speter /* 48712024Speter * In case somebody has started inetd manually, we need to 48812024Speter * clear the logname, so that old servers run as root do not 48912024Speter * get the user's logname.. 49012024Speter */ 49112024Speter if (setlogin("") < 0) { 49212024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 49312024Speter /* no big deal if it fails.. */ 49412024Speter } 495149432Spjd if (pfh != NULL && pidfile_write(pfh) == -1) { 496149432Spjd syslog(LOG_WARNING, "pidfile_write(): %m"); 49711447Swollman } 4981553Srgrimes } 499100127Salfred 500101474Sume for (i = 0; i < PERIPSIZE; ++i) 501101474Sume LIST_INIT(&proctable[i]); 502101474Sume 503102938Sdwmalone if (v4bind_ok) { 504100127Salfred udpconf = getnetconfigent("udp"); 505100127Salfred tcpconf = getnetconfigent("tcp"); 506100127Salfred if (udpconf == NULL || tcpconf == NULL) { 507102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 508100127Salfred exit(EX_USAGE); 509100127Salfred } 510100127Salfred } 511100127Salfred#ifdef INET6 512102938Sdwmalone if (v6bind_ok) { 513100127Salfred udp6conf = getnetconfigent("udp6"); 514100127Salfred tcp6conf = getnetconfigent("tcp6"); 515100127Salfred if (udp6conf == NULL || tcp6conf == NULL) { 516102860Sdwmalone syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 517100127Salfred exit(EX_USAGE); 518100127Salfred } 519100127Salfred } 520100127Salfred#endif 521100127Salfred 52235948Sbde sa.sa_flags = 0; 52335948Sbde sigemptyset(&sa.sa_mask); 52435948Sbde sigaddset(&sa.sa_mask, SIGALRM); 52535948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 52635948Sbde sigaddset(&sa.sa_mask, SIGHUP); 527154530Sdelphij sa.sa_handler = flag_retry; 52848962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 52942122Sdes config(); 530154530Sdelphij sa.sa_handler = flag_config; 53148962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 532154530Sdelphij sa.sa_handler = flag_reapchild; 533154530Sdelphij sigaction(SIGCHLD, &sa, &sachld); 534154530Sdelphij sa.sa_handler = SIG_IGN; 53535948Sbde sigaction(SIGPIPE, &sa, &sapipe); 5361553Srgrimes 5371553Srgrimes { 5381553Srgrimes /* space for daemons to overwrite environment for ps */ 5391553Srgrimes#define DUMMYSIZE 100 5401553Srgrimes char dummy[DUMMYSIZE]; 5411553Srgrimes 54219298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 5431553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 5441553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 5451553Srgrimes } 5461553Srgrimes 547154530Sdelphij if (pipe(signalpipe) != 0) { 548154530Sdelphij syslog(LOG_ERR, "pipe: %m"); 549154530Sdelphij exit(EX_OSERR); 550154530Sdelphij } 551154530Sdelphij if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 || 552154530Sdelphij fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) { 553154530Sdelphij syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m"); 554154530Sdelphij exit(EX_OSERR); 555154530Sdelphij } 556154530Sdelphij FD_SET(signalpipe[0], &allsock); 557154530Sdelphij#ifdef SANITY_CHECK 558154530Sdelphij nsock++; 559154530Sdelphij#endif 560154530Sdelphij if (signalpipe[0] > maxsock) 561154530Sdelphij maxsock = signalpipe[0]; 562154530Sdelphij if (signalpipe[1] > maxsock) 563154530Sdelphij maxsock = signalpipe[1]; 564154530Sdelphij 5651553Srgrimes for (;;) { 5661553Srgrimes int n, ctrl; 567154530Sdelphij fd_set readable; 5681553Srgrimes 56948991Ssheldonh#ifdef SANITY_CHECK 5701553Srgrimes if (nsock == 0) { 571135823Sstefanf syslog(LOG_ERR, "%s: nsock=0", __func__); 57247015Sdes exit(EX_SOFTWARE); 5731553Srgrimes } 57448991Ssheldonh#endif 575154530Sdelphij readable = allsock; 576154530Sdelphij if ((n = select(maxsock + 1, &readable, (fd_set *)0, 577154530Sdelphij (fd_set *)0, (struct timeval *)0)) <= 0) { 578154530Sdelphij if (n < 0 && errno != EINTR) { 579154530Sdelphij syslog(LOG_WARNING, "select: %m"); 58028907Simp sleep(1); 58128907Simp } 5821553Srgrimes continue; 5831553Srgrimes } 584154530Sdelphij /* handle any queued signal flags */ 585154530Sdelphij if (FD_ISSET(signalpipe[0], &readable)) { 586154530Sdelphij int nsig; 587154530Sdelphij if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 588154530Sdelphij syslog(LOG_ERR, "ioctl: %m"); 589154530Sdelphij exit(EX_OSERR); 590154530Sdelphij } 591154530Sdelphij while (--nsig >= 0) { 592154530Sdelphij char c; 593154530Sdelphij if (read(signalpipe[0], &c, 1) != 1) { 594154530Sdelphij syslog(LOG_ERR, "read: %m"); 595154530Sdelphij exit(EX_OSERR); 596154530Sdelphij } 59742250Sdes if (debug) 598154530Sdelphij warnx("handling signal flag %c", c); 599154530Sdelphij switch(c) { 600154530Sdelphij case 'A': /* sigalrm */ 601154530Sdelphij retry(); 602154530Sdelphij break; 603154530Sdelphij case 'C': /* sigchld */ 604154530Sdelphij reapchild(); 605154530Sdelphij break; 606154530Sdelphij case 'H': /* sighup */ 607154530Sdelphij config(); 608154530Sdelphij break; 609154530Sdelphij } 610154530Sdelphij } 611154530Sdelphij } 612154530Sdelphij for (sep = servtab; n && sep; sep = sep->se_next) 613154530Sdelphij if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 614154530Sdelphij n--; 6151553Srgrimes if (debug) 61629602Scharnier warnx("someone wants %s", sep->se_service); 617101474Sume dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 618101474Sume conn = NULL; 61919618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 62053256Speter i = 1; 62153256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 62253256Speter syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 6231553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62471399Sdwmalone (socklen_t *)0); 6251553Srgrimes if (debug) 62629602Scharnier warnx("accept, ctrl %d", ctrl); 6271553Srgrimes if (ctrl < 0) { 6281553Srgrimes if (errno != EINTR) 6291553Srgrimes syslog(LOG_WARNING, 6301553Srgrimes "accept (for %s): %m", 63137844Sphk sep->se_service); 63237816Sphk if (sep->se_accept && 63337816Sphk sep->se_socktype == SOCK_STREAM) 63437816Sphk close(ctrl); 6351553Srgrimes continue; 6361553Srgrimes } 63753256Speter i = 0; 63853256Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 63953256Speter syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 64053256Speter if (ioctl(ctrl, FIONBIO, &i) < 0) 64153256Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 64230847Sdima if (cpmip(sep, ctrl) < 0) { 64330847Sdima close(ctrl); 64430847Sdima continue; 64530847Sdima } 646101474Sume if (dofork && 647101474Sume (conn = search_conn(sep, ctrl)) != NULL && 648101474Sume !room_conn(sep, conn)) { 649101474Sume close(ctrl); 650101474Sume continue; 651101474Sume } 6521553Srgrimes } else 6531553Srgrimes ctrl = sep->se_fd; 654121766Speter if (dolog && !ISWRAP(sep)) { 65571399Sdwmalone char pname[INET6_ADDRSTRLEN] = "unknown"; 65671399Sdwmalone socklen_t sl; 65771399Sdwmalone sl = sizeof peermax; 65848382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 65971399Sdwmalone &peermax, &sl)) { 66071399Sdwmalone sl = sizeof peermax; 66148382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 66248382Ssheldonh MSG_PEEK, 66356590Sshin (struct sockaddr *)&peermax, 66471399Sdwmalone &sl) >= 0) { 66556590Sshin getnameinfo((struct sockaddr *)&peermax, 66657383Sshin peer.sa_len, 66756590Sshin pname, sizeof(pname), 668146187Sume NULL, 0, NI_NUMERICHOST); 66956590Sshin } 67056590Sshin } else { 67156590Sshin getnameinfo((struct sockaddr *)&peermax, 67257383Sshin peer.sa_len, 67356590Sshin pname, sizeof(pname), 674146187Sume NULL, 0, NI_NUMERICHOST); 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) { 731149432Spjd pidfile_close(pfh); 7321553Srgrimes if (dofork) { 73348962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73448962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 73548962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 73648962Ssheldonh /* SIGPIPE reset before exec */ 7371553Srgrimes } 73835829Sguido /* 73935829Sguido * Call tcpmux to find the real service to exec. 74035829Sguido */ 74135829Sguido if (sep->se_bi && 74278694Sdwmalone sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 74335829Sguido sep = tcpmux(ctrl); 74435829Sguido if (sep == NULL) { 74535829Sguido close(ctrl); 74635829Sguido _exit(0); 74735829Sguido } 74835829Sguido } 74948382Ssheldonh if (ISWRAP(sep)) { 75048698Ssheldonh inetd_setproctitle("wrapping", ctrl); 75147972Ssheldonh service = sep->se_server_name ? 75247972Ssheldonh sep->se_server_name : sep->se_service; 753127865Sdwmalone request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, 0); 75445089Smarkm fromhost(&req); 75547972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 75647972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 75745089Smarkm denied = !hosts_access(&req); 75845089Smarkm if (denied) { 75945089Smarkm syslog(deny_severity, 76096224Sume "refused connection from %.500s, service %s (%s%s)", 76196224Sume eval_client(&req), service, sep->se_proto, 762110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 76348382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 76448382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 76564059Sdwmalone if (dofork) { 76664059Sdwmalone sleep(1); 76748382Ssheldonh _exit(0); 76864059Sdwmalone } 76945089Smarkm } 770121766Speter if (dolog) { 77145089Smarkm syslog(allow_severity, 77296224Sume "connection from %.500s, service %s (%s%s)", 77396224Sume eval_client(&req), service, sep->se_proto, 774110802Sume (whichaf(&req) == AF_INET6) ? "6" : ""); 77545089Smarkm } 77645089Smarkm } 77719617Sjulian if (sep->se_bi) { 7781553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 77919617Sjulian } else { 7801553Srgrimes if (debug) 78129602Scharnier warnx("%d execl %s", 78229602Scharnier getpid(), sep->se_server); 783111324Sdwmalone /* Clear close-on-exec. */ 784111324Sdwmalone if (fcntl(ctrl, F_SETFD, 0) < 0) { 785111324Sdwmalone syslog(LOG_ERR, 786111324Sdwmalone "%s/%s: fcntl (F_SETFD, 0): %m", 787111324Sdwmalone sep->se_service, sep->se_proto); 788111324Sdwmalone _exit(EX_OSERR); 789111324Sdwmalone } 790111324Sdwmalone if (ctrl != 0) { 791111324Sdwmalone dup2(ctrl, 0); 792111324Sdwmalone close(ctrl); 793111324Sdwmalone } 7941553Srgrimes dup2(0, 1); 7951553Srgrimes dup2(0, 2); 7961553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 7971553Srgrimes syslog(LOG_ERR, 79856482Scharnier "%s/%s: %s: no such user", 7991553Srgrimes sep->se_service, sep->se_proto, 8001553Srgrimes sep->se_user); 8011553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8021553Srgrimes recv(0, buf, sizeof (buf), 0); 80319617Sjulian _exit(EX_NOUSER); 8041553Srgrimes } 80530807Sache grp = NULL; 80630807Sache if ( sep->se_group != NULL 80730807Sache && (grp = getgrnam(sep->se_group)) == NULL 80830807Sache ) { 80930807Sache syslog(LOG_ERR, 81056482Scharnier "%s/%s: %s: no such group", 81130807Sache sep->se_service, sep->se_proto, 81230807Sache sep->se_group); 81330807Sache if (sep->se_socktype != SOCK_STREAM) 81430807Sache recv(0, buf, sizeof (buf), 0); 81530807Sache _exit(EX_NOUSER); 81630807Sache } 81730807Sache if (grp != NULL) 81830807Sache pwd->pw_gid = grp->gr_gid; 81921640Speter#ifdef LOGIN_CAP 82030792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 82130792Sache /* error syslogged by getclass */ 82230792Sache syslog(LOG_ERR, 82330792Sache "%s/%s: %s: login class error", 82437850Sache sep->se_service, sep->se_proto, 82537850Sache sep->se_class); 82630792Sache if (sep->se_socktype != SOCK_STREAM) 82730792Sache recv(0, buf, sizeof (buf), 0); 82830792Sache _exit(EX_NOUSER); 82930792Sache } 83021640Speter#endif 83112024Speter if (setsid() < 0) { 83212024Speter syslog(LOG_ERR, 83312024Speter "%s: can't setsid(): %m", 83412024Speter sep->se_service); 83519617Sjulian /* _exit(EX_OSERR); not fatal yet */ 83612024Speter } 83721640Speter#ifdef LOGIN_CAP 83821640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 839109349Srwatson LOGIN_SETALL & ~LOGIN_SETMAC) 840108951Srwatson != 0) { 84121640Speter syslog(LOG_ERR, 84221640Speter "%s: can't setusercontext(..%s..): %m", 84321640Speter sep->se_service, sep->se_user); 84421640Speter _exit(EX_OSERR); 84521640Speter } 846111323Sdwmalone login_close(lc); 84721640Speter#else 8481553Srgrimes if (pwd->pw_uid) { 84912024Speter if (setlogin(sep->se_user) < 0) { 85012024Speter syslog(LOG_ERR, 85112024Speter "%s: can't setlogin(%s): %m", 85212024Speter sep->se_service, sep->se_user); 85319617Sjulian /* _exit(EX_OSERR); not yet */ 85412024Speter } 8551553Srgrimes if (setgid(pwd->pw_gid) < 0) { 8561553Srgrimes syslog(LOG_ERR, 8578857Srgrimes "%s: can't set gid %d: %m", 8581553Srgrimes sep->se_service, pwd->pw_gid); 85919617Sjulian _exit(EX_OSERR); 8601553Srgrimes } 8611553Srgrimes (void) initgroups(pwd->pw_name, 8621553Srgrimes pwd->pw_gid); 8631553Srgrimes if (setuid(pwd->pw_uid) < 0) { 8641553Srgrimes syslog(LOG_ERR, 8658857Srgrimes "%s: can't set uid %d: %m", 8661553Srgrimes sep->se_service, pwd->pw_uid); 86719617Sjulian _exit(EX_OSERR); 8681553Srgrimes } 8691553Srgrimes } 87021640Speter#endif 87135948Sbde sigaction(SIGPIPE, &sapipe, 87235948Sbde (struct sigaction *)0); 8731553Srgrimes execv(sep->se_server, sep->se_argv); 87445089Smarkm syslog(LOG_ERR, 87545089Smarkm "cannot execute %s: %m", sep->se_server); 8761553Srgrimes if (sep->se_socktype != SOCK_STREAM) 8771553Srgrimes recv(0, buf, sizeof (buf), 0); 8781553Srgrimes } 87947972Ssheldonh if (dofork) 88047972Ssheldonh _exit(0); 8811553Srgrimes } 88219618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 8831553Srgrimes close(ctrl); 8841553Srgrimes } 8851553Srgrimes } 8861553Srgrimes} 8871553Srgrimes 88819618Sjulian/* 889154530Sdelphij * Add a signal flag to the signal flag queue for later handling 890154530Sdelphij */ 891154530Sdelphij 892154530Sdelphijvoid 893154530Sdelphijflag_signal(int c) 894154530Sdelphij{ 895154530Sdelphij char ch = c; 896154530Sdelphij 897154530Sdelphij if (write(signalpipe[1], &ch, 1) != 1) { 898154530Sdelphij syslog(LOG_ERR, "write: %m"); 899154530Sdelphij _exit(EX_OSERR); 900154530Sdelphij } 901154530Sdelphij} 902154530Sdelphij 903154530Sdelphij/* 90419618Sjulian * Record a new child pid for this service. If we've reached the 90519618Sjulian * limit on children, then stop accepting incoming requests. 90619618Sjulian */ 90719618Sjulian 9081553Srgrimesvoid 90919618Sjulianaddchild(struct servtab *sep, pid_t pid) 91019618Sjulian{ 911154530Sdelphij if (sep->se_maxchild <= 0) 912154530Sdelphij return; 91319618Sjulian#ifdef SANITY_CHECK 914154530Sdelphij if (sep->se_numchild >= sep->se_maxchild) { 91519618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 916135823Sstefanf __func__, sep->se_numchild, sep->se_maxchild); 91719618Sjulian exit(EX_SOFTWARE); 91819618Sjulian } 91919618Sjulian#endif 920154530Sdelphij sep->se_pids[sep->se_numchild++] = pid; 921154530Sdelphij if (sep->se_numchild == sep->se_maxchild) 92219618Sjulian disable(sep); 92319618Sjulian} 92419618Sjulian 925154530Sdelphij/* 926154530Sdelphij * Some child process has exited. See if it's on somebody's list. 927154530Sdelphij */ 928154530Sdelphij 92919618Sjulianvoid 930154530Sdelphijflag_reapchild(int signo __unused) 931154530Sdelphij{ 932154530Sdelphij flag_signal('C'); 933154530Sdelphij} 934154530Sdelphij 935154530Sdelphijvoid 936154530Sdelphijreapchild(void) 937154530Sdelphij{ 938154530Sdelphij int k, status; 939154530Sdelphij pid_t pid; 940154530Sdelphij struct servtab *sep; 941154530Sdelphij 942154530Sdelphij for (;;) { 943154530Sdelphij pid = wait3(&status, WNOHANG, (struct rusage *)0); 944154530Sdelphij if (pid <= 0) 945154530Sdelphij break; 946154530Sdelphij if (debug) 947154530Sdelphij warnx("%d reaped, %s %u", pid, 948154530Sdelphij WIFEXITED(status) ? "status" : "signal", 949154530Sdelphij WIFEXITED(status) ? WEXITSTATUS(status) 950154530Sdelphij : WTERMSIG(status)); 951154530Sdelphij for (sep = servtab; sep; sep = sep->se_next) { 952154530Sdelphij for (k = 0; k < sep->se_numchild; k++) 953154530Sdelphij if (sep->se_pids[k] == pid) 954154530Sdelphij break; 955154530Sdelphij if (k == sep->se_numchild) 956154530Sdelphij continue; 957154530Sdelphij if (sep->se_numchild == sep->se_maxchild) 958154530Sdelphij enable(sep); 959154530Sdelphij sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 960154530Sdelphij if (WIFSIGNALED(status) || WEXITSTATUS(status)) 961154530Sdelphij syslog(LOG_WARNING, 962154530Sdelphij "%s[%d]: exited, %s %u", 963154530Sdelphij sep->se_server, pid, 964154530Sdelphij WIFEXITED(status) ? "status" : "signal", 965154530Sdelphij WIFEXITED(status) ? WEXITSTATUS(status) 966154530Sdelphij : WTERMSIG(status)); 967154530Sdelphij break; 968154530Sdelphij } 969154530Sdelphij reapchild_conn(pid); 970154530Sdelphij } 971154530Sdelphij} 972154530Sdelphij 973154530Sdelphijvoid 974154530Sdelphijflag_config(int signo __unused) 975154530Sdelphij{ 976154530Sdelphij flag_signal('H'); 977154530Sdelphij} 978154530Sdelphij 979154530Sdelphijvoid 98098558Sjmallettconfig(void) 98142122Sdes{ 98219618Sjulian struct servtab *sep, *new, **sepp; 98342122Sdes long omask; 984100127Salfred int new_nomapped; 985111323Sdwmalone#ifdef LOGIN_CAP 986111323Sdwmalone login_cap_t *lc = NULL; 987111323Sdwmalone#endif 9881553Srgrimes 9891553Srgrimes if (!setconfig()) { 9901553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 9911553Srgrimes return; 9921553Srgrimes } 993154530Sdelphij for (sep = servtab; sep; sep = sep->se_next) 9941553Srgrimes sep->se_checked = 0; 99519618Sjulian while ((new = getconfigent())) { 99630807Sache if (getpwnam(new->se_user) == NULL) { 9971553Srgrimes syslog(LOG_ERR, 99856482Scharnier "%s/%s: no such user '%s', service ignored", 99919618Sjulian new->se_service, new->se_proto, new->se_user); 10001553Srgrimes continue; 10011553Srgrimes } 100230807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 100330807Sache syslog(LOG_ERR, 100456482Scharnier "%s/%s: no such group '%s', service ignored", 100530807Sache new->se_service, new->se_proto, new->se_group); 100630807Sache continue; 100730807Sache } 100830792Sache#ifdef LOGIN_CAP 1009111323Sdwmalone if ((lc = login_getclass(new->se_class)) == NULL) { 101030792Sache /* error syslogged by getclass */ 101130792Sache syslog(LOG_ERR, 101237850Sache "%s/%s: %s: login class error, service ignored", 101337850Sache new->se_service, new->se_proto, new->se_class); 101430792Sache continue; 101530792Sache } 1016111323Sdwmalone login_close(lc); 101730792Sache#endif 1018100127Salfred new_nomapped = new->se_nomapped; 10191553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 102019618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 102156590Sshin strcmp(sep->se_proto, new->se_proto) == 0 && 1022100127Salfred sep->se_rpc == new->se_rpc && 102378356Sdwmalone sep->se_socktype == new->se_socktype && 102456590Sshin sep->se_family == new->se_family) 10251553Srgrimes break; 10261553Srgrimes if (sep != 0) { 10271553Srgrimes int i; 10281553Srgrimes 102998611Sjmallett#define SWAP(t,a, b) { t c = a; a = b; b = c; } 103042122Sdes omask = sigblock(SIGBLOCK); 103156590Sshin if (sep->se_nomapped != new->se_nomapped) { 1032100127Salfred /* for rpc keep old nommaped till unregister */ 1033100127Salfred if (!sep->se_rpc) 1034100127Salfred sep->se_nomapped = new->se_nomapped; 103556590Sshin sep->se_reset = 1; 103656590Sshin } 103719618Sjulian /* copy over outstanding child pids */ 103864197Sdwmalone if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 103919618Sjulian new->se_numchild = sep->se_numchild; 104019618Sjulian if (new->se_numchild > new->se_maxchild) 104119618Sjulian new->se_numchild = new->se_maxchild; 104219618Sjulian memcpy(new->se_pids, sep->se_pids, 104319618Sjulian new->se_numchild * sizeof(*new->se_pids)); 104419618Sjulian } 104598611Sjmallett SWAP(pid_t *, sep->se_pids, new->se_pids); 104619618Sjulian sep->se_maxchild = new->se_maxchild; 104719618Sjulian sep->se_numchild = new->se_numchild; 104830847Sdima sep->se_maxcpm = new->se_maxcpm; 1049101474Sume resize_conn(sep, new->se_maxperip); 1050101474Sume sep->se_maxperip = new->se_maxperip; 105166544Sdwmalone sep->se_bi = new->se_bi; 105219618Sjulian /* might need to turn on or off service now */ 105319618Sjulian if (sep->se_fd >= 0) { 1054154530Sdelphij if (sep->se_maxchild > 0 1055154530Sdelphij && sep->se_numchild == sep->se_maxchild) { 1056154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) 1057154530Sdelphij disable(sep); 1058154530Sdelphij } else { 1059154530Sdelphij if (!FD_ISSET(sep->se_fd, &allsock)) 1060154530Sdelphij enable(sep); 1061154530Sdelphij } 106219618Sjulian } 106319618Sjulian sep->se_accept = new->se_accept; 106498611Sjmallett SWAP(char *, sep->se_user, new->se_user); 106598611Sjmallett SWAP(char *, sep->se_group, new->se_group); 106630792Sache#ifdef LOGIN_CAP 106798611Sjmallett SWAP(char *, sep->se_class, new->se_class); 106830792Sache#endif 106998611Sjmallett SWAP(char *, sep->se_server, new->se_server); 107098611Sjmallett SWAP(char *, sep->se_server_name, new->se_server_name); 10711553Srgrimes for (i = 0; i < MAXARGV; i++) 107298611Sjmallett SWAP(char *, sep->se_argv[i], new->se_argv[i]); 107356590Sshin#ifdef IPSEC 107498611Sjmallett SWAP(char *, sep->se_policy, new->se_policy); 107556590Sshin ipsecsetup(sep); 107656590Sshin#endif 107742122Sdes sigsetmask(omask); 107819618Sjulian freeconfig(new); 10791553Srgrimes if (debug) 10801553Srgrimes print_service("REDO", sep); 10811553Srgrimes } else { 108219618Sjulian sep = enter(new); 10831553Srgrimes if (debug) 10841553Srgrimes print_service("ADD ", sep); 10851553Srgrimes } 10861553Srgrimes sep->se_checked = 1; 10871553Srgrimes if (ISMUX(sep)) { 10881553Srgrimes sep->se_fd = -1; 10891553Srgrimes continue; 10901553Srgrimes } 109156590Sshin switch (sep->se_family) { 109256590Sshin case AF_INET: 1093102938Sdwmalone if (!v4bind_ok) { 109456590Sshin sep->se_fd = -1; 109556590Sshin continue; 109656590Sshin } 109756590Sshin break; 109856590Sshin#ifdef INET6 109956590Sshin case AF_INET6: 1100102938Sdwmalone if (!v6bind_ok) { 110156590Sshin sep->se_fd = -1; 110256590Sshin continue; 110356590Sshin } 110456590Sshin break; 110556590Sshin#endif 110656590Sshin } 11072657Scsgr if (!sep->se_rpc) { 110878356Sdwmalone if (sep->se_family != AF_UNIX) { 110978356Sdwmalone sp = getservbyname(sep->se_service, sep->se_proto); 111078356Sdwmalone if (sp == 0) { 111178356Sdwmalone syslog(LOG_ERR, "%s/%s: unknown service", 111278356Sdwmalone sep->se_service, sep->se_proto); 111378356Sdwmalone sep->se_checked = 0; 111478356Sdwmalone continue; 111578356Sdwmalone } 11162657Scsgr } 111756590Sshin switch (sep->se_family) { 111856590Sshin case AF_INET: 111956590Sshin if (sp->s_port != sep->se_ctrladdr4.sin_port) { 112056590Sshin sep->se_ctrladdr4.sin_port = 112156590Sshin sp->s_port; 112256590Sshin sep->se_reset = 1; 112356590Sshin } 112456590Sshin break; 112556590Sshin#ifdef INET6 112656590Sshin case AF_INET6: 112756590Sshin if (sp->s_port != 112856590Sshin sep->se_ctrladdr6.sin6_port) { 112956590Sshin sep->se_ctrladdr6.sin6_port = 113056590Sshin sp->s_port; 113156590Sshin sep->se_reset = 1; 113256590Sshin } 113356590Sshin break; 113456590Sshin#endif 11352657Scsgr } 113656590Sshin if (sep->se_reset != 0 && sep->se_fd >= 0) 113756590Sshin close_sep(sep); 11382657Scsgr } else { 11392657Scsgr rpc = getrpcbyname(sep->se_service); 11402657Scsgr if (rpc == 0) { 114152219Scharnier syslog(LOG_ERR, "%s/%s unknown RPC service", 11422657Scsgr sep->se_service, sep->se_proto); 11432657Scsgr if (sep->se_fd != -1) 11442657Scsgr (void) close(sep->se_fd); 11452657Scsgr sep->se_fd = -1; 11462657Scsgr continue; 11472657Scsgr } 1148100127Salfred if (sep->se_reset != 0 || 1149100127Salfred rpc->r_number != sep->se_rpc_prog) { 11502657Scsgr if (sep->se_rpc_prog) 11512657Scsgr unregisterrpc(sep); 11522657Scsgr sep->se_rpc_prog = rpc->r_number; 11532657Scsgr if (sep->se_fd != -1) 11542657Scsgr (void) close(sep->se_fd); 11552657Scsgr sep->se_fd = -1; 11562657Scsgr } 1157100127Salfred sep->se_nomapped = new_nomapped; 11581553Srgrimes } 1159100127Salfred sep->se_reset = 0; 11601553Srgrimes if (sep->se_fd == -1) 11611553Srgrimes setup(sep); 11621553Srgrimes } 11631553Srgrimes endconfig(); 11641553Srgrimes /* 11651553Srgrimes * Purge anything not looked at above. 11661553Srgrimes */ 116742122Sdes omask = sigblock(SIGBLOCK); 11681553Srgrimes sepp = &servtab; 116919617Sjulian while ((sep = *sepp)) { 11701553Srgrimes if (sep->se_checked) { 11711553Srgrimes sepp = &sep->se_next; 11721553Srgrimes continue; 11731553Srgrimes } 11741553Srgrimes *sepp = sep->se_next; 11751553Srgrimes if (sep->se_fd >= 0) 11761553Srgrimes close_sep(sep); 11771553Srgrimes if (debug) 11781553Srgrimes print_service("FREE", sep); 11792657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 11802657Scsgr unregisterrpc(sep); 1181154530Sdelphij freeconfig(sep); 1182154530Sdelphij free(sep); 11831553Srgrimes } 118442122Sdes (void) sigsetmask(omask); 11851553Srgrimes} 11861553Srgrimes 11871553Srgrimesvoid 118898558Sjmallettunregisterrpc(struct servtab *sep) 11892657Scsgr{ 119078694Sdwmalone u_int i; 11912657Scsgr struct servtab *sepp; 119242122Sdes long omask; 1193100127Salfred struct netconfig *netid4, *netid6; 11942657Scsgr 119542122Sdes omask = sigblock(SIGBLOCK); 1196100127Salfred netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1197100127Salfred netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1198100127Salfred if (sep->se_family == AF_INET) 1199100127Salfred netid6 = NULL; 1200100127Salfred else if (sep->se_nomapped) 1201100127Salfred netid4 = NULL; 1202100127Salfred /* 1203100127Salfred * Conflict if same prog and protocol - In that case one should look 1204100127Salfred * to versions, but it is not interesting: having separate servers for 1205100127Salfred * different versions does not work well. 1206100127Salfred * Therefore one do not unregister if there is a conflict. 1207100127Salfred * There is also transport conflict if destroying INET when INET46 1208100127Salfred * exists, or destroying INET46 when INET exists 1209100127Salfred */ 12102657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 12112657Scsgr if (sepp == sep) 12122657Scsgr continue; 1213100127Salfred if (sepp->se_checked == 0 || 12142657Scsgr !sepp->se_rpc || 1215100127Salfred strcmp(sep->se_proto, sepp->se_proto) != 0 || 12162657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 12172657Scsgr continue; 1218100127Salfred if (sepp->se_family == AF_INET) 1219100127Salfred netid4 = NULL; 1220100127Salfred if (sepp->se_family == AF_INET6) { 1221100127Salfred netid6 = NULL; 1222100127Salfred if (!sep->se_nomapped) 1223100127Salfred netid4 = NULL; 1224100127Salfred } 1225100127Salfred if (netid4 == NULL && netid6 == NULL) 1226100127Salfred return; 12272657Scsgr } 12282657Scsgr if (debug) 12292657Scsgr print_service("UNREG", sep); 1230100127Salfred for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1231100127Salfred if (netid4) 1232100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid4); 1233100127Salfred if (netid6) 1234100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid6); 1235100127Salfred } 12362657Scsgr if (sep->se_fd != -1) 12372657Scsgr (void) close(sep->se_fd); 12382657Scsgr sep->se_fd = -1; 123942122Sdes (void) sigsetmask(omask); 12402657Scsgr} 12412657Scsgr 12422657Scsgrvoid 1243154530Sdelphijflag_retry(int signo __unused) 1244154530Sdelphij{ 1245154530Sdelphij flag_signal('A'); 1246154530Sdelphij} 1247154530Sdelphij 1248154530Sdelphijvoid 124998558Sjmallettretry(void) 125042122Sdes{ 12511553Srgrimes struct servtab *sep; 12521553Srgrimes 12531553Srgrimes timingout = 0; 12541553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 125519617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 12561553Srgrimes setup(sep); 12571553Srgrimes} 12581553Srgrimes 12591553Srgrimesvoid 126098558Sjmallettsetup(struct servtab *sep) 12611553Srgrimes{ 12621553Srgrimes int on = 1; 12631553Srgrimes 126456590Sshin if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 12651553Srgrimes if (debug) 126629602Scharnier warn("socket failed on %s/%s", 126729602Scharnier sep->se_service, sep->se_proto); 12681553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 12691553Srgrimes sep->se_service, sep->se_proto); 12701553Srgrimes return; 12711553Srgrimes } 1272111324Sdwmalone /* Set all listening sockets to close-on-exec. */ 1273111324Sdwmalone if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) { 1274111324Sdwmalone syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m", 1275111324Sdwmalone sep->se_service, sep->se_proto); 1276111324Sdwmalone close(sep->se_fd); 1277111324Sdwmalone return; 1278111324Sdwmalone } 12791553Srgrimes#define turnon(fd, opt) \ 12801553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 12811553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 1282154530Sdelphij turnon(sep->se_fd, SO_DEBUG) < 0) 12831553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 1284154530Sdelphij if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 12851553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 128625253Swollman#ifdef SO_PRIVSTATE 1287154530Sdelphij if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 128813956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 128925253Swollman#endif 129056590Sshin /* tftpd opens a new connection then needs more infos */ 129156590Sshin if ((sep->se_family == AF_INET6) && 129256590Sshin (strcmp(sep->se_proto, "udp") == 0) && 129356590Sshin (sep->se_accept == 0) && 1294121559Sume (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1295154530Sdelphij (char *)&on, sizeof (on)) < 0)) 129656590Sshin syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 129758935Sume if (sep->se_family == AF_INET6) { 129858935Sume int flag = sep->se_nomapped ? 1 : 0; 1299100505Sume if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 130058935Sume (char *)&flag, sizeof (flag)) < 0) 1301100505Sume syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 130258935Sume } 13031553Srgrimes#undef turnon 130436042Sguido if (sep->se_type == TTCP_TYPE) 130536042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 130636042Sguido (char *)&on, sizeof (on)) < 0) 130736042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 130856590Sshin#ifdef IPV6_FAITH 130956590Sshin if (sep->se_type == FAITH_TYPE) { 131056590Sshin if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 131156590Sshin sizeof(on)) < 0) { 131256590Sshin syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 131356590Sshin } 131456590Sshin } 131556590Sshin#endif 131656590Sshin#ifdef IPSEC 131756590Sshin ipsecsetup(sep); 131856590Sshin#endif 131978356Sdwmalone if (sep->se_family == AF_UNIX) { 132078356Sdwmalone (void) unlink(sep->se_ctrladdr_un.sun_path); 132178356Sdwmalone umask(0777); /* Make socket with conservative permissions */ 132278356Sdwmalone } 13231553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 132456590Sshin sep->se_ctrladdr_size) < 0) { 13251553Srgrimes if (debug) 132629602Scharnier warn("bind failed on %s/%s", 132729602Scharnier sep->se_service, sep->se_proto); 13281553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 13291553Srgrimes sep->se_service, sep->se_proto); 13301553Srgrimes (void) close(sep->se_fd); 13311553Srgrimes sep->se_fd = -1; 13321553Srgrimes if (!timingout) { 13331553Srgrimes timingout = 1; 13341553Srgrimes alarm(RETRYTIME); 13351553Srgrimes } 133678356Sdwmalone if (sep->se_family == AF_UNIX) 133778356Sdwmalone umask(mask); 13381553Srgrimes return; 13391553Srgrimes } 134078356Sdwmalone if (sep->se_family == AF_UNIX) { 134178356Sdwmalone /* Ick - fch{own,mod} don't work on Unix domain sockets */ 134278356Sdwmalone if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 134378356Sdwmalone syslog(LOG_ERR, "chown socket: %m"); 134478356Sdwmalone if (chmod(sep->se_service, sep->se_sockmode) < 0) 134578356Sdwmalone syslog(LOG_ERR, "chmod socket: %m"); 134678356Sdwmalone umask(mask); 134778356Sdwmalone } 13482657Scsgr if (sep->se_rpc) { 134978694Sdwmalone u_int i; 135071399Sdwmalone socklen_t len = sep->se_ctrladdr_size; 1351100127Salfred struct netconfig *netid, *netid2 = NULL; 1352100127Salfred struct sockaddr_in sock; 1353100127Salfred struct netbuf nbuf, nbuf2; 13542657Scsgr 13558857Srgrimes if (getsockname(sep->se_fd, 13562657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 13572657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 13582657Scsgr sep->se_service, sep->se_proto); 13592657Scsgr (void) close(sep->se_fd); 13602657Scsgr sep->se_fd = -1; 13618857Srgrimes return; 13622657Scsgr } 1363100127Salfred nbuf.buf = &sep->se_ctrladdr; 1364100127Salfred nbuf.len = sep->se_ctrladdr.sa_len; 1365100127Salfred if (sep->se_family == AF_INET) 1366100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1367100127Salfred else { 1368100127Salfred netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1369100127Salfred if (!sep->se_nomapped) { /* INET and INET6 */ 1370100127Salfred netid2 = netid==udp6conf? udpconf:tcpconf; 1371100127Salfred memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1372100127Salfred nbuf2.buf = &sock; 1373100127Salfred nbuf2.len = sock.sin_len = sizeof sock; 1374100127Salfred sock.sin_family = AF_INET; 1375100127Salfred sock.sin_port = sep->se_ctrladdr6.sin6_port; 1376100127Salfred } 1377100127Salfred } 13782657Scsgr if (debug) 13792657Scsgr print_service("REG ", sep); 13802657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1381100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid); 1382100127Salfred rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1383100127Salfred if (netid2) { 1384100127Salfred rpcb_unset(sep->se_rpc_prog, i, netid2); 1385100127Salfred rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1386100127Salfred } 13872657Scsgr } 13882657Scsgr } 13891553Srgrimes if (sep->se_socktype == SOCK_STREAM) 139017197Sdg listen(sep->se_fd, 64); 139119618Sjulian enable(sep); 13921553Srgrimes if (debug) { 139329602Scharnier warnx("registered %s on %d", 13941553Srgrimes sep->se_server, sep->se_fd); 13951553Srgrimes } 13961553Srgrimes} 13971553Srgrimes 139856590Sshin#ifdef IPSEC 139956590Sshinvoid 1400154530Sdelphijipsecsetup(sep) 1401154530Sdelphij struct servtab *sep; 140256590Sshin{ 140356590Sshin char *buf; 140456590Sshin char *policy_in = NULL; 140556590Sshin char *policy_out = NULL; 140656590Sshin int level; 140756590Sshin int opt; 140856590Sshin 140956590Sshin switch (sep->se_family) { 141056590Sshin case AF_INET: 141156590Sshin level = IPPROTO_IP; 141256590Sshin opt = IP_IPSEC_POLICY; 141356590Sshin break; 141456590Sshin#ifdef INET6 141556590Sshin case AF_INET6: 141656590Sshin level = IPPROTO_IPV6; 141756590Sshin opt = IPV6_IPSEC_POLICY; 141856590Sshin break; 141956590Sshin#endif 142056590Sshin default: 142156590Sshin return; 142256590Sshin } 142356590Sshin 142456590Sshin if (!sep->se_policy || sep->se_policy[0] == '\0') { 142578694Sdwmalone static char def_in[] = "in entrust", def_out[] = "out entrust"; 142678694Sdwmalone policy_in = def_in; 142778694Sdwmalone policy_out = def_out; 142856590Sshin } else { 142956590Sshin if (!strncmp("in", sep->se_policy, 2)) 143056590Sshin policy_in = sep->se_policy; 143156590Sshin else if (!strncmp("out", sep->se_policy, 3)) 143256590Sshin policy_out = sep->se_policy; 143356590Sshin else { 143456590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 143556590Sshin sep->se_policy); 143656590Sshin return; 143756590Sshin } 143856590Sshin } 143956590Sshin 144056590Sshin if (policy_in != NULL) { 144156590Sshin buf = ipsec_set_policy(policy_in, strlen(policy_in)); 144256590Sshin if (buf != NULL) { 144356590Sshin if (setsockopt(sep->se_fd, level, opt, 144456675Sshin buf, ipsec_get_policylen(buf)) < 0 && 144556759Sshin debug != 0) 144656759Sshin warnx("%s/%s: ipsec initialization failed; %s", 144756759Sshin sep->se_service, sep->se_proto, 144856759Sshin policy_in); 144956590Sshin free(buf); 145056590Sshin } else 145156590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 145256590Sshin policy_in); 145356590Sshin } 145456590Sshin if (policy_out != NULL) { 145556590Sshin buf = ipsec_set_policy(policy_out, strlen(policy_out)); 145656590Sshin if (buf != NULL) { 145756590Sshin if (setsockopt(sep->se_fd, level, opt, 145856675Sshin buf, ipsec_get_policylen(buf)) < 0 && 145956759Sshin debug != 0) 146056759Sshin warnx("%s/%s: ipsec initialization failed; %s", 146156759Sshin sep->se_service, sep->se_proto, 146256759Sshin policy_out); 146356590Sshin free(buf); 146456590Sshin } else 146556590Sshin syslog(LOG_ERR, "invalid security policy \"%s\"", 146656590Sshin policy_out); 146756590Sshin } 146856590Sshin} 146956590Sshin#endif 147056590Sshin 14711553Srgrimes/* 14721553Srgrimes * Finish with a service and its socket. 14731553Srgrimes */ 14741553Srgrimesvoid 147598558Sjmallettclose_sep(struct servtab *sep) 14761553Srgrimes{ 14771553Srgrimes if (sep->se_fd >= 0) { 1478154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) 1479154530Sdelphij disable(sep); 14801553Srgrimes (void) close(sep->se_fd); 14811553Srgrimes sep->se_fd = -1; 14821553Srgrimes } 14831553Srgrimes sep->se_count = 0; 148419618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 14851553Srgrimes} 14861553Srgrimes 148748467Ssheldonhint 148898558Sjmallettmatchservent(const char *name1, const char *name2, const char *proto) 148948467Ssheldonh{ 149078356Sdwmalone char **alias, *p; 149148467Ssheldonh struct servent *se; 149248467Ssheldonh 149378356Sdwmalone if (strcmp(proto, "unix") == 0) { 149478356Sdwmalone if ((p = strrchr(name1, '/')) != NULL) 149578356Sdwmalone name1 = p + 1; 149678356Sdwmalone if ((p = strrchr(name2, '/')) != NULL) 149778356Sdwmalone name2 = p + 1; 149878356Sdwmalone } 149949026Sdes if (strcmp(name1, name2) == 0) 150049026Sdes return(1); 150148467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 150248467Ssheldonh if (strcmp(name2, se->s_name) == 0) 150348467Ssheldonh return(1); 150448467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 150548467Ssheldonh if (strcmp(name2, *alias) == 0) 150648467Ssheldonh return(1); 150748467Ssheldonh } 150848467Ssheldonh return(0); 150948467Ssheldonh} 151048467Ssheldonh 15111553Srgrimesstruct servtab * 151298558Sjmallettenter(struct servtab *cp) 15131553Srgrimes{ 15141553Srgrimes struct servtab *sep; 151542122Sdes long omask; 15161553Srgrimes 15171553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 1518154530Sdelphij if (sep == (struct servtab *)0) { 151949102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 152019617Sjulian exit(EX_OSERR); 15211553Srgrimes } 15221553Srgrimes *sep = *cp; 15231553Srgrimes sep->se_fd = -1; 152442122Sdes omask = sigblock(SIGBLOCK); 15251553Srgrimes sep->se_next = servtab; 15261553Srgrimes servtab = sep; 152742122Sdes sigsetmask(omask); 15281553Srgrimes return (sep); 15291553Srgrimes} 15301553Srgrimes 153119618Sjulianvoid 153298558Sjmallettenable(struct servtab *sep) 153319618Sjulian{ 153419618Sjulian if (debug) 153529602Scharnier warnx( 153619618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 153719618Sjulian#ifdef SANITY_CHECK 153819618Sjulian if (sep->se_fd < 0) { 153919618Sjulian syslog(LOG_ERR, 1540135823Sstefanf "%s: %s: bad fd", __func__, sep->se_service); 154119618Sjulian exit(EX_SOFTWARE); 154219618Sjulian } 154319618Sjulian if (ISMUX(sep)) { 154419618Sjulian syslog(LOG_ERR, 1545135823Sstefanf "%s: %s: is mux", __func__, sep->se_service); 154619618Sjulian exit(EX_SOFTWARE); 154719618Sjulian } 1548154530Sdelphij if (FD_ISSET(sep->se_fd, &allsock)) { 1549154530Sdelphij syslog(LOG_ERR, 1550154530Sdelphij "%s: %s: not off", __func__, sep->se_service); 1551154530Sdelphij exit(EX_SOFTWARE); 1552154530Sdelphij } 155348991Ssheldonh nsock++; 155419618Sjulian#endif 1555154530Sdelphij FD_SET(sep->se_fd, &allsock); 155619618Sjulian if (sep->se_fd > maxsock) 155719618Sjulian maxsock = sep->se_fd; 155819618Sjulian} 155919618Sjulian 156019618Sjulianvoid 156198558Sjmallettdisable(struct servtab *sep) 156219618Sjulian{ 156319618Sjulian if (debug) 156429602Scharnier warnx( 156519618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 156619618Sjulian#ifdef SANITY_CHECK 156719618Sjulian if (sep->se_fd < 0) { 156819618Sjulian syslog(LOG_ERR, 1569135823Sstefanf "%s: %s: bad fd", __func__, sep->se_service); 157019618Sjulian exit(EX_SOFTWARE); 157119618Sjulian } 157219618Sjulian if (ISMUX(sep)) { 157319618Sjulian syslog(LOG_ERR, 1574135823Sstefanf "%s: %s: is mux", __func__, sep->se_service); 157519618Sjulian exit(EX_SOFTWARE); 157619618Sjulian } 1577154530Sdelphij if (!FD_ISSET(sep->se_fd, &allsock)) { 1578154530Sdelphij syslog(LOG_ERR, 1579154530Sdelphij "%s: %s: not on", __func__, sep->se_service); 1580154530Sdelphij exit(EX_SOFTWARE); 1581154530Sdelphij } 158219618Sjulian if (nsock == 0) { 1583135823Sstefanf syslog(LOG_ERR, "%s: nsock=0", __func__); 158419618Sjulian exit(EX_SOFTWARE); 158519618Sjulian } 158648991Ssheldonh nsock--; 158719618Sjulian#endif 1588154530Sdelphij FD_CLR(sep->se_fd, &allsock); 158919618Sjulian if (sep->se_fd == maxsock) 159019618Sjulian maxsock--; 159119618Sjulian} 159219618Sjulian 15931553SrgrimesFILE *fconfig = NULL; 15941553Srgrimesstruct servtab serv; 15951553Srgrimeschar line[LINE_MAX]; 15961553Srgrimes 15971553Srgrimesint 159898558Sjmallettsetconfig(void) 15991553Srgrimes{ 16001553Srgrimes 16011553Srgrimes if (fconfig != NULL) { 16021553Srgrimes fseek(fconfig, 0L, SEEK_SET); 16031553Srgrimes return (1); 16041553Srgrimes } 16051553Srgrimes fconfig = fopen(CONFIG, "r"); 16061553Srgrimes return (fconfig != NULL); 16071553Srgrimes} 16081553Srgrimes 16091553Srgrimesvoid 161098558Sjmallettendconfig(void) 16111553Srgrimes{ 16121553Srgrimes if (fconfig) { 16131553Srgrimes (void) fclose(fconfig); 16141553Srgrimes fconfig = NULL; 16151553Srgrimes } 16161553Srgrimes} 16171553Srgrimes 16181553Srgrimesstruct servtab * 161998558Sjmallettgetconfigent(void) 16201553Srgrimes{ 16211553Srgrimes struct servtab *sep = &serv; 16221553Srgrimes int argc; 162319618Sjulian char *cp, *arg, *s; 16242657Scsgr char *versp; 16251553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 16261553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 162756590Sshin#ifdef IPSEC 1628102861Sdwmalone char *policy; 162956590Sshin#endif 1630102861Sdwmalone int v4bind; 163156590Sshin#ifdef INET6 1632102861Sdwmalone int v6bind; 163356590Sshin#endif 1634101474Sume int i; 16351553Srgrimes 1636102861Sdwmalone#ifdef IPSEC 1637102861Sdwmalone policy = NULL; 1638102861Sdwmalone#endif 16391553Srgrimesmore: 1640102861Sdwmalone v4bind = 0; 1641102861Sdwmalone#ifdef INET6 1642102861Sdwmalone v6bind = 0; 1643102861Sdwmalone#endif 164456590Sshin while ((cp = nextline(fconfig)) != NULL) { 164556590Sshin#ifdef IPSEC 164656590Sshin /* lines starting with #@ is not a comment, but the policy */ 164756590Sshin if (cp[0] == '#' && cp[1] == '@') { 164856590Sshin char *p; 164956590Sshin for (p = cp + 2; p && *p && isspace(*p); p++) 165056590Sshin ; 165156590Sshin if (*p == '\0') { 1652154530Sdelphij if (policy) 1653154530Sdelphij free(policy); 165456590Sshin policy = NULL; 165556590Sshin } else if (ipsec_get_policylen(p) >= 0) { 1656154530Sdelphij if (policy) 1657154530Sdelphij free(policy); 165856590Sshin policy = newstr(p); 165956590Sshin } else { 166056590Sshin syslog(LOG_ERR, 166156590Sshin "%s: invalid ipsec policy \"%s\"", 166256590Sshin CONFIG, p); 166356590Sshin exit(EX_CONFIG); 166456590Sshin } 166556590Sshin } 166656590Sshin#endif 166756590Sshin if (*cp == '#' || *cp == '\0') 166856590Sshin continue; 166956590Sshin break; 167056590Sshin } 16711553Srgrimes if (cp == NULL) 16721553Srgrimes return ((struct servtab *)0); 16731553Srgrimes /* 16741553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 16751553Srgrimes * for example) don't get initialized here. 16761553Srgrimes */ 167771399Sdwmalone memset(sep, 0, sizeof *sep); 16781553Srgrimes arg = skip(&cp); 16791553Srgrimes if (cp == NULL) { 16801553Srgrimes /* got an empty line containing just blanks/tabs. */ 16811553Srgrimes goto more; 16821553Srgrimes } 168378356Sdwmalone if (arg[0] == ':') { /* :user:group:perm: */ 168478356Sdwmalone char *user, *group, *perm; 168578356Sdwmalone struct passwd *pw; 168678356Sdwmalone struct group *gr; 168778356Sdwmalone user = arg+1; 168878356Sdwmalone if ((group = strchr(user, ':')) == NULL) { 168978356Sdwmalone syslog(LOG_ERR, "no group after user '%s'", user); 169078356Sdwmalone goto more; 169178356Sdwmalone } 169278356Sdwmalone *group++ = '\0'; 169378356Sdwmalone if ((perm = strchr(group, ':')) == NULL) { 169478356Sdwmalone syslog(LOG_ERR, "no mode after group '%s'", group); 169578356Sdwmalone goto more; 169678356Sdwmalone } 169778356Sdwmalone *perm++ = '\0'; 169878356Sdwmalone if ((pw = getpwnam(user)) == NULL) { 169978356Sdwmalone syslog(LOG_ERR, "no such user '%s'", user); 170078356Sdwmalone goto more; 170178356Sdwmalone } 170278356Sdwmalone sep->se_sockuid = pw->pw_uid; 170378356Sdwmalone if ((gr = getgrnam(group)) == NULL) { 170478356Sdwmalone syslog(LOG_ERR, "no such user '%s'", group); 170578356Sdwmalone goto more; 170678356Sdwmalone } 170778356Sdwmalone sep->se_sockgid = gr->gr_gid; 170878356Sdwmalone sep->se_sockmode = strtol(perm, &arg, 8); 170978356Sdwmalone if (*arg != ':') { 171078356Sdwmalone syslog(LOG_ERR, "bad mode '%s'", perm); 171178356Sdwmalone goto more; 171278356Sdwmalone } 171378356Sdwmalone *arg++ = '\0'; 171478356Sdwmalone } else { 171578356Sdwmalone sep->se_sockuid = euid; 171678356Sdwmalone sep->se_sockgid = egid; 171778356Sdwmalone sep->se_sockmode = 0200; 171878356Sdwmalone } 17191553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 17201553Srgrimes char *c = arg + MUX_LEN; 17211553Srgrimes if (*c == '+') { 17221553Srgrimes sep->se_type = MUXPLUS_TYPE; 17231553Srgrimes c++; 17241553Srgrimes } else 17251553Srgrimes sep->se_type = MUX_TYPE; 17261553Srgrimes sep->se_service = newstr(c); 17271553Srgrimes } else { 17281553Srgrimes sep->se_service = newstr(arg); 17291553Srgrimes sep->se_type = NORM_TYPE; 17301553Srgrimes } 17311553Srgrimes arg = sskip(&cp); 17321553Srgrimes if (strcmp(arg, "stream") == 0) 17331553Srgrimes sep->se_socktype = SOCK_STREAM; 17341553Srgrimes else if (strcmp(arg, "dgram") == 0) 17351553Srgrimes sep->se_socktype = SOCK_DGRAM; 17361553Srgrimes else if (strcmp(arg, "rdm") == 0) 17371553Srgrimes sep->se_socktype = SOCK_RDM; 17381553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 17391553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 17401553Srgrimes else if (strcmp(arg, "raw") == 0) 17411553Srgrimes sep->se_socktype = SOCK_RAW; 17421553Srgrimes else 17431553Srgrimes sep->se_socktype = -1; 174436042Sguido 174536042Sguido arg = sskip(&cp); 174656590Sshin if (strncmp(arg, "tcp", 3) == 0) { 174756590Sshin sep->se_proto = newstr(strsep(&arg, "/")); 174856590Sshin if (arg != NULL) { 174956590Sshin if (strcmp(arg, "ttcp") == 0) 175056590Sshin sep->se_type = TTCP_TYPE; 175156590Sshin else if (strcmp(arg, "faith") == 0) 175256590Sshin sep->se_type = FAITH_TYPE; 175356590Sshin } 175477518Sume } else { 175577518Sume if (sep->se_type == NORM_TYPE && 175677518Sume strncmp(arg, "faith/", 6) == 0) { 175777518Sume arg += 6; 175877518Sume sep->se_type = FAITH_TYPE; 175977518Sume } 176036042Sguido sep->se_proto = newstr(arg); 176177518Sume } 17622657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 176319237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 176419237Sjoerg strlen(sep->se_proto) + 1 - 4); 17652657Scsgr sep->se_rpc = 1; 17662657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 17672657Scsgr sep->se_rpc_lowvers = 0; 176856590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 176956590Sshin sizeof(sep->se_ctrladdr4)); 17702657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 17712657Scsgr *versp++ = '\0'; 1772102859Sdwmalone switch (sscanf(versp, "%u-%u", 17732657Scsgr &sep->se_rpc_lowvers, 17742657Scsgr &sep->se_rpc_highvers)) { 17752657Scsgr case 2: 17762657Scsgr break; 17772657Scsgr case 1: 17782657Scsgr sep->se_rpc_highvers = 17792657Scsgr sep->se_rpc_lowvers; 17802657Scsgr break; 17812657Scsgr default: 17828857Srgrimes syslog(LOG_ERR, 178352219Scharnier "bad RPC version specifier; %s", 17842657Scsgr sep->se_service); 17852657Scsgr freeconfig(sep); 17862657Scsgr goto more; 17872657Scsgr } 17882657Scsgr } 17892657Scsgr else { 17902657Scsgr sep->se_rpc_lowvers = 17912657Scsgr sep->se_rpc_highvers = 1; 17922657Scsgr } 17932657Scsgr } 179456590Sshin sep->se_nomapped = 0; 179578356Sdwmalone if (strcmp(sep->se_proto, "unix") == 0) { 179678356Sdwmalone sep->se_family = AF_UNIX; 1797102937Sdwmalone } else { 1798102937Sdwmalone while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 179956590Sshin#ifdef INET6 1800102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1801102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1802102937Sdwmalone v6bind = 1; 1803102937Sdwmalone continue; 1804102937Sdwmalone } 1805102937Sdwmalone#endif 1806102937Sdwmalone if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1807102937Sdwmalone sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1808102937Sdwmalone v4bind = 1; 1809102937Sdwmalone continue; 1810102937Sdwmalone } 1811102937Sdwmalone /* illegal version num */ 1812102937Sdwmalone syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1813100127Salfred freeconfig(sep); 1814100127Salfred goto more; 1815100127Salfred } 1816102937Sdwmalone#ifdef INET6 1817102938Sdwmalone if (v6bind && !v6bind_ok) { 1818102937Sdwmalone syslog(LOG_INFO, "IPv6 bind is ignored for %s", 181956590Sshin sep->se_service); 1820102938Sdwmalone if (v4bind && v4bind_ok) 1821102937Sdwmalone v6bind = 0; 1822102937Sdwmalone else { 1823102937Sdwmalone freeconfig(sep); 1824102937Sdwmalone goto more; 1825102937Sdwmalone } 182656590Sshin } 1827102938Sdwmalone if (v6bind) { 1828102937Sdwmalone sep->se_family = AF_INET6; 1829102938Sdwmalone if (!v4bind || !v4bind_ok) 1830102937Sdwmalone sep->se_nomapped = 1; 1831102937Sdwmalone } else 1832102937Sdwmalone#endif 1833102937Sdwmalone { /* default to v4 bind if not v6 bind */ 1834102938Sdwmalone if (!v4bind_ok) { 1835102937Sdwmalone syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1836102937Sdwmalone sep->se_service); 1837102937Sdwmalone freeconfig(sep); 1838102937Sdwmalone goto more; 1839102937Sdwmalone } 1840102937Sdwmalone sep->se_family = AF_INET; 1841102937Sdwmalone } 184256590Sshin } 184356590Sshin /* init ctladdr */ 184456590Sshin switch(sep->se_family) { 184556590Sshin case AF_INET: 184656590Sshin memcpy(&sep->se_ctrladdr4, bind_sa4, 184756590Sshin sizeof(sep->se_ctrladdr4)); 184856590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 184956590Sshin break; 185056590Sshin#ifdef INET6 185156590Sshin case AF_INET6: 185256590Sshin memcpy(&sep->se_ctrladdr6, bind_sa6, 185356590Sshin sizeof(sep->se_ctrladdr6)); 185456590Sshin sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 185556590Sshin break; 185656590Sshin#endif 185778356Sdwmalone case AF_UNIX: 185878356Sdwmalone if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 185978356Sdwmalone syslog(LOG_ERR, 186078356Sdwmalone "domain socket pathname too long for service %s", 186178356Sdwmalone sep->se_service); 186278356Sdwmalone goto more; 186378356Sdwmalone } 186478356Sdwmalone memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 186578356Sdwmalone sep->se_ctrladdr_un.sun_family = sep->se_family; 186678356Sdwmalone sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 186778356Sdwmalone strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 186878356Sdwmalone sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 186956590Sshin } 18701553Srgrimes arg = sskip(&cp); 187119618Sjulian if (!strncmp(arg, "wait", 4)) 187219618Sjulian sep->se_accept = 0; 187319618Sjulian else if (!strncmp(arg, "nowait", 6)) 187419618Sjulian sep->se_accept = 1; 187519618Sjulian else { 187619618Sjulian syslog(LOG_ERR, 187719618Sjulian "%s: bad wait/nowait for service %s", 187819618Sjulian CONFIG, sep->se_service); 187919618Sjulian goto more; 188019618Sjulian } 188148069Ssheldonh sep->se_maxchild = -1; 188248069Ssheldonh sep->se_maxcpm = -1; 1883101474Sume sep->se_maxperip = -1; 188419618Sjulian if ((s = strchr(arg, '/')) != NULL) { 188519618Sjulian char *eptr; 188619618Sjulian u_long val; 188719618Sjulian 188819618Sjulian val = strtoul(s + 1, &eptr, 10); 188930847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 189019618Sjulian syslog(LOG_ERR, 189119618Sjulian "%s: bad max-child for service %s", 189219618Sjulian CONFIG, sep->se_service); 189319618Sjulian goto more; 189419618Sjulian } 189548069Ssheldonh if (debug) 189648069Ssheldonh if (!sep->se_accept && val != 1) 189748069Ssheldonh warnx("maxchild=%lu for wait service %s" 189848069Ssheldonh " not recommended", val, sep->se_service); 189919618Sjulian sep->se_maxchild = val; 190030847Sdima if (*eptr == '/') 190130847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1902101474Sume if (*eptr == '/') 1903101474Sume sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 190430847Sdima /* 190530847Sdima * explicitly do not check for \0 for future expansion / 190630847Sdima * backwards compatibility 190730847Sdima */ 190819618Sjulian } 19091553Srgrimes if (ISMUX(sep)) { 19101553Srgrimes /* 191119618Sjulian * Silently enforce "nowait" mode for TCPMUX services 191219618Sjulian * since they don't have an assigned port to listen on. 19131553Srgrimes */ 191419618Sjulian sep->se_accept = 1; 19151553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 19168857Srgrimes syslog(LOG_ERR, 19171553Srgrimes "%s: bad protocol for tcpmux service %s", 19181553Srgrimes CONFIG, sep->se_service); 19191553Srgrimes goto more; 19201553Srgrimes } 19211553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 19228857Srgrimes syslog(LOG_ERR, 19231553Srgrimes "%s: bad socket type for tcpmux service %s", 19241553Srgrimes CONFIG, sep->se_service); 19251553Srgrimes goto more; 19261553Srgrimes } 19271553Srgrimes } 19281553Srgrimes sep->se_user = newstr(sskip(&cp)); 192930792Sache#ifdef LOGIN_CAP 193030792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 193130792Sache *s = '\0'; 193230792Sache sep->se_class = newstr(s + 1); 193330792Sache } else 193430792Sache sep->se_class = newstr(RESOURCE_RC); 193530792Sache#endif 193630807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 193730807Sache *s = '\0'; 193830807Sache sep->se_group = newstr(s + 1); 193930807Sache } else 194030807Sache sep->se_group = NULL; 19411553Srgrimes sep->se_server = newstr(sskip(&cp)); 194245588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 194345588Smarkm sep->se_server_name++; 19441553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 19451553Srgrimes struct biltin *bi; 19461553Srgrimes 19471553Srgrimes for (bi = biltins; bi->bi_service; bi++) 194849026Sdes if (bi->bi_socktype == sep->se_socktype && 194948467Ssheldonh matchservent(bi->bi_service, sep->se_service, 195048467Ssheldonh sep->se_proto)) 19511553Srgrimes break; 19521553Srgrimes if (bi->bi_service == 0) { 19531553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 19541553Srgrimes sep->se_service); 19551553Srgrimes goto more; 19561553Srgrimes } 195719618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 19581553Srgrimes sep->se_bi = bi; 19591553Srgrimes } else 19601553Srgrimes sep->se_bi = NULL; 1961101474Sume if (sep->se_maxperip < 0) 1962101474Sume sep->se_maxperip = maxperip; 196348069Ssheldonh if (sep->se_maxcpm < 0) 196448069Ssheldonh sep->se_maxcpm = maxcpm; 196545588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 196648069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 196719618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 196848069Ssheldonh else if (sep->se_accept) 196948069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 197019618Sjulian else 197148069Ssheldonh sep->se_maxchild = 1; 197245588Smarkm } 197364197Sdwmalone if (sep->se_maxchild > 0) { 197419618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 197519618Sjulian if (sep->se_pids == NULL) { 197649102Ssheldonh syslog(LOG_ERR, "malloc: %m"); 197719618Sjulian exit(EX_OSERR); 197819618Sjulian } 197919618Sjulian } 19801553Srgrimes argc = 0; 19811553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 198219618Sjulian if (argc < MAXARGV) { 19831553Srgrimes sep->se_argv[argc++] = newstr(arg); 198419618Sjulian } else { 198519618Sjulian syslog(LOG_ERR, 198619618Sjulian "%s: too many arguments for service %s", 198719618Sjulian CONFIG, sep->se_service); 198819618Sjulian goto more; 198919618Sjulian } 19901553Srgrimes while (argc <= MAXARGV) 19911553Srgrimes sep->se_argv[argc++] = NULL; 1992101474Sume for (i = 0; i < PERIPSIZE; ++i) 1993101474Sume LIST_INIT(&sep->se_conn[i]); 199456590Sshin#ifdef IPSEC 199556590Sshin sep->se_policy = policy ? newstr(policy) : NULL; 199656590Sshin#endif 19971553Srgrimes return (sep); 19981553Srgrimes} 19991553Srgrimes 20001553Srgrimesvoid 200198558Sjmallettfreeconfig(struct servtab *cp) 20021553Srgrimes{ 20031553Srgrimes int i; 20041553Srgrimes 2005154530Sdelphij if (cp->se_service) 2006154530Sdelphij free(cp->se_service); 2007154530Sdelphij if (cp->se_proto) 2008154530Sdelphij free(cp->se_proto); 2009154530Sdelphij if (cp->se_user) 2010154530Sdelphij free(cp->se_user); 2011154530Sdelphij if (cp->se_group) 2012154530Sdelphij free(cp->se_group); 201330792Sache#ifdef LOGIN_CAP 2014154530Sdelphij if (cp->se_class) 2015154530Sdelphij free(cp->se_class); 201630792Sache#endif 2017154530Sdelphij if (cp->se_server) 2018154530Sdelphij free(cp->se_server); 2019154530Sdelphij if (cp->se_pids) 2020154530Sdelphij free(cp->se_pids); 20211553Srgrimes for (i = 0; i < MAXARGV; i++) 2022154530Sdelphij if (cp->se_argv[i]) 2023154530Sdelphij free(cp->se_argv[i]); 2024101474Sume free_connlist(cp); 202556590Sshin#ifdef IPSEC 2026154530Sdelphij if (cp->se_policy) 2027154530Sdelphij free(cp->se_policy); 202856590Sshin#endif 20291553Srgrimes} 20301553Srgrimes 20311553Srgrimes 20321553Srgrimes/* 20331553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 20341553Srgrimes * configuration file and exit. 20351553Srgrimes */ 20361553Srgrimeschar * 203798558Sjmallettsskip(char **cpp) 20381553Srgrimes{ 20391553Srgrimes char *cp; 20401553Srgrimes 20411553Srgrimes cp = skip(cpp); 20421553Srgrimes if (cp == NULL) { 20431553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 204419617Sjulian exit(EX_DATAERR); 20451553Srgrimes } 20461553Srgrimes return (cp); 20471553Srgrimes} 20481553Srgrimes 20491553Srgrimeschar * 205098558Sjmallettskip(char **cpp) 20511553Srgrimes{ 20521553Srgrimes char *cp = *cpp; 20531553Srgrimes char *start; 205411933Sadam char quote = '\0'; 20551553Srgrimes 20561553Srgrimesagain: 20571553Srgrimes while (*cp == ' ' || *cp == '\t') 20581553Srgrimes cp++; 20591553Srgrimes if (*cp == '\0') { 20601553Srgrimes int c; 20611553Srgrimes 20621553Srgrimes c = getc(fconfig); 20631553Srgrimes (void) ungetc(c, fconfig); 20641553Srgrimes if (c == ' ' || c == '\t') 206519617Sjulian if ((cp = nextline(fconfig))) 20661553Srgrimes goto again; 20671553Srgrimes *cpp = (char *)0; 20681553Srgrimes return ((char *)0); 20691553Srgrimes } 207011933Sadam if (*cp == '"' || *cp == '\'') 207111933Sadam quote = *cp++; 20721553Srgrimes start = cp; 207311933Sadam if (quote) 207411933Sadam while (*cp && *cp != quote) 207511933Sadam cp++; 207611933Sadam else 207711933Sadam while (*cp && *cp != ' ' && *cp != '\t') 207811933Sadam cp++; 20791553Srgrimes if (*cp != '\0') 20801553Srgrimes *cp++ = '\0'; 20811553Srgrimes *cpp = cp; 20821553Srgrimes return (start); 20831553Srgrimes} 20841553Srgrimes 20851553Srgrimeschar * 208698558Sjmallettnextline(FILE *fd) 20871553Srgrimes{ 20881553Srgrimes char *cp; 20891553Srgrimes 20901553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 20911553Srgrimes return ((char *)0); 20921553Srgrimes cp = strchr(line, '\n'); 20931553Srgrimes if (cp) 20941553Srgrimes *cp = '\0'; 20951553Srgrimes return (line); 20961553Srgrimes} 20971553Srgrimes 20981553Srgrimeschar * 209998558Sjmallettnewstr(const char *cp) 21001553Srgrimes{ 210178694Sdwmalone char *cr; 210278694Sdwmalone 210378694Sdwmalone if ((cr = strdup(cp != NULL ? cp : ""))) 210478694Sdwmalone return (cr); 21051553Srgrimes syslog(LOG_ERR, "strdup: %m"); 210619617Sjulian exit(EX_OSERR); 21071553Srgrimes} 21081553Srgrimes 21091553Srgrimesvoid 211098558Sjmallettinetd_setproctitle(const char *a, int s) 21111553Srgrimes{ 211271399Sdwmalone socklen_t size; 211356590Sshin struct sockaddr_storage ss; 211456590Sshin char buf[80], pbuf[INET6_ADDRSTRLEN]; 21151553Srgrimes 211656590Sshin size = sizeof(ss); 211756590Sshin if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 211856590Sshin getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 2119146187Sume NULL, 0, NI_NUMERICHOST); 212056590Sshin (void) sprintf(buf, "%s [%s]", a, pbuf); 212156590Sshin } else 212213142Speter (void) sprintf(buf, "%s", a); 212313142Speter setproctitle("%s", buf); 212413142Speter} 212513142Speter 212678694Sdwmaloneint 212798558Sjmallettcheck_loop(const struct sockaddr *sa, const struct servtab *sep) 21285182Swollman{ 21295182Swollman struct servtab *se2; 213056590Sshin char pname[INET6_ADDRSTRLEN]; 21315182Swollman 21325182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 21335182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 21345182Swollman continue; 21355182Swollman 213656590Sshin switch (se2->se_family) { 213756590Sshin case AF_INET: 213878694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 213956590Sshin se2->se_ctrladdr4.sin_port) 214056590Sshin goto isloop; 214156590Sshin continue; 214256590Sshin#ifdef INET6 214356590Sshin case AF_INET6: 214478694Sdwmalone if (((const struct sockaddr_in *)sa)->sin_port == 214556590Sshin se2->se_ctrladdr4.sin_port) 214656590Sshin goto isloop; 214756590Sshin continue; 214856590Sshin#endif 214956590Sshin default: 215056590Sshin continue; 21515182Swollman } 215256590Sshin isloop: 215356590Sshin getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 2154146187Sume NI_NUMERICHOST); 215556590Sshin syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 215656590Sshin sep->se_service, sep->se_proto, 215756590Sshin se2->se_service, se2->se_proto, 215856590Sshin pname); 215956590Sshin return 1; 21605182Swollman } 21615182Swollman return 0; 21625182Swollman} 21635182Swollman 21641553Srgrimes/* 21651553Srgrimes * print_service: 21661553Srgrimes * Dump relevant information to stderr 21671553Srgrimes */ 21681553Srgrimesvoid 216998558Sjmallettprint_service(const char *action, const struct servtab *sep) 21701553Srgrimes{ 217119617Sjulian fprintf(stderr, 217256590Sshin "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 217330792Sache#ifdef LOGIN_CAP 217456590Sshin "class=%s" 217530792Sache#endif 217656590Sshin " builtin=%p server=%s" 217756590Sshin#ifdef IPSEC 217856590Sshin " policy=\"%s\"" 217956590Sshin#endif 218056590Sshin "\n", 218119617Sjulian action, sep->se_service, sep->se_proto, 218230807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 218330792Sache#ifdef LOGIN_CAP 218430792Sache sep->se_class, 218530792Sache#endif 218656590Sshin (void *) sep->se_bi, sep->se_server 218756590Sshin#ifdef IPSEC 218856590Sshin , (sep->se_policy ? sep->se_policy : "") 218956590Sshin#endif 219056590Sshin ); 21911553Srgrimes} 21921553Srgrimes 219330847Sdima#define CPMHSIZE 256 219430847Sdima#define CPMHMASK (CPMHSIZE-1) 219530847Sdima#define CHTGRAN 10 219630847Sdima#define CHTSIZE 6 219730847Sdima 219830847Sdimatypedef struct CTime { 219930847Sdima unsigned long ct_Ticks; 220030847Sdima int ct_Count; 220130847Sdima} CTime; 220230847Sdima 220330847Sdimatypedef struct CHash { 220456590Sshin union { 220556590Sshin struct in_addr c4_Addr; 220656590Sshin struct in6_addr c6_Addr; 220756590Sshin } cu_Addr; 220856590Sshin#define ch_Addr4 cu_Addr.c4_Addr 220956590Sshin#define ch_Addr6 cu_Addr.c6_Addr 221056590Sshin int ch_Family; 221130847Sdima time_t ch_LTime; 221230847Sdima char *ch_Service; 221330847Sdima CTime ch_Times[CHTSIZE]; 221430847Sdima} CHash; 221530847Sdima 221630847SdimaCHash CHashAry[CPMHSIZE]; 221730847Sdima 221830847Sdimaint 221998558Sjmallettcpmip(const struct servtab *sep, int ctrl) 222030847Sdima{ 222156590Sshin struct sockaddr_storage rss; 222271399Sdwmalone socklen_t rssLen = sizeof(rss); 222330847Sdima int r = 0; 222430847Sdima 222530847Sdima /* 222630847Sdima * If getpeername() fails, just let it through (if logging is 222730847Sdima * enabled the condition is caught elsewhere) 222830847Sdima */ 222930847Sdima 223030847Sdima if (sep->se_maxcpm > 0 && 223156590Sshin getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 223230847Sdima time_t t = time(NULL); 223330847Sdima int hv = 0xABC3D20F; 223430847Sdima int i; 223530847Sdima int cnt = 0; 223630847Sdima CHash *chBest = NULL; 223730847Sdima unsigned int ticks = t / CHTGRAN; 223878694Sdwmalone struct sockaddr_in *sin4; 223956590Sshin#ifdef INET6 224056590Sshin struct sockaddr_in6 *sin6; 224156590Sshin#endif 224230847Sdima 224378694Sdwmalone sin4 = (struct sockaddr_in *)&rss; 224456590Sshin#ifdef INET6 224556590Sshin sin6 = (struct sockaddr_in6 *)&rss; 224656590Sshin#endif 224730847Sdima { 224830847Sdima char *p; 224978694Sdwmalone int addrlen; 225030847Sdima 225156590Sshin switch (rss.ss_family) { 225256590Sshin case AF_INET: 225378694Sdwmalone p = (char *)&sin4->sin_addr; 225456590Sshin addrlen = sizeof(struct in_addr); 225556590Sshin break; 225656590Sshin#ifdef INET6 225756590Sshin case AF_INET6: 225856590Sshin p = (char *)&sin6->sin6_addr; 225956590Sshin addrlen = sizeof(struct in6_addr); 226056590Sshin break; 226156590Sshin#endif 226256590Sshin default: 226356590Sshin /* should not happen */ 226456590Sshin return -1; 226556590Sshin } 226656590Sshin 226756590Sshin for (i = 0; i < addrlen; ++i, ++p) { 226830847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 226930847Sdima } 227030847Sdima hv = (hv ^ (hv >> 16)); 227130847Sdima } 227230847Sdima for (i = 0; i < 5; ++i) { 227330847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 227430847Sdima 227556590Sshin if (rss.ss_family == AF_INET && 227656590Sshin ch->ch_Family == AF_INET && 227778694Sdwmalone sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 227830847Sdima ch->ch_Service && strcmp(sep->se_service, 227930847Sdima ch->ch_Service) == 0) { 228030847Sdima chBest = ch; 228130847Sdima break; 228230847Sdima } 228356590Sshin#ifdef INET6 228456590Sshin if (rss.ss_family == AF_INET6 && 228556590Sshin ch->ch_Family == AF_INET6 && 228656590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 228756590Sshin &ch->ch_Addr6) != 0 && 228856590Sshin ch->ch_Service && strcmp(sep->se_service, 228956590Sshin ch->ch_Service) == 0) { 229056590Sshin chBest = ch; 229156590Sshin break; 229256590Sshin } 229356590Sshin#endif 229430847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 229530847Sdima ch->ch_LTime < chBest->ch_LTime) { 229630847Sdima chBest = ch; 229730847Sdima } 229830847Sdima } 229956590Sshin if ((rss.ss_family == AF_INET && 230056590Sshin (chBest->ch_Family != AF_INET || 230178694Sdwmalone sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 230230847Sdima chBest->ch_Service == NULL || 230330847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 230478694Sdwmalone chBest->ch_Family = sin4->sin_family; 230578694Sdwmalone chBest->ch_Addr4 = sin4->sin_addr; 2306154530Sdelphij if (chBest->ch_Service) 2307154530Sdelphij free(chBest->ch_Service); 230830847Sdima chBest->ch_Service = strdup(sep->se_service); 230930847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 231030847Sdima } 231156590Sshin#ifdef INET6 231256590Sshin if ((rss.ss_family == AF_INET6 && 231356590Sshin (chBest->ch_Family != AF_INET6 || 231456590Sshin IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 231556590Sshin &chBest->ch_Addr6) == 0)) || 231656590Sshin chBest->ch_Service == NULL || 231756590Sshin strcmp(sep->se_service, chBest->ch_Service) != 0) { 231856590Sshin chBest->ch_Family = sin6->sin6_family; 231956590Sshin chBest->ch_Addr6 = sin6->sin6_addr; 2320154530Sdelphij if (chBest->ch_Service) 2321154530Sdelphij free(chBest->ch_Service); 232256590Sshin chBest->ch_Service = strdup(sep->se_service); 232356590Sshin bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 232456590Sshin } 232556590Sshin#endif 232630847Sdima chBest->ch_LTime = t; 232730847Sdima { 232830847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 232930847Sdima if (ct->ct_Ticks != ticks) { 233030847Sdima ct->ct_Ticks = ticks; 233130847Sdima ct->ct_Count = 0; 233230847Sdima } 233330847Sdima ++ct->ct_Count; 233430847Sdima } 233530847Sdima for (i = 0; i < CHTSIZE; ++i) { 233630847Sdima CTime *ct = &chBest->ch_Times[i]; 233730847Sdima if (ct->ct_Ticks <= ticks && 233830847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 233930847Sdima cnt += ct->ct_Count; 234030847Sdima } 234130847Sdima } 2342117644Sdwmalone if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 234356590Sshin char pname[INET6_ADDRSTRLEN]; 234456590Sshin 234556590Sshin getnameinfo((struct sockaddr *)&rss, 234656590Sshin ((struct sockaddr *)&rss)->sa_len, 234756590Sshin pname, sizeof(pname), NULL, 0, 2348146187Sume NI_NUMERICHOST); 234930847Sdima r = -1; 235030847Sdima syslog(LOG_ERR, 235133794Spst "%s from %s exceeded counts/min (limit %d/min)", 235256590Sshin sep->se_service, pname, 235333794Spst sep->se_maxcpm); 235430847Sdima } 235530847Sdima } 235630847Sdima return(r); 235730847Sdima} 2358101474Sume 2359101474Sumestatic struct conninfo * 2360101474Sumesearch_conn(struct servtab *sep, int ctrl) 2361101474Sume{ 2362101474Sume struct sockaddr_storage ss; 2363101474Sume socklen_t sslen = sizeof(ss); 2364101474Sume struct conninfo *conn; 2365101474Sume int hv; 2366101474Sume char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2367101474Sume 2368101474Sume if (sep->se_maxperip <= 0) 2369101474Sume return NULL; 2370101474Sume 2371101474Sume /* 2372101474Sume * If getpeername() fails, just let it through (if logging is 2373101474Sume * enabled the condition is caught elsewhere) 2374101474Sume */ 2375101474Sume if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2376101474Sume return NULL; 2377101474Sume 2378101474Sume switch (ss.ss_family) { 2379101474Sume case AF_INET: 2380101474Sume hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2381101474Sume sizeof(struct in_addr)); 2382101474Sume break; 2383101474Sume#ifdef INET6 2384101474Sume case AF_INET6: 2385101474Sume hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2386101474Sume sizeof(struct in6_addr)); 2387101474Sume break; 2388101474Sume#endif 2389101474Sume default: 2390101474Sume /* 2391101474Sume * Since we only support AF_INET and AF_INET6, just 2392101474Sume * let other than AF_INET and AF_INET6 through. 2393101474Sume */ 2394101474Sume return NULL; 2395101474Sume } 2396101474Sume 2397101474Sume if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2398146187Sume NULL, 0, NI_NUMERICHOST) != 0) 2399101474Sume return NULL; 2400101474Sume 2401101474Sume LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2402101474Sume if (getnameinfo((struct sockaddr *)&conn->co_addr, 2403101474Sume conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2404146187Sume NI_NUMERICHOST) == 0 && 2405101474Sume strcmp(pname, pname2) == 0) 2406101474Sume break; 2407101474Sume } 2408101474Sume 2409101474Sume if (conn == NULL) { 2410101474Sume if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2411101474Sume syslog(LOG_ERR, "malloc: %m"); 2412101474Sume exit(EX_OSERR); 2413101474Sume } 2414101474Sume conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2415101474Sume if (conn->co_proc == NULL) { 2416101474Sume syslog(LOG_ERR, "malloc: %m"); 2417101474Sume exit(EX_OSERR); 2418101474Sume } 2419101474Sume memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2420101474Sume conn->co_numchild = 0; 2421101474Sume LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2422101474Sume } 2423101474Sume 2424101474Sume /* 2425101474Sume * Since a child process is not invoked yet, we cannot 2426101474Sume * determine a pid of a child. So, co_proc and co_numchild 2427101474Sume * should be filled leter. 2428101474Sume */ 2429101474Sume 2430101474Sume return conn; 2431101474Sume} 2432101474Sume 2433101474Sumestatic int 2434101474Sumeroom_conn(struct servtab *sep, struct conninfo *conn) 2435101474Sume{ 2436101474Sume char pname[NI_MAXHOST]; 2437101474Sume 2438101474Sume if (conn->co_numchild >= sep->se_maxperip) { 2439101474Sume getnameinfo((struct sockaddr *)&conn->co_addr, 2440101474Sume conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2441146187Sume NI_NUMERICHOST); 2442101474Sume syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2443101474Sume sep->se_service, pname, sep->se_maxperip); 2444101474Sume return 0; 2445101474Sume } 2446101474Sume return 1; 2447101474Sume} 2448101474Sume 2449101474Sumestatic void 2450101474Sumeaddchild_conn(struct conninfo *conn, pid_t pid) 2451101474Sume{ 2452101474Sume struct procinfo *proc; 2453101474Sume 2454101474Sume if (conn == NULL) 2455101474Sume return; 2456101474Sume 2457101474Sume if ((proc = search_proc(pid, 1)) != NULL) { 2458101474Sume if (proc->pr_conn != NULL) { 2459101474Sume syslog(LOG_ERR, 2460101474Sume "addchild_conn: child already on process list"); 2461101474Sume exit(EX_OSERR); 2462101474Sume } 2463101474Sume proc->pr_conn = conn; 2464101474Sume } 2465101474Sume 2466101474Sume conn->co_proc[conn->co_numchild++] = proc; 2467101474Sume} 2468101474Sume 2469101474Sumestatic void 2470154530Sdelphijreapchild_conn(pid_t pid) 2471154530Sdelphij{ 2472154530Sdelphij struct procinfo *proc; 2473154530Sdelphij struct conninfo *conn; 2474154530Sdelphij int i; 2475154530Sdelphij 2476154530Sdelphij if ((proc = search_proc(pid, 0)) == NULL) 2477154530Sdelphij return; 2478154530Sdelphij if ((conn = proc->pr_conn) == NULL) 2479154530Sdelphij return; 2480154530Sdelphij for (i = 0; i < conn->co_numchild; ++i) 2481154530Sdelphij if (conn->co_proc[i] == proc) { 2482154530Sdelphij conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2483154530Sdelphij break; 2484154530Sdelphij } 2485154530Sdelphij free_proc(proc); 2486154530Sdelphij free_conn(conn); 2487154530Sdelphij} 2488154530Sdelphij 2489154530Sdelphijstatic void 2490102859Sdwmaloneresize_conn(struct servtab *sep, int maxpip) 2491101474Sume{ 2492101474Sume struct conninfo *conn; 2493101474Sume int i, j; 2494101474Sume 2495101474Sume if (sep->se_maxperip <= 0) 2496101474Sume return; 2497102859Sdwmalone if (maxpip <= 0) { 2498101474Sume free_connlist(sep); 2499101474Sume return; 2500101474Sume } 2501101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2502101474Sume LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2503102859Sdwmalone for (j = maxpip; j < conn->co_numchild; ++j) 2504101474Sume free_proc(conn->co_proc[j]); 2505101474Sume conn->co_proc = realloc(conn->co_proc, 2506102859Sdwmalone maxpip * sizeof(*conn->co_proc)); 2507101474Sume if (conn->co_proc == NULL) { 2508101474Sume syslog(LOG_ERR, "realloc: %m"); 2509101474Sume exit(EX_OSERR); 2510101474Sume } 2511102859Sdwmalone if (conn->co_numchild > maxpip) 2512102859Sdwmalone conn->co_numchild = maxpip; 2513101474Sume } 2514101474Sume } 2515101474Sume} 2516101474Sume 2517101474Sumestatic void 2518101474Sumefree_connlist(struct servtab *sep) 2519101474Sume{ 2520101474Sume struct conninfo *conn; 2521101474Sume int i, j; 2522101474Sume 2523101474Sume for (i = 0; i < PERIPSIZE; ++i) { 2524101474Sume while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2525101474Sume for (j = 0; j < conn->co_numchild; ++j) 2526101474Sume free_proc(conn->co_proc[j]); 2527101474Sume conn->co_numchild = 0; 2528101474Sume free_conn(conn); 2529101474Sume } 2530101474Sume } 2531101474Sume} 2532101474Sume 2533101474Sumestatic void 2534101474Sumefree_conn(struct conninfo *conn) 2535101474Sume{ 2536101474Sume if (conn == NULL) 2537101474Sume return; 2538101474Sume if (conn->co_numchild <= 0) { 2539101474Sume LIST_REMOVE(conn, co_link); 2540101474Sume free(conn->co_proc); 2541101474Sume free(conn); 2542101474Sume } 2543101474Sume} 2544101474Sume 2545101474Sumestatic struct procinfo * 2546101474Sumesearch_proc(pid_t pid, int add) 2547101474Sume{ 2548101474Sume struct procinfo *proc; 2549101474Sume int hv; 2550101474Sume 2551101474Sume hv = hashval((char *)&pid, sizeof(pid)); 2552101474Sume LIST_FOREACH(proc, &proctable[hv], pr_link) { 2553101474Sume if (proc->pr_pid == pid) 2554101474Sume break; 2555101474Sume } 2556101474Sume if (proc == NULL && add) { 2557101474Sume if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2558101474Sume syslog(LOG_ERR, "malloc: %m"); 2559101474Sume exit(EX_OSERR); 2560101474Sume } 2561101474Sume proc->pr_pid = pid; 2562101474Sume proc->pr_conn = NULL; 2563101474Sume LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2564101474Sume } 2565101474Sume return proc; 2566101474Sume} 2567101474Sume 2568101474Sumestatic void 2569101474Sumefree_proc(struct procinfo *proc) 2570101474Sume{ 2571101474Sume if (proc == NULL) 2572101474Sume return; 2573101474Sume LIST_REMOVE(proc, pr_link); 2574101474Sume free(proc); 2575101474Sume} 2576101474Sume 2577101474Sumestatic int 2578101474Sumehashval(char *p, int len) 2579101474Sume{ 2580101474Sume int i, hv = 0xABC3D20F; 2581101474Sume 2582101474Sume for (i = 0; i < len; ++i, ++p) 2583101474Sume hv = (hv << 5) ^ (hv >> 23) ^ *p; 2584101474Sume hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2585101474Sume return hv; 2586101474Sume} 2587