inetd.c revision 313206
12061Sjkh/* 236622Scharnier * Copyright (c) 1983, 1991, 1993, 1994 32061Sjkh * The Regents of the University of California. All rights reserved. 433611Sjb * 532427Sjb * Redistribution and use in source and binary forms, with or without 632427Sjb * modification, are permitted provided that the following conditions 736111Sjb * are met: 833611Sjb * 1. Redistributions of source code must retain the above copyright 932427Sjb * notice, this list of conditions and the following disclaimer. 1032427Sjb * 2. Redistributions in binary form must reproduce the above copyright 112061Sjkh * notice, this list of conditions and the following disclaimer in the 1215603Smarkm * documentation and/or other materials provided with the distribution. 1330169Sjkh * 4. Neither the name of the University nor the names of its contributors 1420710Sasami * may be used to endorse or promote products derived from this software 1520710Sasami * without specific prior written permission. 163197Scsgr * 172061Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1812483Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1934509Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 202160Scsgr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 212834Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 222061Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 232061Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 242160Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2517308Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2619320Sadam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2727788Sasami * SUCH DAMAGE. 2830169Sjkh */ 2925980Sasami 301594Srgrimes#ifndef lint 3117308Speterstatic const char copyright[] = 3217308Speter"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 3327910Sasami The Regents of the University of California. All rights reserved.\n"; 3427910Sasami#endif /* not lint */ 3527910Sasami 3617308Speter#ifndef lint 3717308Speter#if 0 3817308Speterstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 3919175Sbde#endif 4019175Sbde#endif /* not lint */ 4119175Sbde 4219175Sbde#include <sys/cdefs.h> 4317308Speter__FBSDID("$FreeBSD: stable/10/usr.sbin/inetd/inetd.c 313206 2017-02-04 15:52:08Z ngie $"); 4427910Sasami 4534509Sbde/* 4627910Sasami * Inetd - Internet super-server 4717308Speter * 482061Sjkh * This program invokes all internet services as needed. Connection-oriented 492061Sjkh * services are invoked each time a connection is made, by creating a process. 501594Srgrimes * This process is passed the connection as file descriptor 0 and is expected 5130169Sjkh * to do a getpeername to find out the source host and port. 5230169Sjkh * 5330169Sjkh * Datagram oriented services are invoked when a datagram 5430169Sjkh * arrives; a process is created and passed a pending message 5530169Sjkh * on file descriptor 0. Datagram servers may either connect 5630169Sjkh * to their peer, freeing up the original socket for inetd 5730169Sjkh * to receive further messages on, or ``take over the socket'', 5830169Sjkh * processing all arriving datagrams and, eventually, timing 597407Srgrimes * out. The first type of server is said to be ``multi-threaded''; 607108Sphk * the second type of server ``single-threaded''. 617108Sphk * 627108Sphk * Inetd uses a configuration file which is read at startup 637407Srgrimes * and, possibly, at some later time in response to a hangup signal. 647407Srgrimes * The configuration file is ``free format'' with fields given in the 657407Srgrimes * order shown below. Continuation lines for an entry must begin with 667108Sphk * a space or tab. All fields must be present in each entry. 672061Sjkh * 682061Sjkh * service name must be in /etc/services 692061Sjkh * or name a tcpmux service 7017308Speter * or specify a unix domain socket 712061Sjkh * socket type stream/dgram/raw/rdm/seqpacket 722061Sjkh * protocol tcp[4][6][/faith], udp[4][6], unix 732061Sjkh * wait/nowait single-threaded/multi-threaded 742061Sjkh * user[:group][/login-class] user/group/login-class to run daemon as 752061Sjkh * server program full path name 7635427Sbde * server program arguments maximum of MAXARGS (20) 7735427Sbde * 7830169Sjkh * TCP services without official port numbers are handled with the 792626Scsgr * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 802061Sjkh * requests. When a connection is made from a foreign host, the service 812061Sjkh * requested is passed to tcpmux, which looks it up in the servtab list 822061Sjkh * and returns the proper entry for the service. Tcpmux returns a 832061Sjkh * negative reply if the service doesn't exist, otherwise the invoked 842061Sjkh * server is expected to return the positive reply if the service type in 852061Sjkh * inetd.conf file has the prefix "tcpmux/". If the service type has the 8619320Sadam * prefix "tcpmux/+", tcpmux will return the positive reply for the 872061Sjkh * process; this is for compatibility with older server code, and also 882061Sjkh * allows you to invoke programs that use stdin/stdout without putting any 892061Sjkh * special server code in them. Services that use tcpmux are "nowait" 902061Sjkh * because they do not have a well-known port and hence cannot listen 912061Sjkh * for new requests. 922061Sjkh * 932061Sjkh * For RPC services 942061Sjkh * service name/version must be in /etc/rpc 952061Sjkh * socket type stream/dgram/raw/rdm/seqpacket 962061Sjkh * protocol rpc/tcp[4][6], rpc/udp[4][6] 972061Sjkh * wait/nowait single-threaded/multi-threaded 982834Swollman * user[:group][/login-class] user/group/login-class to run daemon as 992834Swollman * server program full path name 1002834Swollman * server program arguments maximum of MAXARGS 1012834Swollman * 1022834Swollman * Comment lines are indicated by a `#' in column 1. 1032834Swollman * 1041594Srgrimes * #ifdef IPSEC 1054486Sphk * Comment lines that start with "#@" denote IPsec policy string, as described 1064486Sphk * in ipsec_set_policy(3). This will affect all the following items in 1074486Sphk * inetd.conf(8). To reset the policy, just use "#@" line. By default, 1084486Sphk * there's no IPsec policy. 1094486Sphk * #endif 1102061Sjkh */ 1112061Sjkh#include <sys/param.h> 11225979Sjkh#include <sys/ioctl.h> 11325979Sjkh#include <sys/mman.h> 11425979Sjkh#include <sys/wait.h> 11525979Sjkh#include <sys/time.h> 1162061Sjkh#include <sys/resource.h> 11725979Sjkh#include <sys/stat.h> 1182061Sjkh#include <sys/un.h> 1192061Sjkh 12017308Speter#include <netinet/in.h> 1212061Sjkh#include <netinet/tcp.h> 1222061Sjkh#include <arpa/inet.h> 1232061Sjkh#include <rpc/rpc.h> 1242061Sjkh#include <rpc/pmap_clnt.h> 1252061Sjkh 12612483Speter#include <ctype.h> 12712483Speter#include <errno.h> 12812483Speter#include <err.h> 12912483Speter#include <fcntl.h> 1302061Sjkh#include <grp.h> 13135479Sbde#include <libutil.h> 1328854Srgrimes#include <limits.h> 1332061Sjkh#include <netdb.h> 1342061Sjkh#include <pwd.h> 13512483Speter#include <signal.h> 1362061Sjkh#include <stdio.h> 13735479Sbde#include <stdlib.h> 13835479Sbde#include <string.h> 13935479Sbde#include <sysexits.h> 14035479Sbde#include <syslog.h> 14135479Sbde#ifdef LIBWRAP 14235479Sbde#include <tcpd.h> 14335479Sbde#endif 14435479Sbde#include <unistd.h> 14535479Sbde 14635462Sjkh#include "inetd.h" 14735462Sjkh#include "pathnames.h" 14818714Sache 14917308Speter#ifdef IPSEC 15034541Sbde#include <netipsec/ipsec.h> 15134575Sbde#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 15234575Sbde#undef IPSEC 15334575Sbde#endif 15434592Sbde#endif 15517308Speter 15634575Sbde#ifndef LIBWRAP_ALLOW_FACILITY 15735427Sbde# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 15834575Sbde#endif 15935427Sbde#ifndef LIBWRAP_ALLOW_SEVERITY 16034575Sbde# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 16115603Smarkm#endif 16217308Speter#ifndef LIBWRAP_DENY_FACILITY 16317308Speter# define LIBWRAP_DENY_FACILITY LOG_AUTH 16417308Speter#endif 16517308Speter#ifndef LIBWRAP_DENY_SEVERITY 16617308Speter# define LIBWRAP_DENY_SEVERITY LOG_WARNING 16717308Speter#endif 16817308Speter 16917308Speter#define ISWRAP(sep) \ 17017308Speter ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 17118362Sjkh && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 17219966Sache && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17318362Sjkh || (sep)->se_socktype == SOCK_DGRAM)) 17417308Speter 17527910Sasami#ifdef LOGIN_CAP 17617308Speter#include <login_cap.h> 17717308Speter 17817308Speter/* see init.c */ 17936074Sbde#define RESOURCE_RC "daemon" 18027910Sasami 18136074Sbde#endif 18236074Sbde 18327910Sasami#ifndef MAXCHILD 18417308Speter#define MAXCHILD -1 /* maximum number of this service 1852061Sjkh < 0 = no limit */ 18627910Sasami#endif 1872061Sjkh 18836074Sbde#ifndef MAXCPM 18927910Sasami#define MAXCPM -1 /* rate limit invocations from a 1902061Sjkh single remote address, 19117308Speter < 0 = no limit */ 19227910Sasami#endif 19317308Speter 19427910Sasami#ifndef MAXPERIP 19527910Sasami#define MAXPERIP -1 /* maximum number of this service 19627910Sasami from a single remote address, 19717308Speter < 0 = no limit */ 19827910Sasami#endif 19917308Speter 20027910Sasami#ifndef TOOMANY 20127910Sasami#define TOOMANY 256 /* don't start more than TOOMANY */ 20227910Sasami#endif 20327910Sasami#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 20436622Scharnier#define RETRYTIME (60*10) /* retry after bind or server fail */ 20536622Scharnier#define MAX_MAXCHLD 32767 /* max allowable max children */ 20627910Sasami 20727910Sasami#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 20827910Sasami 20927910Sasamivoid close_sep(struct servtab *); 21027910Sasamivoid flag_signal(int); 21127910Sasamivoid flag_config(int); 21234509Sbdevoid config(void); 21327910Sasamiint cpmip(const struct servtab *, int); 21427910Sasamivoid endconfig(void); 21527910Sasamistruct servtab *enter(struct servtab *); 21636423Spetervoid freeconfig(struct servtab *); 21736423Speterstruct servtab *getconfigent(void); 21827910Sasamiint matchservent(const char *, const char *, const char *); 21936423Speterchar *nextline(FILE *); 22035479Sbdevoid addchild(struct servtab *, int); 22127910Sasamivoid flag_reapchild(int); 22227910Sasamivoid reapchild(void); 22334688Sbdevoid enable(struct servtab *); 22434688Sbdevoid disable(struct servtab *); 22527910Sasamivoid flag_retry(int); 22635427Sbdevoid retry(void); 22727910Sasamiint setconfig(void); 22835427Sbdevoid setup(struct servtab *); 22927910Sasami#ifdef IPSEC 23035427Sbdevoid ipsecsetup(struct servtab *); 23127910Sasami#endif 23227910Sasamivoid unregisterrpc(register struct servtab *sep); 23327910Sasamistatic struct conninfo *search_conn(struct servtab *sep, int ctrl); 23427910Sasamistatic int room_conn(struct servtab *sep, struct conninfo *conn); 23527910Sasamistatic void addchild_conn(struct conninfo *conn, pid_t pid); 23627910Sasamistatic void reapchild_conn(pid_t pid); 23727910Sasamistatic void free_conn(struct conninfo *conn); 23827910Sasamistatic void resize_conn(struct servtab *sep, int maxperip); 23927910Sasamistatic void free_connlist(struct servtab *sep); 24017308Speterstatic void free_proc(struct procinfo *); 24117308Speterstatic struct procinfo *search_proc(pid_t pid, int add); 24227910Sasamistatic int hashval(char *p, int len); 24317308Speter 24427910Sasamiint allow_severity; 24527910Sasamiint deny_severity; 24627910Sasamiint wrap_ex = 0; 24727910Sasamiint wrap_bi = 0; 24833133Sadamint debug = 0; 24917466Speterint dolog = 0; 25017308Speterint maxsock; /* highest-numbered descriptor */ 25127910Sasamifd_set allsock; 25217308Speterint options; 25334688Sbdeint timingout; 25434688Sbdeint toomany = TOOMANY; 25536074Sbdeint maxchild = MAXCHILD; 25636074Sbdeint maxcpm = MAXCPM; 25736074Sbdeint maxperip = MAXPERIP; 25836074Sbdestruct servent *sp; 25934688Sbdestruct rpcent *rpc; 26034688Sbdechar *hostname = NULL; 26133133Sadamstruct sockaddr_in *bind_sa4; 26217308Speterint v4bind_ok = 0; 26317308Speter#ifdef INET6 26427910Sasamistruct sockaddr_in6 *bind_sa6; 26517308Speterint v6bind_ok = 0; 26636074Sbde#endif 26727910Sasamiint signalpipe[2]; 26817308Speter#ifdef SANITY_CHECK 26917308Speterint nsock; 27027910Sasami#endif 27117308Speteruid_t euid; 27236074Sbdegid_t egid; 27327910Sasamimode_t mask; 27427910Sasami 27517308Speterstruct servtab *servtab; 27617308Speter 27727910Sasamiextern struct biltin biltins[]; 27817308Speter 27936074Sbdeconst char *CONFIG = _PATH_INETDCONF; 28027910Sasamiconst char *pid_file = _PATH_INETDPID; 28133133Sadamstruct pidfh *pfh = NULL; 28217308Speter 28317308Speterstruct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; 28427910Sasami 28517308Speterstatic LIST_HEAD(, procinfo) proctable[PERIPSIZE]; 28636074Sbde 28717308Speterint 28817308Spetergetvalue(const char *arg, int *value, const char *whine) 28927910Sasami{ 29017308Speter int tmp; 29136074Sbde char *p; 29233133Sadam 29317308Speter tmp = strtol(arg, &p, 0); 29417308Speter if (tmp < 0 || *p) { 29534509Sbde syslog(LOG_ERR, whine, arg); 29617308Speter return 1; /* failure */ 29736429Speter } 29835851Sjb *value = tmp; 29935851Sjb return 0; /* success */ 30035851Sjb} 30135851Sjb 30236074Sbde#ifdef LIBWRAP 30333133Sadamstatic sa_family_t 30417962Speterwhichaf(struct request_info *req) 30517962Speter{ 30635851Sjb struct sockaddr *sa; 30717962Speter 30836074Sbde sa = (struct sockaddr *)req->client->sin; 30933133Sadam if (sa == NULL) 31033133Sadam return AF_UNSPEC; 31117962Speter if (sa->sa_family == AF_INET6 && 31217962Speter IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) 31327910Sasami return AF_INET; 31417962Speter return sa->sa_family; 31536074Sbde} 31633133Sadam#endif 31735479Sbde 31817308Speterint 31917308Spetermain(int argc, char **argv) 32027910Sasami{ 32117308Speter struct servtab *sep; 32236074Sbde struct passwd *pwd; 32335479Sbde struct group *grp; 32417308Speter struct sigaction sa, saalrm, sachld, sahup, sapipe; 32517308Speter int ch, dofork; 32635427Sbde pid_t pid; 32735427Sbde char buf[50]; 32836074Sbde#ifdef LOGIN_CAP 32935427Sbde login_cap_t *lc = NULL; 33035427Sbde#endif 33127910Sasami#ifdef LIBWRAP 33217962Speter struct request_info req; 33336074Sbde int denied; 3342061Sjkh char *service = NULL; 33517308Speter#endif 33627910Sasami struct sockaddr_storage peer; 33727910Sasami int i; 33827910Sasami struct addrinfo hints, *res; 33927910Sasami const char *servname; 34027910Sasami int error; 34136074Sbde struct conninfo *conn; 34227910Sasami 34327910Sasami openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 34417308Speter 34517308Speter while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1) 34617308Speter switch(ch) { 34717308Speter case 'd': 34817308Speter debug = 1; 34917308Speter options |= SO_DEBUG; 35017308Speter break; 35112483Speter case 'l': 35217308Speter dolog = 1; 35312483Speter break; 35436074Sbde case 'R': 35512483Speter getvalue(optarg, &toomany, 3562061Sjkh "-R %s: bad value for service invocation rate"); 35717962Speter break; 35817962Speter case 'c': 35936074Sbde getvalue(optarg, &maxchild, 36017962Speter "-c %s: bad value for maximum children"); 36117962Speter break; 36233595Snate case 'C': 36333595Snate getvalue(optarg, &maxcpm, 36436074Sbde "-C %s: bad value for maximum children/minute"); 36533595Snate break; 36633595Snate case 'a': 36717962Speter hostname = optarg; 36817962Speter break; 36936074Sbde case 'p': 3702061Sjkh pid_file = optarg; 37117308Speter break; 37217308Speter case 's': 37317308Speter getvalue(optarg, &maxperip, 37417308Speter "-s %s: bad value for maximum children per source address"); 37517308Speter break; 37617308Speter case 'w': 3772302Spaul wrap_ex++; 3782302Spaul break; 3792302Spaul case 'W': 38035462Sjkh wrap_bi++; 3812302Spaul break; 38218714Sache case '?': 38310760Sache default: 38418714Sache syslog(LOG_ERR, 3852302Spaul "usage: inetd [-dlwW] [-a address] [-R rate]" 38610760Sache " [-c maximum] [-C rate]" 38718714Sache " [-p pidfile] [conf-file]"); 38810760Sache exit(EX_USAGE); 38910760Sache } 3902302Spaul /* 3912302Spaul * Initialize Bind Addrs. 3922302Spaul * When hostname is NULL, wild card bind addrs are obtained from 3932302Spaul * getaddrinfo(). But getaddrinfo() requires at least one of 39436074Sbde * hostname or servname is non NULL. 3952302Spaul * So when hostname is NULL, set dummy value to servname. 3962302Spaul * Since getaddrinfo() doesn't accept numeric servname, and 39717308Speter * we doesn't use ai_socktype of struct addrinfo returned 39817308Speter * from getaddrinfo(), we set dummy value to ai_socktype. 39917308Speter */ 40017308Speter servname = (hostname == NULL) ? "0" /* dummy */ : NULL; 40117308Speter 40217308Speter bzero(&hints, sizeof(struct addrinfo)); 4032061Sjkh hints.ai_flags = AI_PASSIVE; 40417308Speter hints.ai_family = AF_UNSPEC; 4052061Sjkh hints.ai_socktype = SOCK_STREAM; /* dummy */ 40636074Sbde error = getaddrinfo(hostname, servname, &hints, &res); 40736074Sbde if (error != 0) { 40836074Sbde syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 40936074Sbde if (error == EAI_SYSTEM) 41036074Sbde syslog(LOG_ERR, "%s", strerror(errno)); 41136074Sbde exit(EX_USAGE); 41236074Sbde } 41336074Sbde do { 41430169Sjkh if (res->ai_addr == NULL) { 41536074Sbde syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 41617308Speter exit(EX_USAGE); 41717308Speter } 41836074Sbde switch (res->ai_addr->sa_family) { 41917308Speter case AF_INET: 4202061Sjkh if (v4bind_ok) 42117308Speter continue; 42217308Speter bind_sa4 = (struct sockaddr_in *)res->ai_addr; 42317308Speter /* init port num in case servname is dummy */ 42417308Speter bind_sa4->sin_port = 0; 42517308Speter v4bind_ok = 1; 42617308Speter continue; 4273626Swollman#ifdef INET6 4283626Swollman case AF_INET6: 4293626Swollman if (v6bind_ok) 4303626Swollman continue; 43136074Sbde bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 43236074Sbde /* init port num in case servname is dummy */ 43336074Sbde bind_sa6->sin6_port = 0; 43436074Sbde v6bind_ok = 1; 43536074Sbde continue; 43636074Sbde#endif 43736074Sbde } 43836074Sbde if (v4bind_ok 43930169Sjkh#ifdef INET6 44036074Sbde && v6bind_ok 4413626Swollman#endif 4423626Swollman ) 44336074Sbde break; 4443626Swollman } while ((res = res->ai_next) != NULL); 4453626Swollman if (!v4bind_ok 44617308Speter#ifdef INET6 44717308Speter && !v6bind_ok 44817308Speter#endif 44917308Speter ) { 45017308Speter syslog(LOG_ERR, "-a %s: unknown address family", hostname); 45117308Speter exit(EX_USAGE); 45217308Speter } 45317308Speter 45417308Speter euid = geteuid(); 45517308Speter egid = getegid(); 4563626Swollman umask(mask = umask(0777)); 45717308Speter 45817308Speter argc -= optind; 45917308Speter argv += optind; 46017308Speter 46136074Sbde if (argc > 0) 46217308Speter CONFIG = argv[0]; 46317308Speter if (access(CONFIG, R_OK) < 0) 46417308Speter syslog(LOG_ERR, "Accessing %s: %m, continuing anyway.", CONFIG); 46517308Speter if (debug == 0) { 46617308Speter pid_t otherpid; 46717308Speter 46817308Speter pfh = pidfile_open(pid_file, 0600, &otherpid); 46927910Sasami if (pfh == NULL) { 47027910Sasami if (errno == EEXIST) { 47127910Sasami syslog(LOG_ERR, "%s already running, pid: %d", 47236074Sbde getprogname(), otherpid); 47336442Speter exit(EX_OSERR); 47436442Speter } 47536442Speter syslog(LOG_WARNING, "pidfile_open() failed: %m"); 47636442Speter } 47736442Speter 47836429Speter if (daemon(0, 0) < 0) { 47936429Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 48036429Speter } 48136429Speter /* From now on we don't want syslog messages going to stderr. */ 48236429Speter closelog(); 48336429Speter openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 48427910Sasami /* 48536074Sbde * In case somebody has started inetd manually, we need to 48636074Sbde * clear the logname, so that old servers run as root do not 48730113Sjkh * get the user's logname.. 48836074Sbde */ 48936074Sbde if (setlogin("") < 0) { 49030113Sjkh syslog(LOG_WARNING, "cannot clear logname: %m"); 49136074Sbde /* no big deal if it fails.. */ 49236074Sbde } 49336074Sbde if (pfh != NULL && pidfile_write(pfh) == -1) { 49430113Sjkh syslog(LOG_WARNING, "pidfile_write(): %m"); 49536429Speter } 49636429Speter } 49736429Speter 49829938Smckay if (madvise(NULL, 0, MADV_PROTECT) != 0) 49936074Sbde syslog(LOG_WARNING, "madvise() failed: %s", strerror(errno)); 50029938Smckay 50117308Speter for (i = 0; i < PERIPSIZE; ++i) 50217308Speter LIST_INIT(&proctable[i]); 50317308Speter 50417308Speter if (v4bind_ok) { 50517308Speter udpconf = getnetconfigent("udp"); 50627910Sasami tcpconf = getnetconfigent("tcp"); 50727910Sasami if (udpconf == NULL || tcpconf == NULL) { 50827910Sasami syslog(LOG_ERR, "unknown rpc/udp or rpc/tcp"); 50917308Speter exit(EX_USAGE); 51017308Speter } 51134520Sbde } 51236074Sbde#ifdef INET6 51336074Sbde if (v6bind_ok) { 51436074Sbde udp6conf = getnetconfigent("udp6"); 51530113Sjkh tcp6conf = getnetconfigent("tcp6"); 51634520Sbde if (udp6conf == NULL || tcp6conf == NULL) { 51717308Speter syslog(LOG_ERR, "unknown rpc/udp6 or rpc/tcp6"); 51817308Speter exit(EX_USAGE); 51917308Speter } 52017308Speter } 52114119Speter#endif 5222061Sjkh 5237130Srgrimes sa.sa_flags = 0; 5247130Srgrimes sigemptyset(&sa.sa_mask); 5257130Srgrimes sigaddset(&sa.sa_mask, SIGALRM); 5262061Sjkh sigaddset(&sa.sa_mask, SIGCHLD); 52736074Sbde sigaddset(&sa.sa_mask, SIGHUP); 52836074Sbde sa.sa_handler = flag_retry; 52936074Sbde sigaction(SIGALRM, &sa, &saalrm); 53036074Sbde config(); 53136074Sbde sa.sa_handler = flag_config; 53236074Sbde sigaction(SIGHUP, &sa, &sahup); 53336074Sbde sa.sa_handler = flag_reapchild; 53436074Sbde sigaction(SIGCHLD, &sa, &sachld); 53536074Sbde sa.sa_handler = SIG_IGN; 53636074Sbde sigaction(SIGPIPE, &sa, &sapipe); 53730169Sjkh 53836074Sbde { 5393197Scsgr /* space for daemons to overwrite environment for ps */ 54030169Sjkh#define DUMMYSIZE 100 54136074Sbde char dummy[DUMMYSIZE]; 54236074Sbde 54336074Sbde (void)memset(dummy, 'x', DUMMYSIZE - 1); 54436074Sbde dummy[DUMMYSIZE - 1] = '\0'; 54536074Sbde (void)setenv("inetd_dummy", dummy, 1); 54636074Sbde } 54730169Sjkh 54836074Sbde if (pipe2(signalpipe, O_CLOEXEC) != 0) { 54930169Sjkh syslog(LOG_ERR, "pipe: %m"); 55032427Sjb exit(EX_OSERR); 55136074Sbde } 55232427Sjb FD_SET(signalpipe[0], &allsock); 55336074Sbde#ifdef SANITY_CHECK 55436074Sbde nsock++; 55536074Sbde#endif 55636074Sbde if (signalpipe[0] > maxsock) 55736074Sbde maxsock = signalpipe[0]; 55836074Sbde if (signalpipe[1] > maxsock) 55936074Sbde maxsock = signalpipe[1]; 56036074Sbde 56136074Sbde for (;;) { 56236074Sbde int n, ctrl; 5637281Srgrimes fd_set readable; 56436074Sbde 5653242Spaul#ifdef SANITY_CHECK 56636074Sbde if (nsock == 0) { 56736074Sbde syslog(LOG_ERR, "%s: nsock=0", __func__); 56836074Sbde exit(EX_SOFTWARE); 56936074Sbde } 57030169Sjkh#endif 57130169Sjkh readable = allsock; 57236074Sbde if ((n = select(maxsock + 1, &readable, (fd_set *)0, 57330169Sjkh (fd_set *)0, (struct timeval *)0)) <= 0) { 57436074Sbde if (n < 0 && errno != EINTR) { 57536074Sbde syslog(LOG_WARNING, "select: %m"); 57636074Sbde sleep(1); 57736074Sbde } 57836074Sbde continue; 57936074Sbde } 58036074Sbde /* handle any queued signal flags */ 58136074Sbde if (FD_ISSET(signalpipe[0], &readable)) { 58236074Sbde int nsig; 5832061Sjkh if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 58417308Speter syslog(LOG_ERR, "ioctl: %m"); 58517308Speter exit(EX_OSERR); 58617308Speter } 58727910Sasami while (--nsig >= 0) { 58827910Sasami char c; 58936573Speter if (read(signalpipe[0], &c, 1) != 1) { 5905366Snate syslog(LOG_ERR, "read: %m"); 59127910Sasami exit(EX_OSERR); 59227910Sasami } 59327910Sasami if (debug) 59427910Sasami warnx("handling signal flag %c", c); 59527910Sasami switch(c) { 59627910Sasami case 'A': /* sigalrm */ 59727910Sasami retry(); 59827910Sasami break; 59927910Sasami case 'C': /* sigchld */ 60027910Sasami reapchild(); 60127910Sasami break; 60227910Sasami case 'H': /* sighup */ 60336374Ssos config(); 60436374Ssos break; 60536374Ssos } 60636419Speter } 60736585Speter } 60836419Speter for (sep = servtab; n && sep; sep = sep->se_next) 60936074Sbde if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 61036074Sbde n--; 61136074Sbde if (debug) 61234575Sbde warnx("someone wants %s", sep->se_service); 61327910Sasami dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 6145366Snate conn = NULL; 61517308Speter if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 61635427Sbde i = 1; 61717308Speter if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 61835427Sbde syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 61935427Sbde ctrl = accept(sep->se_fd, (struct sockaddr *)0, 62035427Sbde (socklen_t *)0); 62135427Sbde if (debug) 62235427Sbde warnx("accept, ctrl %d", ctrl); 62335427Sbde if (ctrl < 0) { 62435427Sbde if (errno != EINTR) 62535427Sbde syslog(LOG_WARNING, 62635427Sbde "accept (for %s): %m", 62735427Sbde sep->se_service); 62835427Sbde if (sep->se_accept && 62935427Sbde sep->se_socktype == SOCK_STREAM) 63035427Sbde close(ctrl); 63135427Sbde continue; 63235427Sbde } 63334541Sbde i = 0; 63435427Sbde if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 63524754Sjdp syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 63634541Sbde if (ioctl(ctrl, FIONBIO, &i) < 0) 63736444Speter syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 63836444Speter if (cpmip(sep, ctrl) < 0) { 63936470Sjhay close(ctrl); 64036444Speter continue; 64136444Speter } 64235427Sbde if (dofork && 64335427Sbde (conn = search_conn(sep, ctrl)) != NULL && 64435427Sbde !room_conn(sep, conn)) { 64534541Sbde close(ctrl); 64635427Sbde continue; 64734541Sbde } 64835427Sbde } else 6498295Srgrimes ctrl = sep->se_fd; 65034541Sbde if (dolog && !ISWRAP(sep)) { 65134541Sbde char pname[NI_MAXHOST] = "unknown"; 65235427Sbde socklen_t sl; 65335427Sbde sl = sizeof(peer); 65434541Sbde if (getpeername(ctrl, (struct sockaddr *) 65535427Sbde &peer, &sl)) { 65635427Sbde sl = sizeof(peer); 65735427Sbde if (recvfrom(ctrl, buf, sizeof(buf), 65835427Sbde MSG_PEEK, 65935427Sbde (struct sockaddr *)&peer, 66034541Sbde &sl) >= 0) { 66135427Sbde getnameinfo((struct sockaddr *)&peer, 66235427Sbde peer.ss_len, 66335427Sbde pname, sizeof(pname), 66435427Sbde NULL, 0, NI_NUMERICHOST); 66534541Sbde } 66635427Sbde } else { 66735427Sbde getnameinfo((struct sockaddr *)&peer, 66836397Ssos peer.ss_len, 66936444Speter pname, sizeof(pname), 67035427Sbde NULL, 0, NI_NUMERICHOST); 67134541Sbde } 67236074Sbde syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 67336074Sbde } 67436074Sbde (void) sigblock(SIGBLOCK); 67530113Sjkh pid = 0; 6768489Srgrimes /* 67734541Sbde * Fork for all external services, builtins which need to 67835427Sbde * fork and anything we're wrapping (as wrapping might 67935427Sbde * block or use hosts_options(5) twist). 68035427Sbde */ 68135427Sbde if (dofork) { 68235427Sbde if (sep->se_count++ == 0) 68335427Sbde (void)clock_gettime(CLOCK_MONOTONIC_FAST, &sep->se_time); 68435427Sbde else if (toomany > 0 && sep->se_count >= toomany) { 68535427Sbde struct timespec now; 68635427Sbde 68735427Sbde (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); 68835427Sbde if (now.tv_sec - sep->se_time.tv_sec > 68935427Sbde CNT_INTVL) { 69035427Sbde sep->se_time = now; 69136074Sbde sep->se_count = 1; 69235427Sbde } else { 69335427Sbde syslog(LOG_ERR, 69434541Sbde "%s/%s server failing (looping), service terminated", 69536074Sbde sep->se_service, sep->se_proto); 6962160Scsgr if (sep->se_accept && 69734541Sbde sep->se_socktype == SOCK_STREAM) 69834541Sbde close(ctrl); 69936074Sbde close_sep(sep); 7002626Scsgr free_conn(conn); 7012061Sjkh sigsetmask(0L); 70236589Sjhay if (!timingout) { 70336589Sjhay timingout = 1; 70436589Sjhay alarm(RETRYTIME); 70536589Sjhay } 70636589Sjhay continue; 70736589Sjhay } 70836589Sjhay } 70917308Speter pid = fork(); 71017308Speter } 71117308Speter if (pid < 0) { 71227910Sasami syslog(LOG_ERR, "fork: %m"); 71327910Sasami if (sep->se_accept && 71427910Sasami sep->se_socktype == SOCK_STREAM) 71527910Sasami close(ctrl); 71627910Sasami free_conn(conn); 71727910Sasami sigsetmask(0L); 71817308Speter sleep(1); 71911806Sphk continue; 72019175Sbde } 72127910Sasami if (pid) { 72227910Sasami addchild_conn(conn, pid); 72327910Sasami addchild(sep, pid); 72427910Sasami } 72527910Sasami sigsetmask(0L); 72627910Sasami if (pid == 0) { 72727910Sasami pidfile_close(pfh); 72827910Sasami if (dofork) { 72927910Sasami sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 73027910Sasami sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 73127910Sasami sigaction(SIGHUP, &sahup, (struct sigaction *)0); 73227910Sasami /* SIGPIPE reset before exec */ 73327910Sasami } 73427910Sasami /* 73527910Sasami * Call tcpmux to find the real service to exec. 73627910Sasami */ 73727910Sasami if (sep->se_bi && 73827910Sasami sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 73927910Sasami sep = tcpmux(ctrl); 74027910Sasami if (sep == NULL) { 74135621Sbde close(ctrl); 74236589Sjhay _exit(0); 74327910Sasami } 74434509Sbde } 74527910Sasami#ifdef LIBWRAP 74627910Sasami if (ISWRAP(sep)) { 74727910Sasami inetd_setproctitle("wrapping", ctrl); 74827910Sasami service = sep->se_server_name ? 74927910Sasami sep->se_server_name : sep->se_service; 75027910Sasami request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, 0); 75127910Sasami fromhost(&req); 75227910Sasami deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 75327910Sasami allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 75427910Sasami denied = !hosts_access(&req); 75536454Sjkh if (denied) { 75627910Sasami syslog(deny_severity, 75727910Sasami "refused connection from %.500s, service %s (%s%s)", 75827910Sasami eval_client(&req), service, sep->se_proto, 75927910Sasami (whichaf(&req) == AF_INET6) ? "6" : ""); 76027910Sasami if (sep->se_socktype != SOCK_STREAM) 76127910Sasami recv(ctrl, buf, sizeof (buf), 0); 76227910Sasami if (dofork) { 76327910Sasami sleep(1); 76419175Sbde _exit(0); 76527910Sasami } 76627910Sasami } 76727910Sasami if (dolog) { 76827910Sasami syslog(allow_severity, 76927910Sasami "connection from %.500s, service %s (%s%s)", 77027910Sasami eval_client(&req), service, sep->se_proto, 77127910Sasami (whichaf(&req) == AF_INET6) ? "6" : ""); 77227910Sasami } 77334688Sbde } 77427910Sasami#endif 77527910Sasami if (sep->se_bi) { 77627910Sasami (*sep->se_bi->bi_fn)(ctrl, sep); 77736455Sjkh } else { 77836455Sjkh if (debug) 77936074Sbde warnx("%d execl %s", 78036074Sbde getpid(), sep->se_server); 78130113Sjkh /* Clear close-on-exec. */ 78219175Sbde if (fcntl(ctrl, F_SETFD, 0) < 0) { 7832061Sjkh syslog(LOG_ERR, 78435479Sbde "%s/%s: fcntl (F_SETFD, 0): %m", 78530113Sjkh sep->se_service, sep->se_proto); 78630113Sjkh _exit(EX_OSERR); 78735294Sdt } 78830113Sjkh if (ctrl != 0) { 78930113Sjkh dup2(ctrl, 0); 79030113Sjkh close(ctrl); 79130113Sjkh } 79230113Sjkh dup2(0, 1); 79330113Sjkh dup2(0, 2); 79430113Sjkh if ((pwd = getpwnam(sep->se_user)) == NULL) { 79530113Sjkh syslog(LOG_ERR, 79630113Sjkh "%s/%s: %s: no such user", 79730113Sjkh sep->se_service, sep->se_proto, 79830113Sjkh sep->se_user); 79930113Sjkh if (sep->se_socktype != SOCK_STREAM) 80030113Sjkh recv(0, buf, sizeof (buf), 0); 80132427Sjb _exit(EX_NOUSER); 80232427Sjb } 8031594Srgrimes grp = NULL; 804 if ( sep->se_group != NULL 805 && (grp = getgrnam(sep->se_group)) == NULL 806 ) { 807 syslog(LOG_ERR, 808 "%s/%s: %s: no such group", 809 sep->se_service, sep->se_proto, 810 sep->se_group); 811 if (sep->se_socktype != SOCK_STREAM) 812 recv(0, buf, sizeof (buf), 0); 813 _exit(EX_NOUSER); 814 } 815 if (grp != NULL) 816 pwd->pw_gid = grp->gr_gid; 817#ifdef LOGIN_CAP 818 if ((lc = login_getclass(sep->se_class)) == NULL) { 819 /* error syslogged by getclass */ 820 syslog(LOG_ERR, 821 "%s/%s: %s: login class error", 822 sep->se_service, sep->se_proto, 823 sep->se_class); 824 if (sep->se_socktype != SOCK_STREAM) 825 recv(0, buf, sizeof (buf), 0); 826 _exit(EX_NOUSER); 827 } 828#endif 829 if (setsid() < 0) { 830 syslog(LOG_ERR, 831 "%s: can't setsid(): %m", 832 sep->se_service); 833 /* _exit(EX_OSERR); not fatal yet */ 834 } 835#ifdef LOGIN_CAP 836 if (setusercontext(lc, pwd, pwd->pw_uid, 837 LOGIN_SETALL & ~LOGIN_SETMAC) 838 != 0) { 839 syslog(LOG_ERR, 840 "%s: can't setusercontext(..%s..): %m", 841 sep->se_service, sep->se_user); 842 _exit(EX_OSERR); 843 } 844 login_close(lc); 845#else 846 if (pwd->pw_uid) { 847 if (setlogin(sep->se_user) < 0) { 848 syslog(LOG_ERR, 849 "%s: can't setlogin(%s): %m", 850 sep->se_service, sep->se_user); 851 /* _exit(EX_OSERR); not yet */ 852 } 853 if (setgid(pwd->pw_gid) < 0) { 854 syslog(LOG_ERR, 855 "%s: can't set gid %d: %m", 856 sep->se_service, pwd->pw_gid); 857 _exit(EX_OSERR); 858 } 859 (void) initgroups(pwd->pw_name, 860 pwd->pw_gid); 861 if (setuid(pwd->pw_uid) < 0) { 862 syslog(LOG_ERR, 863 "%s: can't set uid %d: %m", 864 sep->se_service, pwd->pw_uid); 865 _exit(EX_OSERR); 866 } 867 } 868#endif 869 sigaction(SIGPIPE, &sapipe, 870 (struct sigaction *)0); 871 execv(sep->se_server, sep->se_argv); 872 syslog(LOG_ERR, 873 "cannot execute %s: %m", sep->se_server); 874 if (sep->se_socktype != SOCK_STREAM) 875 recv(0, buf, sizeof (buf), 0); 876 } 877 if (dofork) 878 _exit(0); 879 } 880 if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 881 close(ctrl); 882 } 883 } 884} 885 886/* 887 * Add a signal flag to the signal flag queue for later handling 888 */ 889 890void 891flag_signal(int c) 892{ 893 char ch = c; 894 895 if (write(signalpipe[1], &ch, 1) != 1) { 896 syslog(LOG_ERR, "write: %m"); 897 _exit(EX_OSERR); 898 } 899} 900 901/* 902 * Record a new child pid for this service. If we've reached the 903 * limit on children, then stop accepting incoming requests. 904 */ 905 906void 907addchild(struct servtab *sep, pid_t pid) 908{ 909 if (sep->se_maxchild <= 0) 910 return; 911#ifdef SANITY_CHECK 912 if (sep->se_numchild >= sep->se_maxchild) { 913 syslog(LOG_ERR, "%s: %d >= %d", 914 __func__, sep->se_numchild, sep->se_maxchild); 915 exit(EX_SOFTWARE); 916 } 917#endif 918 sep->se_pids[sep->se_numchild++] = pid; 919 if (sep->se_numchild == sep->se_maxchild) 920 disable(sep); 921} 922 923/* 924 * Some child process has exited. See if it's on somebody's list. 925 */ 926 927void 928flag_reapchild(int signo __unused) 929{ 930 flag_signal('C'); 931} 932 933void 934reapchild(void) 935{ 936 int k, status; 937 pid_t pid; 938 struct servtab *sep; 939 940 for (;;) { 941 pid = wait3(&status, WNOHANG, (struct rusage *)0); 942 if (pid <= 0) 943 break; 944 if (debug) 945 warnx("%d reaped, %s %u", pid, 946 WIFEXITED(status) ? "status" : "signal", 947 WIFEXITED(status) ? WEXITSTATUS(status) 948 : WTERMSIG(status)); 949 for (sep = servtab; sep; sep = sep->se_next) { 950 for (k = 0; k < sep->se_numchild; k++) 951 if (sep->se_pids[k] == pid) 952 break; 953 if (k == sep->se_numchild) 954 continue; 955 if (sep->se_numchild == sep->se_maxchild) 956 enable(sep); 957 sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 958 if (WIFSIGNALED(status) || WEXITSTATUS(status)) 959 syslog(LOG_WARNING, 960 "%s[%d]: exited, %s %u", 961 sep->se_server, pid, 962 WIFEXITED(status) ? "status" : "signal", 963 WIFEXITED(status) ? WEXITSTATUS(status) 964 : WTERMSIG(status)); 965 break; 966 } 967 reapchild_conn(pid); 968 } 969} 970 971void 972flag_config(int signo __unused) 973{ 974 flag_signal('H'); 975} 976 977void 978config(void) 979{ 980 struct servtab *sep, *new, **sepp; 981 long omask; 982 int new_nomapped; 983#ifdef LOGIN_CAP 984 login_cap_t *lc = NULL; 985#endif 986 987 if (!setconfig()) { 988 syslog(LOG_ERR, "%s: %m", CONFIG); 989 return; 990 } 991 for (sep = servtab; sep; sep = sep->se_next) 992 sep->se_checked = 0; 993 while ((new = getconfigent())) { 994 if (getpwnam(new->se_user) == NULL) { 995 syslog(LOG_ERR, 996 "%s/%s: no such user '%s', service ignored", 997 new->se_service, new->se_proto, new->se_user); 998 continue; 999 } 1000 if (new->se_group && getgrnam(new->se_group) == NULL) { 1001 syslog(LOG_ERR, 1002 "%s/%s: no such group '%s', service ignored", 1003 new->se_service, new->se_proto, new->se_group); 1004 continue; 1005 } 1006#ifdef LOGIN_CAP 1007 if ((lc = login_getclass(new->se_class)) == NULL) { 1008 /* error syslogged by getclass */ 1009 syslog(LOG_ERR, 1010 "%s/%s: %s: login class error, service ignored", 1011 new->se_service, new->se_proto, new->se_class); 1012 continue; 1013 } 1014 login_close(lc); 1015#endif 1016 new_nomapped = new->se_nomapped; 1017 for (sep = servtab; sep; sep = sep->se_next) 1018 if (strcmp(sep->se_service, new->se_service) == 0 && 1019 strcmp(sep->se_proto, new->se_proto) == 0 && 1020 sep->se_rpc == new->se_rpc && 1021 sep->se_socktype == new->se_socktype && 1022 sep->se_family == new->se_family) 1023 break; 1024 if (sep != 0) { 1025 int i; 1026 1027#define SWAP(t,a, b) { t c = a; a = b; b = c; } 1028 omask = sigblock(SIGBLOCK); 1029 if (sep->se_nomapped != new->se_nomapped) { 1030 /* for rpc keep old nommaped till unregister */ 1031 if (!sep->se_rpc) 1032 sep->se_nomapped = new->se_nomapped; 1033 sep->se_reset = 1; 1034 } 1035 /* copy over outstanding child pids */ 1036 if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 1037 new->se_numchild = sep->se_numchild; 1038 if (new->se_numchild > new->se_maxchild) 1039 new->se_numchild = new->se_maxchild; 1040 memcpy(new->se_pids, sep->se_pids, 1041 new->se_numchild * sizeof(*new->se_pids)); 1042 } 1043 SWAP(pid_t *, sep->se_pids, new->se_pids); 1044 sep->se_maxchild = new->se_maxchild; 1045 sep->se_numchild = new->se_numchild; 1046 sep->se_maxcpm = new->se_maxcpm; 1047 resize_conn(sep, new->se_maxperip); 1048 sep->se_maxperip = new->se_maxperip; 1049 sep->se_bi = new->se_bi; 1050 /* might need to turn on or off service now */ 1051 if (sep->se_fd >= 0) { 1052 if (sep->se_maxchild > 0 1053 && sep->se_numchild == sep->se_maxchild) { 1054 if (FD_ISSET(sep->se_fd, &allsock)) 1055 disable(sep); 1056 } else { 1057 if (!FD_ISSET(sep->se_fd, &allsock)) 1058 enable(sep); 1059 } 1060 } 1061 sep->se_accept = new->se_accept; 1062 SWAP(char *, sep->se_user, new->se_user); 1063 SWAP(char *, sep->se_group, new->se_group); 1064#ifdef LOGIN_CAP 1065 SWAP(char *, sep->se_class, new->se_class); 1066#endif 1067 SWAP(char *, sep->se_server, new->se_server); 1068 SWAP(char *, sep->se_server_name, new->se_server_name); 1069 for (i = 0; i < MAXARGV; i++) 1070 SWAP(char *, sep->se_argv[i], new->se_argv[i]); 1071#ifdef IPSEC 1072 SWAP(char *, sep->se_policy, new->se_policy); 1073 ipsecsetup(sep); 1074#endif 1075 sigsetmask(omask); 1076 freeconfig(new); 1077 if (debug) 1078 print_service("REDO", sep); 1079 } else { 1080 sep = enter(new); 1081 if (debug) 1082 print_service("ADD ", sep); 1083 } 1084 sep->se_checked = 1; 1085 if (ISMUX(sep)) { 1086 sep->se_fd = -1; 1087 continue; 1088 } 1089 switch (sep->se_family) { 1090 case AF_INET: 1091 if (!v4bind_ok) { 1092 sep->se_fd = -1; 1093 continue; 1094 } 1095 break; 1096#ifdef INET6 1097 case AF_INET6: 1098 if (!v6bind_ok) { 1099 sep->se_fd = -1; 1100 continue; 1101 } 1102 break; 1103#endif 1104 } 1105 if (!sep->se_rpc) { 1106 if (sep->se_family != AF_UNIX) { 1107 sp = getservbyname(sep->se_service, sep->se_proto); 1108 if (sp == 0) { 1109 syslog(LOG_ERR, "%s/%s: unknown service", 1110 sep->se_service, sep->se_proto); 1111 sep->se_checked = 0; 1112 continue; 1113 } 1114 } 1115 switch (sep->se_family) { 1116 case AF_INET: 1117 if (sp->s_port != sep->se_ctrladdr4.sin_port) { 1118 sep->se_ctrladdr4.sin_port = 1119 sp->s_port; 1120 sep->se_reset = 1; 1121 } 1122 break; 1123#ifdef INET6 1124 case AF_INET6: 1125 if (sp->s_port != 1126 sep->se_ctrladdr6.sin6_port) { 1127 sep->se_ctrladdr6.sin6_port = 1128 sp->s_port; 1129 sep->se_reset = 1; 1130 } 1131 break; 1132#endif 1133 } 1134 if (sep->se_reset != 0 && sep->se_fd >= 0) 1135 close_sep(sep); 1136 } else { 1137 rpc = getrpcbyname(sep->se_service); 1138 if (rpc == 0) { 1139 syslog(LOG_ERR, "%s/%s unknown RPC service", 1140 sep->se_service, sep->se_proto); 1141 if (sep->se_fd != -1) 1142 (void) close(sep->se_fd); 1143 sep->se_fd = -1; 1144 continue; 1145 } 1146 if (sep->se_reset != 0 || 1147 rpc->r_number != sep->se_rpc_prog) { 1148 if (sep->se_rpc_prog) 1149 unregisterrpc(sep); 1150 sep->se_rpc_prog = rpc->r_number; 1151 if (sep->se_fd != -1) 1152 (void) close(sep->se_fd); 1153 sep->se_fd = -1; 1154 } 1155 sep->se_nomapped = new_nomapped; 1156 } 1157 sep->se_reset = 0; 1158 if (sep->se_fd == -1) 1159 setup(sep); 1160 } 1161 endconfig(); 1162 /* 1163 * Purge anything not looked at above. 1164 */ 1165 omask = sigblock(SIGBLOCK); 1166 sepp = &servtab; 1167 while ((sep = *sepp)) { 1168 if (sep->se_checked) { 1169 sepp = &sep->se_next; 1170 continue; 1171 } 1172 *sepp = sep->se_next; 1173 if (sep->se_fd >= 0) 1174 close_sep(sep); 1175 if (debug) 1176 print_service("FREE", sep); 1177 if (sep->se_rpc && sep->se_rpc_prog > 0) 1178 unregisterrpc(sep); 1179 freeconfig(sep); 1180 free(sep); 1181 } 1182 (void) sigsetmask(omask); 1183} 1184 1185void 1186unregisterrpc(struct servtab *sep) 1187{ 1188 u_int i; 1189 struct servtab *sepp; 1190 long omask; 1191 struct netconfig *netid4, *netid6; 1192 1193 omask = sigblock(SIGBLOCK); 1194 netid4 = sep->se_socktype == SOCK_DGRAM ? udpconf : tcpconf; 1195 netid6 = sep->se_socktype == SOCK_DGRAM ? udp6conf : tcp6conf; 1196 if (sep->se_family == AF_INET) 1197 netid6 = NULL; 1198 else if (sep->se_nomapped) 1199 netid4 = NULL; 1200 /* 1201 * Conflict if same prog and protocol - In that case one should look 1202 * to versions, but it is not interesting: having separate servers for 1203 * different versions does not work well. 1204 * Therefore one do not unregister if there is a conflict. 1205 * There is also transport conflict if destroying INET when INET46 1206 * exists, or destroying INET46 when INET exists 1207 */ 1208 for (sepp = servtab; sepp; sepp = sepp->se_next) { 1209 if (sepp == sep) 1210 continue; 1211 if (sepp->se_checked == 0 || 1212 !sepp->se_rpc || 1213 strcmp(sep->se_proto, sepp->se_proto) != 0 || 1214 sep->se_rpc_prog != sepp->se_rpc_prog) 1215 continue; 1216 if (sepp->se_family == AF_INET) 1217 netid4 = NULL; 1218 if (sepp->se_family == AF_INET6) { 1219 netid6 = NULL; 1220 if (!sep->se_nomapped) 1221 netid4 = NULL; 1222 } 1223 if (netid4 == NULL && netid6 == NULL) 1224 return; 1225 } 1226 if (debug) 1227 print_service("UNREG", sep); 1228 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1229 if (netid4) 1230 rpcb_unset(sep->se_rpc_prog, i, netid4); 1231 if (netid6) 1232 rpcb_unset(sep->se_rpc_prog, i, netid6); 1233 } 1234 if (sep->se_fd != -1) 1235 (void) close(sep->se_fd); 1236 sep->se_fd = -1; 1237 (void) sigsetmask(omask); 1238} 1239 1240void 1241flag_retry(int signo __unused) 1242{ 1243 flag_signal('A'); 1244} 1245 1246void 1247retry(void) 1248{ 1249 struct servtab *sep; 1250 1251 timingout = 0; 1252 for (sep = servtab; sep; sep = sep->se_next) 1253 if (sep->se_fd == -1 && !ISMUX(sep)) 1254 setup(sep); 1255} 1256 1257void 1258setup(struct servtab *sep) 1259{ 1260 int on = 1; 1261 1262 /* Set all listening sockets to close-on-exec. */ 1263 if ((sep->se_fd = socket(sep->se_family, 1264 sep->se_socktype | SOCK_CLOEXEC, 0)) < 0) { 1265 if (debug) 1266 warn("socket failed on %s/%s", 1267 sep->se_service, sep->se_proto); 1268 syslog(LOG_ERR, "%s/%s: socket: %m", 1269 sep->se_service, sep->se_proto); 1270 return; 1271 } 1272#define turnon(fd, opt) \ 1273setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 1274 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 1275 turnon(sep->se_fd, SO_DEBUG) < 0) 1276 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 1277 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 1278 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 1279#ifdef SO_PRIVSTATE 1280 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 1281 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 1282#endif 1283 /* tftpd opens a new connection then needs more infos */ 1284 if ((sep->se_family == AF_INET6) && 1285 (strcmp(sep->se_proto, "udp") == 0) && 1286 (sep->se_accept == 0) && 1287 (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1288 (char *)&on, sizeof (on)) < 0)) 1289 syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 1290 if (sep->se_family == AF_INET6) { 1291 int flag = sep->se_nomapped ? 1 : 0; 1292 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1293 (char *)&flag, sizeof (flag)) < 0) 1294 syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m"); 1295 } 1296#undef turnon 1297#ifdef IPV6_FAITH 1298 if (sep->se_type == FAITH_TYPE) { 1299 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 1300 sizeof(on)) < 0) { 1301 syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 1302 } 1303 } 1304#endif 1305#ifdef IPSEC 1306 ipsecsetup(sep); 1307#endif 1308 if (sep->se_family == AF_UNIX) { 1309 (void) unlink(sep->se_ctrladdr_un.sun_path); 1310 umask(0777); /* Make socket with conservative permissions */ 1311 } 1312 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 1313 sep->se_ctrladdr_size) < 0) { 1314 if (debug) 1315 warn("bind failed on %s/%s", 1316 sep->se_service, sep->se_proto); 1317 syslog(LOG_ERR, "%s/%s: bind: %m", 1318 sep->se_service, sep->se_proto); 1319 (void) close(sep->se_fd); 1320 sep->se_fd = -1; 1321 if (!timingout) { 1322 timingout = 1; 1323 alarm(RETRYTIME); 1324 } 1325 if (sep->se_family == AF_UNIX) 1326 umask(mask); 1327 return; 1328 } 1329 if (sep->se_family == AF_UNIX) { 1330 /* Ick - fch{own,mod} don't work on Unix domain sockets */ 1331 if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 1332 syslog(LOG_ERR, "chown socket: %m"); 1333 if (chmod(sep->se_service, sep->se_sockmode) < 0) 1334 syslog(LOG_ERR, "chmod socket: %m"); 1335 umask(mask); 1336 } 1337 if (sep->se_rpc) { 1338 u_int i; 1339 socklen_t len = sep->se_ctrladdr_size; 1340 struct netconfig *netid, *netid2 = NULL; 1341 struct sockaddr_in sock; 1342 struct netbuf nbuf, nbuf2; 1343 1344 if (getsockname(sep->se_fd, 1345 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 1346 syslog(LOG_ERR, "%s/%s: getsockname: %m", 1347 sep->se_service, sep->se_proto); 1348 (void) close(sep->se_fd); 1349 sep->se_fd = -1; 1350 return; 1351 } 1352 nbuf.buf = &sep->se_ctrladdr; 1353 nbuf.len = sep->se_ctrladdr.sa_len; 1354 if (sep->se_family == AF_INET) 1355 netid = sep->se_socktype==SOCK_DGRAM? udpconf:tcpconf; 1356 else { 1357 netid = sep->se_socktype==SOCK_DGRAM? udp6conf:tcp6conf; 1358 if (!sep->se_nomapped) { /* INET and INET6 */ 1359 netid2 = netid==udp6conf? udpconf:tcpconf; 1360 memset(&sock, 0, sizeof sock); /* ADDR_ANY */ 1361 nbuf2.buf = &sock; 1362 nbuf2.len = sock.sin_len = sizeof sock; 1363 sock.sin_family = AF_INET; 1364 sock.sin_port = sep->se_ctrladdr6.sin6_port; 1365 } 1366 } 1367 if (debug) 1368 print_service("REG ", sep); 1369 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1370 rpcb_unset(sep->se_rpc_prog, i, netid); 1371 rpcb_set(sep->se_rpc_prog, i, netid, &nbuf); 1372 if (netid2) { 1373 rpcb_unset(sep->se_rpc_prog, i, netid2); 1374 rpcb_set(sep->se_rpc_prog, i, netid2, &nbuf2); 1375 } 1376 } 1377 } 1378 if (sep->se_socktype == SOCK_STREAM) 1379 listen(sep->se_fd, -1); 1380 enable(sep); 1381 if (debug) { 1382 warnx("registered %s on %d", 1383 sep->se_server, sep->se_fd); 1384 } 1385} 1386 1387#ifdef IPSEC 1388void 1389ipsecsetup(struct servtab *sep) 1390{ 1391 char *buf; 1392 char *policy_in = NULL; 1393 char *policy_out = NULL; 1394 int level; 1395 int opt; 1396 1397 switch (sep->se_family) { 1398 case AF_INET: 1399 level = IPPROTO_IP; 1400 opt = IP_IPSEC_POLICY; 1401 break; 1402#ifdef INET6 1403 case AF_INET6: 1404 level = IPPROTO_IPV6; 1405 opt = IPV6_IPSEC_POLICY; 1406 break; 1407#endif 1408 default: 1409 return; 1410 } 1411 1412 if (!sep->se_policy || sep->se_policy[0] == '\0') { 1413 static char def_in[] = "in entrust", def_out[] = "out entrust"; 1414 policy_in = def_in; 1415 policy_out = def_out; 1416 } else { 1417 if (!strncmp("in", sep->se_policy, 2)) 1418 policy_in = sep->se_policy; 1419 else if (!strncmp("out", sep->se_policy, 3)) 1420 policy_out = sep->se_policy; 1421 else { 1422 syslog(LOG_ERR, "invalid security policy \"%s\"", 1423 sep->se_policy); 1424 return; 1425 } 1426 } 1427 1428 if (policy_in != NULL) { 1429 buf = ipsec_set_policy(policy_in, strlen(policy_in)); 1430 if (buf != NULL) { 1431 if (setsockopt(sep->se_fd, level, opt, 1432 buf, ipsec_get_policylen(buf)) < 0 && 1433 debug != 0) 1434 warnx("%s/%s: ipsec initialization failed; %s", 1435 sep->se_service, sep->se_proto, 1436 policy_in); 1437 free(buf); 1438 } else 1439 syslog(LOG_ERR, "invalid security policy \"%s\"", 1440 policy_in); 1441 } 1442 if (policy_out != NULL) { 1443 buf = ipsec_set_policy(policy_out, strlen(policy_out)); 1444 if (buf != NULL) { 1445 if (setsockopt(sep->se_fd, level, opt, 1446 buf, ipsec_get_policylen(buf)) < 0 && 1447 debug != 0) 1448 warnx("%s/%s: ipsec initialization failed; %s", 1449 sep->se_service, sep->se_proto, 1450 policy_out); 1451 free(buf); 1452 } else 1453 syslog(LOG_ERR, "invalid security policy \"%s\"", 1454 policy_out); 1455 } 1456} 1457#endif 1458 1459/* 1460 * Finish with a service and its socket. 1461 */ 1462void 1463close_sep(struct servtab *sep) 1464{ 1465 if (sep->se_fd >= 0) { 1466 if (FD_ISSET(sep->se_fd, &allsock)) 1467 disable(sep); 1468 (void) close(sep->se_fd); 1469 sep->se_fd = -1; 1470 } 1471 sep->se_count = 0; 1472 sep->se_numchild = 0; /* forget about any existing children */ 1473} 1474 1475int 1476matchservent(const char *name1, const char *name2, const char *proto) 1477{ 1478 char **alias, *p; 1479 struct servent *se; 1480 1481 if (strcmp(proto, "unix") == 0) { 1482 if ((p = strrchr(name1, '/')) != NULL) 1483 name1 = p + 1; 1484 if ((p = strrchr(name2, '/')) != NULL) 1485 name2 = p + 1; 1486 } 1487 if (strcmp(name1, name2) == 0) 1488 return(1); 1489 if ((se = getservbyname(name1, proto)) != NULL) { 1490 if (strcmp(name2, se->s_name) == 0) 1491 return(1); 1492 for (alias = se->s_aliases; *alias; alias++) 1493 if (strcmp(name2, *alias) == 0) 1494 return(1); 1495 } 1496 return(0); 1497} 1498 1499struct servtab * 1500enter(struct servtab *cp) 1501{ 1502 struct servtab *sep; 1503 long omask; 1504 1505 sep = (struct servtab *)malloc(sizeof (*sep)); 1506 if (sep == (struct servtab *)0) { 1507 syslog(LOG_ERR, "malloc: %m"); 1508 exit(EX_OSERR); 1509 } 1510 *sep = *cp; 1511 sep->se_fd = -1; 1512 omask = sigblock(SIGBLOCK); 1513 sep->se_next = servtab; 1514 servtab = sep; 1515 sigsetmask(omask); 1516 return (sep); 1517} 1518 1519void 1520enable(struct servtab *sep) 1521{ 1522 if (debug) 1523 warnx( 1524 "enabling %s, fd %d", sep->se_service, sep->se_fd); 1525#ifdef SANITY_CHECK 1526 if (sep->se_fd < 0) { 1527 syslog(LOG_ERR, 1528 "%s: %s: bad fd", __func__, sep->se_service); 1529 exit(EX_SOFTWARE); 1530 } 1531 if (ISMUX(sep)) { 1532 syslog(LOG_ERR, 1533 "%s: %s: is mux", __func__, sep->se_service); 1534 exit(EX_SOFTWARE); 1535 } 1536 if (FD_ISSET(sep->se_fd, &allsock)) { 1537 syslog(LOG_ERR, 1538 "%s: %s: not off", __func__, sep->se_service); 1539 exit(EX_SOFTWARE); 1540 } 1541 nsock++; 1542#endif 1543 FD_SET(sep->se_fd, &allsock); 1544 if (sep->se_fd > maxsock) 1545 maxsock = sep->se_fd; 1546} 1547 1548void 1549disable(struct servtab *sep) 1550{ 1551 if (debug) 1552 warnx( 1553 "disabling %s, fd %d", sep->se_service, sep->se_fd); 1554#ifdef SANITY_CHECK 1555 if (sep->se_fd < 0) { 1556 syslog(LOG_ERR, 1557 "%s: %s: bad fd", __func__, sep->se_service); 1558 exit(EX_SOFTWARE); 1559 } 1560 if (ISMUX(sep)) { 1561 syslog(LOG_ERR, 1562 "%s: %s: is mux", __func__, sep->se_service); 1563 exit(EX_SOFTWARE); 1564 } 1565 if (!FD_ISSET(sep->se_fd, &allsock)) { 1566 syslog(LOG_ERR, 1567 "%s: %s: not on", __func__, sep->se_service); 1568 exit(EX_SOFTWARE); 1569 } 1570 if (nsock == 0) { 1571 syslog(LOG_ERR, "%s: nsock=0", __func__); 1572 exit(EX_SOFTWARE); 1573 } 1574 nsock--; 1575#endif 1576 FD_CLR(sep->se_fd, &allsock); 1577 if (sep->se_fd == maxsock) 1578 maxsock--; 1579} 1580 1581FILE *fconfig = NULL; 1582struct servtab serv; 1583char line[LINE_MAX]; 1584 1585int 1586setconfig(void) 1587{ 1588 1589 if (fconfig != NULL) { 1590 fseek(fconfig, 0L, SEEK_SET); 1591 return (1); 1592 } 1593 fconfig = fopen(CONFIG, "r"); 1594 return (fconfig != NULL); 1595} 1596 1597void 1598endconfig(void) 1599{ 1600 if (fconfig) { 1601 (void) fclose(fconfig); 1602 fconfig = NULL; 1603 } 1604} 1605 1606struct servtab * 1607getconfigent(void) 1608{ 1609 struct servtab *sep = &serv; 1610 int argc; 1611 char *cp, *arg, *s; 1612 char *versp; 1613 static char TCPMUX_TOKEN[] = "tcpmux/"; 1614#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 1615#ifdef IPSEC 1616 char *policy; 1617#endif 1618 int v4bind; 1619#ifdef INET6 1620 int v6bind; 1621#endif 1622 int i; 1623 1624#ifdef IPSEC 1625 policy = NULL; 1626#endif 1627more: 1628 v4bind = 0; 1629#ifdef INET6 1630 v6bind = 0; 1631#endif 1632 while ((cp = nextline(fconfig)) != NULL) { 1633#ifdef IPSEC 1634 /* lines starting with #@ is not a comment, but the policy */ 1635 if (cp[0] == '#' && cp[1] == '@') { 1636 char *p; 1637 for (p = cp + 2; p && *p && isspace(*p); p++) 1638 ; 1639 if (*p == '\0') { 1640 if (policy) 1641 free(policy); 1642 policy = NULL; 1643 } else if (ipsec_get_policylen(p) >= 0) { 1644 if (policy) 1645 free(policy); 1646 policy = newstr(p); 1647 } else { 1648 syslog(LOG_ERR, 1649 "%s: invalid ipsec policy \"%s\"", 1650 CONFIG, p); 1651 exit(EX_CONFIG); 1652 } 1653 } 1654#endif 1655 if (*cp == '#' || *cp == '\0') 1656 continue; 1657 break; 1658 } 1659 if (cp == NULL) 1660 return ((struct servtab *)0); 1661 /* 1662 * clear the static buffer, since some fields (se_ctrladdr, 1663 * for example) don't get initialized here. 1664 */ 1665 memset(sep, 0, sizeof *sep); 1666 arg = skip(&cp); 1667 if (cp == NULL) { 1668 /* got an empty line containing just blanks/tabs. */ 1669 goto more; 1670 } 1671 if (arg[0] == ':') { /* :user:group:perm: */ 1672 char *user, *group, *perm; 1673 struct passwd *pw; 1674 struct group *gr; 1675 user = arg+1; 1676 if ((group = strchr(user, ':')) == NULL) { 1677 syslog(LOG_ERR, "no group after user '%s'", user); 1678 goto more; 1679 } 1680 *group++ = '\0'; 1681 if ((perm = strchr(group, ':')) == NULL) { 1682 syslog(LOG_ERR, "no mode after group '%s'", group); 1683 goto more; 1684 } 1685 *perm++ = '\0'; 1686 if ((pw = getpwnam(user)) == NULL) { 1687 syslog(LOG_ERR, "no such user '%s'", user); 1688 goto more; 1689 } 1690 sep->se_sockuid = pw->pw_uid; 1691 if ((gr = getgrnam(group)) == NULL) { 1692 syslog(LOG_ERR, "no such user '%s'", group); 1693 goto more; 1694 } 1695 sep->se_sockgid = gr->gr_gid; 1696 sep->se_sockmode = strtol(perm, &arg, 8); 1697 if (*arg != ':') { 1698 syslog(LOG_ERR, "bad mode '%s'", perm); 1699 goto more; 1700 } 1701 *arg++ = '\0'; 1702 } else { 1703 sep->se_sockuid = euid; 1704 sep->se_sockgid = egid; 1705 sep->se_sockmode = 0200; 1706 } 1707 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 1708 char *c = arg + MUX_LEN; 1709 if (*c == '+') { 1710 sep->se_type = MUXPLUS_TYPE; 1711 c++; 1712 } else 1713 sep->se_type = MUX_TYPE; 1714 sep->se_service = newstr(c); 1715 } else { 1716 sep->se_service = newstr(arg); 1717 sep->se_type = NORM_TYPE; 1718 } 1719 arg = sskip(&cp); 1720 if (strcmp(arg, "stream") == 0) 1721 sep->se_socktype = SOCK_STREAM; 1722 else if (strcmp(arg, "dgram") == 0) 1723 sep->se_socktype = SOCK_DGRAM; 1724 else if (strcmp(arg, "rdm") == 0) 1725 sep->se_socktype = SOCK_RDM; 1726 else if (strcmp(arg, "seqpacket") == 0) 1727 sep->se_socktype = SOCK_SEQPACKET; 1728 else if (strcmp(arg, "raw") == 0) 1729 sep->se_socktype = SOCK_RAW; 1730 else 1731 sep->se_socktype = -1; 1732 1733 arg = sskip(&cp); 1734 if (strncmp(arg, "tcp", 3) == 0) { 1735 sep->se_proto = newstr(strsep(&arg, "/")); 1736 if (arg != NULL) { 1737 if (strcmp(arg, "faith") == 0) 1738 sep->se_type = FAITH_TYPE; 1739 } 1740 } else { 1741 if (sep->se_type == NORM_TYPE && 1742 strncmp(arg, "faith/", 6) == 0) { 1743 arg += 6; 1744 sep->se_type = FAITH_TYPE; 1745 } 1746 sep->se_proto = newstr(arg); 1747 } 1748 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 1749 memmove(sep->se_proto, sep->se_proto + 4, 1750 strlen(sep->se_proto) + 1 - 4); 1751 sep->se_rpc = 1; 1752 sep->se_rpc_prog = sep->se_rpc_lowvers = 1753 sep->se_rpc_highvers = 0; 1754 if ((versp = strrchr(sep->se_service, '/'))) { 1755 *versp++ = '\0'; 1756 switch (sscanf(versp, "%u-%u", 1757 &sep->se_rpc_lowvers, 1758 &sep->se_rpc_highvers)) { 1759 case 2: 1760 break; 1761 case 1: 1762 sep->se_rpc_highvers = 1763 sep->se_rpc_lowvers; 1764 break; 1765 default: 1766 syslog(LOG_ERR, 1767 "bad RPC version specifier; %s", 1768 sep->se_service); 1769 freeconfig(sep); 1770 goto more; 1771 } 1772 } 1773 else { 1774 sep->se_rpc_lowvers = 1775 sep->se_rpc_highvers = 1; 1776 } 1777 } 1778 sep->se_nomapped = 0; 1779 if (strcmp(sep->se_proto, "unix") == 0) { 1780 sep->se_family = AF_UNIX; 1781 } else { 1782 while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 1783#ifdef INET6 1784 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1785 sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1786 v6bind = 1; 1787 continue; 1788 } 1789#endif 1790 if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1791 sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1792 v4bind = 1; 1793 continue; 1794 } 1795 /* illegal version num */ 1796 syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1797 freeconfig(sep); 1798 goto more; 1799 } 1800#ifdef INET6 1801 if (v6bind && !v6bind_ok) { 1802 syslog(LOG_INFO, "IPv6 bind is ignored for %s", 1803 sep->se_service); 1804 if (v4bind && v4bind_ok) 1805 v6bind = 0; 1806 else { 1807 freeconfig(sep); 1808 goto more; 1809 } 1810 } 1811 if (v6bind) { 1812 sep->se_family = AF_INET6; 1813 if (!v4bind || !v4bind_ok) 1814 sep->se_nomapped = 1; 1815 } else 1816#endif 1817 { /* default to v4 bind if not v6 bind */ 1818 if (!v4bind_ok) { 1819 syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1820 sep->se_service); 1821 freeconfig(sep); 1822 goto more; 1823 } 1824 sep->se_family = AF_INET; 1825 } 1826 } 1827 /* init ctladdr */ 1828 switch(sep->se_family) { 1829 case AF_INET: 1830 memcpy(&sep->se_ctrladdr4, bind_sa4, 1831 sizeof(sep->se_ctrladdr4)); 1832 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 1833 break; 1834#ifdef INET6 1835 case AF_INET6: 1836 memcpy(&sep->se_ctrladdr6, bind_sa6, 1837 sizeof(sep->se_ctrladdr6)); 1838 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 1839 break; 1840#endif 1841 case AF_UNIX: 1842 if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 1843 syslog(LOG_ERR, 1844 "domain socket pathname too long for service %s", 1845 sep->se_service); 1846 goto more; 1847 } 1848 memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 1849 sep->se_ctrladdr_un.sun_family = sep->se_family; 1850 sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 1851 strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 1852 sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 1853 } 1854 arg = sskip(&cp); 1855 if (!strncmp(arg, "wait", 4)) 1856 sep->se_accept = 0; 1857 else if (!strncmp(arg, "nowait", 6)) 1858 sep->se_accept = 1; 1859 else { 1860 syslog(LOG_ERR, 1861 "%s: bad wait/nowait for service %s", 1862 CONFIG, sep->se_service); 1863 goto more; 1864 } 1865 sep->se_maxchild = -1; 1866 sep->se_maxcpm = -1; 1867 sep->se_maxperip = -1; 1868 if ((s = strchr(arg, '/')) != NULL) { 1869 char *eptr; 1870 u_long val; 1871 1872 val = strtoul(s + 1, &eptr, 10); 1873 if (eptr == s + 1 || val > MAX_MAXCHLD) { 1874 syslog(LOG_ERR, 1875 "%s: bad max-child for service %s", 1876 CONFIG, sep->se_service); 1877 goto more; 1878 } 1879 if (debug) 1880 if (!sep->se_accept && val != 1) 1881 warnx("maxchild=%lu for wait service %s" 1882 " not recommended", val, sep->se_service); 1883 sep->se_maxchild = val; 1884 if (*eptr == '/') 1885 sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1886 if (*eptr == '/') 1887 sep->se_maxperip = strtol(eptr + 1, &eptr, 10); 1888 /* 1889 * explicitly do not check for \0 for future expansion / 1890 * backwards compatibility 1891 */ 1892 } 1893 if (ISMUX(sep)) { 1894 /* 1895 * Silently enforce "nowait" mode for TCPMUX services 1896 * since they don't have an assigned port to listen on. 1897 */ 1898 sep->se_accept = 1; 1899 if (strcmp(sep->se_proto, "tcp")) { 1900 syslog(LOG_ERR, 1901 "%s: bad protocol for tcpmux service %s", 1902 CONFIG, sep->se_service); 1903 goto more; 1904 } 1905 if (sep->se_socktype != SOCK_STREAM) { 1906 syslog(LOG_ERR, 1907 "%s: bad socket type for tcpmux service %s", 1908 CONFIG, sep->se_service); 1909 goto more; 1910 } 1911 } 1912 sep->se_user = newstr(sskip(&cp)); 1913#ifdef LOGIN_CAP 1914 if ((s = strrchr(sep->se_user, '/')) != NULL) { 1915 *s = '\0'; 1916 sep->se_class = newstr(s + 1); 1917 } else 1918 sep->se_class = newstr(RESOURCE_RC); 1919#endif 1920 if ((s = strrchr(sep->se_user, ':')) != NULL) { 1921 *s = '\0'; 1922 sep->se_group = newstr(s + 1); 1923 } else 1924 sep->se_group = NULL; 1925 sep->se_server = newstr(sskip(&cp)); 1926 if ((sep->se_server_name = strrchr(sep->se_server, '/'))) 1927 sep->se_server_name++; 1928 if (strcmp(sep->se_server, "internal") == 0) { 1929 struct biltin *bi; 1930 1931 for (bi = biltins; bi->bi_service; bi++) 1932 if (bi->bi_socktype == sep->se_socktype && 1933 matchservent(bi->bi_service, sep->se_service, 1934 sep->se_proto)) 1935 break; 1936 if (bi->bi_service == 0) { 1937 syslog(LOG_ERR, "internal service %s unknown", 1938 sep->se_service); 1939 goto more; 1940 } 1941 sep->se_accept = 1; /* force accept mode for built-ins */ 1942 sep->se_bi = bi; 1943 } else 1944 sep->se_bi = NULL; 1945 if (sep->se_maxperip < 0) 1946 sep->se_maxperip = maxperip; 1947 if (sep->se_maxcpm < 0) 1948 sep->se_maxcpm = maxcpm; 1949 if (sep->se_maxchild < 0) { /* apply default max-children */ 1950 if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 1951 sep->se_maxchild = sep->se_bi->bi_maxchild; 1952 else if (sep->se_accept) 1953 sep->se_maxchild = maxchild > 0 ? maxchild : 0; 1954 else 1955 sep->se_maxchild = 1; 1956 } 1957 if (sep->se_maxchild > 0) { 1958 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 1959 if (sep->se_pids == NULL) { 1960 syslog(LOG_ERR, "malloc: %m"); 1961 exit(EX_OSERR); 1962 } 1963 } 1964 argc = 0; 1965 for (arg = skip(&cp); cp; arg = skip(&cp)) 1966 if (argc < MAXARGV) { 1967 sep->se_argv[argc++] = newstr(arg); 1968 } else { 1969 syslog(LOG_ERR, 1970 "%s: too many arguments for service %s", 1971 CONFIG, sep->se_service); 1972 goto more; 1973 } 1974 while (argc <= MAXARGV) 1975 sep->se_argv[argc++] = NULL; 1976 for (i = 0; i < PERIPSIZE; ++i) 1977 LIST_INIT(&sep->se_conn[i]); 1978#ifdef IPSEC 1979 sep->se_policy = policy ? newstr(policy) : NULL; 1980#endif 1981 return (sep); 1982} 1983 1984void 1985freeconfig(struct servtab *cp) 1986{ 1987 int i; 1988 1989 if (cp->se_service) 1990 free(cp->se_service); 1991 if (cp->se_proto) 1992 free(cp->se_proto); 1993 if (cp->se_user) 1994 free(cp->se_user); 1995 if (cp->se_group) 1996 free(cp->se_group); 1997#ifdef LOGIN_CAP 1998 if (cp->se_class) 1999 free(cp->se_class); 2000#endif 2001 if (cp->se_server) 2002 free(cp->se_server); 2003 if (cp->se_pids) 2004 free(cp->se_pids); 2005 for (i = 0; i < MAXARGV; i++) 2006 if (cp->se_argv[i]) 2007 free(cp->se_argv[i]); 2008 free_connlist(cp); 2009#ifdef IPSEC 2010 if (cp->se_policy) 2011 free(cp->se_policy); 2012#endif 2013} 2014 2015 2016/* 2017 * Safe skip - if skip returns null, log a syntax error in the 2018 * configuration file and exit. 2019 */ 2020char * 2021sskip(char **cpp) 2022{ 2023 char *cp; 2024 2025 cp = skip(cpp); 2026 if (cp == NULL) { 2027 syslog(LOG_ERR, "%s: syntax error", CONFIG); 2028 exit(EX_DATAERR); 2029 } 2030 return (cp); 2031} 2032 2033char * 2034skip(char **cpp) 2035{ 2036 char *cp = *cpp; 2037 char *start; 2038 char quote = '\0'; 2039 2040again: 2041 while (*cp == ' ' || *cp == '\t') 2042 cp++; 2043 if (*cp == '\0') { 2044 int c; 2045 2046 c = getc(fconfig); 2047 (void) ungetc(c, fconfig); 2048 if (c == ' ' || c == '\t') 2049 if ((cp = nextline(fconfig))) 2050 goto again; 2051 *cpp = (char *)0; 2052 return ((char *)0); 2053 } 2054 if (*cp == '"' || *cp == '\'') 2055 quote = *cp++; 2056 start = cp; 2057 if (quote) 2058 while (*cp && *cp != quote) 2059 cp++; 2060 else 2061 while (*cp && *cp != ' ' && *cp != '\t') 2062 cp++; 2063 if (*cp != '\0') 2064 *cp++ = '\0'; 2065 *cpp = cp; 2066 return (start); 2067} 2068 2069char * 2070nextline(FILE *fd) 2071{ 2072 char *cp; 2073 2074 if (fgets(line, sizeof (line), fd) == NULL) 2075 return ((char *)0); 2076 cp = strchr(line, '\n'); 2077 if (cp) 2078 *cp = '\0'; 2079 return (line); 2080} 2081 2082char * 2083newstr(const char *cp) 2084{ 2085 char *cr; 2086 2087 if ((cr = strdup(cp != NULL ? cp : ""))) 2088 return (cr); 2089 syslog(LOG_ERR, "strdup: %m"); 2090 exit(EX_OSERR); 2091} 2092 2093void 2094inetd_setproctitle(const char *a, int s) 2095{ 2096 socklen_t size; 2097 struct sockaddr_storage ss; 2098 char buf[80], pbuf[NI_MAXHOST]; 2099 2100 size = sizeof(ss); 2101 if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 2102 getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 2103 NULL, 0, NI_NUMERICHOST); 2104 (void) sprintf(buf, "%s [%s]", a, pbuf); 2105 } else 2106 (void) sprintf(buf, "%s", a); 2107 setproctitle("%s", buf); 2108} 2109 2110int 2111check_loop(const struct sockaddr *sa, const struct servtab *sep) 2112{ 2113 struct servtab *se2; 2114 char pname[NI_MAXHOST]; 2115 2116 for (se2 = servtab; se2; se2 = se2->se_next) { 2117 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 2118 continue; 2119 2120 switch (se2->se_family) { 2121 case AF_INET: 2122 if (((const struct sockaddr_in *)sa)->sin_port == 2123 se2->se_ctrladdr4.sin_port) 2124 goto isloop; 2125 continue; 2126#ifdef INET6 2127 case AF_INET6: 2128 if (((const struct sockaddr_in6 *)sa)->sin6_port == 2129 se2->se_ctrladdr6.sin6_port) 2130 goto isloop; 2131 continue; 2132#endif 2133 default: 2134 continue; 2135 } 2136 isloop: 2137 getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 2138 NI_NUMERICHOST); 2139 syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 2140 sep->se_service, sep->se_proto, 2141 se2->se_service, se2->se_proto, 2142 pname); 2143 return 1; 2144 } 2145 return 0; 2146} 2147 2148/* 2149 * print_service: 2150 * Dump relevant information to stderr 2151 */ 2152void 2153print_service(const char *action, const struct servtab *sep) 2154{ 2155 fprintf(stderr, 2156 "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 2157#ifdef LOGIN_CAP 2158 "class=%s" 2159#endif 2160 " builtin=%p server=%s" 2161#ifdef IPSEC 2162 " policy=\"%s\"" 2163#endif 2164 "\n", 2165 action, sep->se_service, sep->se_proto, 2166 sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 2167#ifdef LOGIN_CAP 2168 sep->se_class, 2169#endif 2170 (void *) sep->se_bi, sep->se_server 2171#ifdef IPSEC 2172 , (sep->se_policy ? sep->se_policy : "") 2173#endif 2174 ); 2175} 2176 2177#define CPMHSIZE 256 2178#define CPMHMASK (CPMHSIZE-1) 2179#define CHTGRAN 10 2180#define CHTSIZE 6 2181 2182typedef struct CTime { 2183 unsigned long ct_Ticks; 2184 int ct_Count; 2185} CTime; 2186 2187typedef struct CHash { 2188 union { 2189 struct in_addr c4_Addr; 2190 struct in6_addr c6_Addr; 2191 } cu_Addr; 2192#define ch_Addr4 cu_Addr.c4_Addr 2193#define ch_Addr6 cu_Addr.c6_Addr 2194 int ch_Family; 2195 time_t ch_LTime; 2196 char *ch_Service; 2197 CTime ch_Times[CHTSIZE]; 2198} CHash; 2199 2200CHash CHashAry[CPMHSIZE]; 2201 2202int 2203cpmip(const struct servtab *sep, int ctrl) 2204{ 2205 struct sockaddr_storage rss; 2206 socklen_t rssLen = sizeof(rss); 2207 int r = 0; 2208 2209 /* 2210 * If getpeername() fails, just let it through (if logging is 2211 * enabled the condition is caught elsewhere) 2212 */ 2213 2214 if (sep->se_maxcpm > 0 && 2215 (sep->se_family == AF_INET || sep->se_family == AF_INET6) && 2216 getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 2217 time_t t = time(NULL); 2218 int hv = 0xABC3D20F; 2219 int i; 2220 int cnt = 0; 2221 CHash *chBest = NULL; 2222 unsigned int ticks = t / CHTGRAN; 2223 struct sockaddr_in *sin4; 2224#ifdef INET6 2225 struct sockaddr_in6 *sin6; 2226#endif 2227 2228 sin4 = (struct sockaddr_in *)&rss; 2229#ifdef INET6 2230 sin6 = (struct sockaddr_in6 *)&rss; 2231#endif 2232 { 2233 char *p; 2234 int addrlen; 2235 2236 switch (rss.ss_family) { 2237 case AF_INET: 2238 p = (char *)&sin4->sin_addr; 2239 addrlen = sizeof(struct in_addr); 2240 break; 2241#ifdef INET6 2242 case AF_INET6: 2243 p = (char *)&sin6->sin6_addr; 2244 addrlen = sizeof(struct in6_addr); 2245 break; 2246#endif 2247 default: 2248 /* should not happen */ 2249 return -1; 2250 } 2251 2252 for (i = 0; i < addrlen; ++i, ++p) { 2253 hv = (hv << 5) ^ (hv >> 23) ^ *p; 2254 } 2255 hv = (hv ^ (hv >> 16)); 2256 } 2257 for (i = 0; i < 5; ++i) { 2258 CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 2259 2260 if (rss.ss_family == AF_INET && 2261 ch->ch_Family == AF_INET && 2262 sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 2263 ch->ch_Service && strcmp(sep->se_service, 2264 ch->ch_Service) == 0) { 2265 chBest = ch; 2266 break; 2267 } 2268#ifdef INET6 2269 if (rss.ss_family == AF_INET6 && 2270 ch->ch_Family == AF_INET6 && 2271 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 2272 &ch->ch_Addr6) != 0 && 2273 ch->ch_Service && strcmp(sep->se_service, 2274 ch->ch_Service) == 0) { 2275 chBest = ch; 2276 break; 2277 } 2278#endif 2279 if (chBest == NULL || ch->ch_LTime == 0 || 2280 ch->ch_LTime < chBest->ch_LTime) { 2281 chBest = ch; 2282 } 2283 } 2284 if ((rss.ss_family == AF_INET && 2285 (chBest->ch_Family != AF_INET || 2286 sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 2287 chBest->ch_Service == NULL || 2288 strcmp(sep->se_service, chBest->ch_Service) != 0) { 2289 chBest->ch_Family = sin4->sin_family; 2290 chBest->ch_Addr4 = sin4->sin_addr; 2291 if (chBest->ch_Service) 2292 free(chBest->ch_Service); 2293 chBest->ch_Service = strdup(sep->se_service); 2294 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 2295 } 2296#ifdef INET6 2297 if ((rss.ss_family == AF_INET6 && 2298 (chBest->ch_Family != AF_INET6 || 2299 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 2300 &chBest->ch_Addr6) == 0)) || 2301 chBest->ch_Service == NULL || 2302 strcmp(sep->se_service, chBest->ch_Service) != 0) { 2303 chBest->ch_Family = sin6->sin6_family; 2304 chBest->ch_Addr6 = sin6->sin6_addr; 2305 if (chBest->ch_Service) 2306 free(chBest->ch_Service); 2307 chBest->ch_Service = strdup(sep->se_service); 2308 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 2309 } 2310#endif 2311 chBest->ch_LTime = t; 2312 { 2313 CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 2314 if (ct->ct_Ticks != ticks) { 2315 ct->ct_Ticks = ticks; 2316 ct->ct_Count = 0; 2317 } 2318 ++ct->ct_Count; 2319 } 2320 for (i = 0; i < CHTSIZE; ++i) { 2321 CTime *ct = &chBest->ch_Times[i]; 2322 if (ct->ct_Ticks <= ticks && 2323 ct->ct_Ticks >= ticks - CHTSIZE) { 2324 cnt += ct->ct_Count; 2325 } 2326 } 2327 if ((cnt * 60) / (CHTSIZE * CHTGRAN) > sep->se_maxcpm) { 2328 char pname[NI_MAXHOST]; 2329 2330 getnameinfo((struct sockaddr *)&rss, 2331 ((struct sockaddr *)&rss)->sa_len, 2332 pname, sizeof(pname), NULL, 0, 2333 NI_NUMERICHOST); 2334 r = -1; 2335 syslog(LOG_ERR, 2336 "%s from %s exceeded counts/min (limit %d/min)", 2337 sep->se_service, pname, 2338 sep->se_maxcpm); 2339 } 2340 } 2341 return(r); 2342} 2343 2344static struct conninfo * 2345search_conn(struct servtab *sep, int ctrl) 2346{ 2347 struct sockaddr_storage ss; 2348 socklen_t sslen = sizeof(ss); 2349 struct conninfo *conn; 2350 int hv; 2351 char pname[NI_MAXHOST], pname2[NI_MAXHOST]; 2352 2353 if (sep->se_maxperip <= 0) 2354 return NULL; 2355 2356 /* 2357 * If getpeername() fails, just let it through (if logging is 2358 * enabled the condition is caught elsewhere) 2359 */ 2360 if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0) 2361 return NULL; 2362 2363 switch (ss.ss_family) { 2364 case AF_INET: 2365 hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr, 2366 sizeof(struct in_addr)); 2367 break; 2368#ifdef INET6 2369 case AF_INET6: 2370 hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr, 2371 sizeof(struct in6_addr)); 2372 break; 2373#endif 2374 default: 2375 /* 2376 * Since we only support AF_INET and AF_INET6, just 2377 * let other than AF_INET and AF_INET6 through. 2378 */ 2379 return NULL; 2380 } 2381 2382 if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname), 2383 NULL, 0, NI_NUMERICHOST) != 0) 2384 return NULL; 2385 2386 LIST_FOREACH(conn, &sep->se_conn[hv], co_link) { 2387 if (getnameinfo((struct sockaddr *)&conn->co_addr, 2388 conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0, 2389 NI_NUMERICHOST) == 0 && 2390 strcmp(pname, pname2) == 0) 2391 break; 2392 } 2393 2394 if (conn == NULL) { 2395 if ((conn = malloc(sizeof(struct conninfo))) == NULL) { 2396 syslog(LOG_ERR, "malloc: %m"); 2397 exit(EX_OSERR); 2398 } 2399 conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc)); 2400 if (conn->co_proc == NULL) { 2401 syslog(LOG_ERR, "malloc: %m"); 2402 exit(EX_OSERR); 2403 } 2404 memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen); 2405 conn->co_numchild = 0; 2406 LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link); 2407 } 2408 2409 /* 2410 * Since a child process is not invoked yet, we cannot 2411 * determine a pid of a child. So, co_proc and co_numchild 2412 * should be filled leter. 2413 */ 2414 2415 return conn; 2416} 2417 2418static int 2419room_conn(struct servtab *sep, struct conninfo *conn) 2420{ 2421 char pname[NI_MAXHOST]; 2422 2423 if (conn->co_numchild >= sep->se_maxperip) { 2424 getnameinfo((struct sockaddr *)&conn->co_addr, 2425 conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0, 2426 NI_NUMERICHOST); 2427 syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)", 2428 sep->se_service, pname, sep->se_maxperip); 2429 return 0; 2430 } 2431 return 1; 2432} 2433 2434static void 2435addchild_conn(struct conninfo *conn, pid_t pid) 2436{ 2437 struct procinfo *proc; 2438 2439 if (conn == NULL) 2440 return; 2441 2442 if ((proc = search_proc(pid, 1)) != NULL) { 2443 if (proc->pr_conn != NULL) { 2444 syslog(LOG_ERR, 2445 "addchild_conn: child already on process list"); 2446 exit(EX_OSERR); 2447 } 2448 proc->pr_conn = conn; 2449 } 2450 2451 conn->co_proc[conn->co_numchild++] = proc; 2452} 2453 2454static void 2455reapchild_conn(pid_t pid) 2456{ 2457 struct procinfo *proc; 2458 struct conninfo *conn; 2459 int i; 2460 2461 if ((proc = search_proc(pid, 0)) == NULL) 2462 return; 2463 if ((conn = proc->pr_conn) == NULL) 2464 return; 2465 for (i = 0; i < conn->co_numchild; ++i) 2466 if (conn->co_proc[i] == proc) { 2467 conn->co_proc[i] = conn->co_proc[--conn->co_numchild]; 2468 break; 2469 } 2470 free_proc(proc); 2471 free_conn(conn); 2472} 2473 2474static void 2475resize_conn(struct servtab *sep, int maxpip) 2476{ 2477 struct conninfo *conn; 2478 int i, j; 2479 2480 if (sep->se_maxperip <= 0) 2481 return; 2482 if (maxpip <= 0) { 2483 free_connlist(sep); 2484 return; 2485 } 2486 for (i = 0; i < PERIPSIZE; ++i) { 2487 LIST_FOREACH(conn, &sep->se_conn[i], co_link) { 2488 for (j = maxpip; j < conn->co_numchild; ++j) 2489 free_proc(conn->co_proc[j]); 2490 conn->co_proc = realloc(conn->co_proc, 2491 maxpip * sizeof(*conn->co_proc)); 2492 if (conn->co_proc == NULL) { 2493 syslog(LOG_ERR, "realloc: %m"); 2494 exit(EX_OSERR); 2495 } 2496 if (conn->co_numchild > maxpip) 2497 conn->co_numchild = maxpip; 2498 } 2499 } 2500} 2501 2502static void 2503free_connlist(struct servtab *sep) 2504{ 2505 struct conninfo *conn; 2506 int i, j; 2507 2508 for (i = 0; i < PERIPSIZE; ++i) { 2509 while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) { 2510 for (j = 0; j < conn->co_numchild; ++j) 2511 free_proc(conn->co_proc[j]); 2512 conn->co_numchild = 0; 2513 free_conn(conn); 2514 } 2515 } 2516} 2517 2518static void 2519free_conn(struct conninfo *conn) 2520{ 2521 if (conn == NULL) 2522 return; 2523 if (conn->co_numchild <= 0) { 2524 LIST_REMOVE(conn, co_link); 2525 free(conn->co_proc); 2526 free(conn); 2527 } 2528} 2529 2530static struct procinfo * 2531search_proc(pid_t pid, int add) 2532{ 2533 struct procinfo *proc; 2534 int hv; 2535 2536 hv = hashval((char *)&pid, sizeof(pid)); 2537 LIST_FOREACH(proc, &proctable[hv], pr_link) { 2538 if (proc->pr_pid == pid) 2539 break; 2540 } 2541 if (proc == NULL && add) { 2542 if ((proc = malloc(sizeof(struct procinfo))) == NULL) { 2543 syslog(LOG_ERR, "malloc: %m"); 2544 exit(EX_OSERR); 2545 } 2546 proc->pr_pid = pid; 2547 proc->pr_conn = NULL; 2548 LIST_INSERT_HEAD(&proctable[hv], proc, pr_link); 2549 } 2550 return proc; 2551} 2552 2553static void 2554free_proc(struct procinfo *proc) 2555{ 2556 if (proc == NULL) 2557 return; 2558 LIST_REMOVE(proc, pr_link); 2559 free(proc); 2560} 2561 2562static int 2563hashval(char *p, int len) 2564{ 2565 int i, hv = 0xABC3D20F; 2566 2567 for (i = 0; i < len; ++i, ++p) 2568 hv = (hv << 5) ^ (hv >> 23) ^ *p; 2569 hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1); 2570 return hv; 2571} 2572