inetd.c revision 98562
1139776Simp/* 21541Srgrimes * Copyright (c) 1983, 1991, 1993, 1994 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 3222521Sdyson */ 331541Srgrimes 3422521Sdyson#ifndef lint 3522521Sdysonstatic const char copyright[] = 3622521Sdyson"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 3722521Sdyson The Regents of the University of California. All rights reserved.\n"; 3822521Sdyson#endif /* not lint */ 3950477Speter 401541Srgrimes#ifndef lint 411541Srgrimes#if 0 421541Srgrimesstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 431541Srgrimes#endif 441541Srgrimesstatic const char rcsid[] = 4577130Sru "$FreeBSD: head/usr.sbin/inetd/inetd.c 98562 2002-06-21 11:42:37Z jmallett $"; 461541Srgrimes#endif /* not lint */ 4796755Strhodes 481541Srgrimes/* 4996755Strhodes * Inetd - Internet super-server 501541Srgrimes * 5135256Sdes * This program invokes all internet services as needed. Connection-oriented 521541Srgrimes * services are invoked each time a connection is made, by creating a process. 531541Srgrimes * This process is passed the connection as file descriptor 0 and is expected 541541Srgrimes * to do a getpeername to find out the source host and port. 551541Srgrimes * 5696755Strhodes * Datagram oriented services are invoked when a datagram 571541Srgrimes * arrives; a process is created and passed a pending message 581541Srgrimes * on file descriptor 0. Datagram servers may either connect 5996755Strhodes * to their peer, freeing up the original socket for inetd 601541Srgrimes * to receive further messages on, or ``take over the socket'', 611541Srgrimes * processing all arriving datagrams and, eventually, timing 621541Srgrimes * out. The first type of server is said to be ``multi-threaded''; 631541Srgrimes * the second type of server ``single-threaded''. 641541Srgrimes * 651541Srgrimes * Inetd uses a configuration file which is read at startup 661541Srgrimes * and, possibly, at some later time in response to a hangup signal. 671541Srgrimes * The configuration file is ``free format'' with fields given in the 6877130Sru * order shown below. Continuation lines for an entry must begin with 6977130Sru * a space or tab. All fields must be present in each entry. 701541Srgrimes * 711541Srgrimes * service name must be in /etc/services 721541Srgrimes * or name a tcpmux service 731541Srgrimes * or specify a unix domain socket 741541Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 751541Srgrimes * protocol tcp[4][6][/faith,ttcp], udp[4][6], unix 761541Srgrimes * wait/nowait single-threaded/multi-threaded 771541Srgrimes * user user to run daemon as 7896755Strhodes * server program full path name 791541Srgrimes * server program arguments maximum of MAXARGS (20) 801541Srgrimes * 8126963Salex * TCP services without official port numbers are handled with the 821541Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 831541Srgrimes * requests. When a connection is made from a foreign host, the service 841541Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 851541Srgrimes * and returns the proper entry for the service. Tcpmux returns a 861541Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 871541Srgrimes * server is expected to return the positive reply if the service type in 881541Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 891541Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 901541Srgrimes * process; this is for compatibility with older server code, and also 911541Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 9222521Sdyson * special server code in them. Services that use tcpmux are "nowait" 9322521Sdyson * because they do not have a well-known port and hence cannot listen 9422521Sdyson * for new requests. 9522521Sdyson * 9622521Sdyson * For RPC services 971541Srgrimes * service name/version must be in /etc/rpc 9822521Sdyson * socket type stream/dgram/raw/rdm/seqpacket 9922521Sdyson * protocol rpc/tcp, rpc/udp 10022521Sdyson * wait/nowait single-threaded/multi-threaded 10122521Sdyson * user user to run daemon as 10222521Sdyson * server program full path name 10322521Sdyson * server program arguments maximum of MAXARGS 10422521Sdyson * 10522521Sdyson * Comment lines are indicated by a `#' in column 1. 10622521Sdyson * 1071541Srgrimes * #ifdef IPSEC 1081541Srgrimes * Comment lines that start with "#@" denote IPsec policy string, as described 1091541Srgrimes * in ipsec_set_policy(3). This will affect all the following items in 1101541Srgrimes * inetd.conf(8). To reset the policy, just use "#@" line. By default, 1111541Srgrimes * there's no IPsec policy. 1121541Srgrimes * #endif 1131541Srgrimes */ 1141541Srgrimes#include <sys/param.h> 1151541Srgrimes#include <sys/ioctl.h> 1161541Srgrimes#include <sys/wait.h> 1171541Srgrimes#include <sys/time.h> 1181541Srgrimes#include <sys/resource.h> 1191541Srgrimes#include <sys/stat.h> 1201541Srgrimes#include <sys/un.h> 1218876Srgrimes 1221541Srgrimes#include <netinet/in.h> 1231541Srgrimes#include <netinet/tcp.h> 1241541Srgrimes#include <arpa/inet.h> 1251541Srgrimes#include <rpc/rpc.h> 12677130Sru#include <rpc/pmap_clnt.h> 1271541Srgrimes 1281541Srgrimes#include <errno.h> 1291541Srgrimes#include <err.h> 1301541Srgrimes#include <fcntl.h> 1318876Srgrimes#include <grp.h> 1321541Srgrimes#include <netdb.h> 1331541Srgrimes#include <pwd.h> 1341541Srgrimes#include <signal.h> 1351541Srgrimes#include <stdio.h> 1361541Srgrimes#include <stdlib.h> 1371541Srgrimes#include <string.h> 1381541Srgrimes#include <syslog.h> 1391541Srgrimes#include <tcpd.h> 14096755Strhodes#include <unistd.h> 1411541Srgrimes#include <libutil.h> 1421541Srgrimes#include <sysexits.h> 1431541Srgrimes#include <ctype.h> 1441541Srgrimes 1458876Srgrimes#include "inetd.h" 1461541Srgrimes#include "pathnames.h" 1471541Srgrimes 1481541Srgrimes#ifdef IPSEC 1491541Srgrimes#include <netinet6/ipsec.h> 1501541Srgrimes#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */ 1518876Srgrimes#undef IPSEC 1521541Srgrimes#endif 1531541Srgrimes#endif 1541541Srgrimes 1551541Srgrimes/* wrapper for KAME-special getnameinfo() */ 156108470Sschweikh#ifndef NI_WITHSCOPEID 1571541Srgrimes#define NI_WITHSCOPEID 0 1581541Srgrimes#endif 1591541Srgrimes 16026964Salex#ifndef LIBWRAP_ALLOW_FACILITY 1611541Srgrimes# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 1621541Srgrimes#endif 1631541Srgrimes#ifndef LIBWRAP_ALLOW_SEVERITY 16426964Salex# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 1651541Srgrimes#endif 1661541Srgrimes#ifndef LIBWRAP_DENY_FACILITY 1671541Srgrimes# define LIBWRAP_DENY_FACILITY LOG_AUTH 16826964Salex#endif 1691541Srgrimes#ifndef LIBWRAP_DENY_SEVERITY 1701541Srgrimes# define LIBWRAP_DENY_SEVERITY LOG_WARNING 1711541Srgrimes#endif 1721541Srgrimes 1731541Srgrimes#define ISWRAP(sep) \ 17476166Smarkm ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 1752960Swollman && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \ 17676166Smarkm && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 17776166Smarkm || (sep)->se_socktype == SOCK_DGRAM)) 17876166Smarkm 17976166Smarkm#ifdef LOGIN_CAP 18076166Smarkm#include <login_cap.h> 18112769Sphk 1821541Srgrimes/* see init.c */ 18376166Smarkm#define RESOURCE_RC "daemon" 18477031Sru 1851541Srgrimes#endif 18666356Sbp 18766356Sbp#ifndef MAXCHILD 18866356Sbp#define MAXCHILD -1 /* maximum number of this service 18966356Sbp < 0 = no limit */ 19066356Sbp#endif 19112769Sphk 19212769Sphk#ifndef MAXCPM 19312769Sphk#define MAXCPM -1 /* rate limit invocations from a 1941541Srgrimes single remote address, 1951541Srgrimes < 0 = no limit */ 1961541Srgrimes#endif 1971541Srgrimes 1981541Srgrimes#ifndef TOOMANY 1991541Srgrimes#define TOOMANY 256 /* don't start more than TOOMANY */ 2001541Srgrimes#endif 2011541Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 2021541Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 2031541Srgrimes#define MAX_MAXCHLD 32767 /* max allowable max children */ 2041541Srgrimes 2051541Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 2061541Srgrimes 2071541Srgrimesvoid close_sep(struct servtab *); 2081541Srgrimesvoid flag_signal(int); 2091541Srgrimesvoid flag_config(int); 2101541Srgrimesvoid config(void); 2111541Srgrimesint cpmip(const struct servtab *, int); 2121541Srgrimesvoid endconfig(void); 2131541Srgrimesstruct servtab *enter(struct servtab *); 2141541Srgrimesvoid freeconfig(struct servtab *); 2151541Srgrimesstruct servtab *getconfigent(void); 2161541Srgrimesint matchservent(const char *, const char *, const char *); 2171541Srgrimeschar *nextline(FILE *); 2188876Srgrimesvoid addchild(struct servtab *, int); 21922521Sdysonvoid flag_reapchild(int); 220140728Sphkvoid reapchild(void); 2211541Srgrimesvoid enable(struct servtab *); 222140732Sphkvoid disable(struct servtab *); 2231541Srgrimesvoid flag_retry(int); 2241541Srgrimesvoid retry(void); 2251541Srgrimesint setconfig(void); 2261541Srgrimesvoid setup(struct servtab *); 2271541Srgrimes#ifdef IPSEC 2281541Srgrimesvoid ipsecsetup(struct servtab *); 2291541Srgrimes#endif 2301541Srgrimesvoid unregisterrpc(register struct servtab *sep); 2311541Srgrimes 2321541Srgrimesint allow_severity; 23350616Sbdeint deny_severity; 2341541Srgrimesint wrap_ex = 0; 2351541Srgrimesint wrap_bi = 0; 2361541Srgrimesint debug = 0; 2371541Srgrimesint log = 0; 2381541Srgrimesint maxsock; /* highest-numbered descriptor */ 23950616Sbdefd_set allsock; 2401541Srgrimesint options; 2411541Srgrimesint timingout; 2421541Srgrimesint toomany = TOOMANY; 2431541Srgrimesint maxchild = MAXCHILD; 2441541Srgrimesint maxcpm = MAXCPM; 2451541Srgrimesstruct servent *sp; 2461541Srgrimesstruct rpcent *rpc; 2471541Srgrimeschar *hostname = NULL; 2481541Srgrimesstruct sockaddr_in *bind_sa4; 2491541Srgrimesint no_v4bind = 1; 2501541Srgrimes#ifdef INET6 2518876Srgrimesstruct sockaddr_in6 *bind_sa6; 2521541Srgrimesint no_v6bind = 1; 2531541Srgrimes#endif 2541541Srgrimesint signalpipe[2]; 2551541Srgrimes#ifdef SANITY_CHECK 2561541Srgrimesint nsock; 2571541Srgrimes#endif 25824987Skatouid_t euid; 259138290Sphkgid_t egid; 26024987Skatomode_t mask; 2611541Srgrimes 2621541Srgrimesstruct servtab *servtab; 2631541Srgrimes 2641541Srgrimesextern struct biltin biltins[]; 2651541Srgrimes 2661541Srgrimes#define NUMINT (sizeof(intab) / sizeof(struct inent)) 2671541Srgrimesconst char *CONFIG = _PATH_INETDCONF; 2681541Srgrimesconst char *pid_file = _PATH_INETDPID; 26966356Sbp 2701541Srgrimesint 2711541Srgrimesgetvalue(const char *arg, int *value, const char *whine) 2728876Srgrimes{ 2731541Srgrimes int tmp; 2741541Srgrimes char *p; 2751541Srgrimes 2761541Srgrimes tmp = strtol(arg, &p, 0); 2771541Srgrimes if (tmp < 0 || *p) { 2781541Srgrimes syslog(LOG_ERR, whine, arg); 27966356Sbp return 1; /* failure */ 280140165Sphk } 28166356Sbp *value = tmp; 28266356Sbp return 0; /* success */ 28366356Sbp} 28466356Sbp 2851541Srgrimesint 2861541Srgrimesmain(int argc, char **argv) 2871541Srgrimes{ 2881541Srgrimes struct servtab *sep; 2891541Srgrimes struct passwd *pwd; 2901541Srgrimes struct group *grp; 2911541Srgrimes struct sigaction sa, saalrm, sachld, sahup, sapipe; 2921541Srgrimes int tmpint, ch, dofork; 2931541Srgrimes pid_t pid; 2941541Srgrimes char buf[50]; 2951541Srgrimes#ifdef LOGIN_CAP 2961541Srgrimes login_cap_t *lc = NULL; 29766356Sbp#endif 29866356Sbp struct request_info req; 299175294Sattilio int denied; 30066356Sbp char *service = NULL; 30166356Sbp union { 3021541Srgrimes struct sockaddr peer_un; 3031541Srgrimes struct sockaddr_in peer_un4; 3041541Srgrimes struct sockaddr_in6 peer_un6; 3051541Srgrimes struct sockaddr_storage peer_max; 3061541Srgrimes } p_un; 3071541Srgrimes#define peer p_un.peer_un 3081541Srgrimes#define peer4 p_un.peer_un4 3091541Srgrimes#define peer6 p_un.peer_un6 3101541Srgrimes#define peermax p_un.peer_max 3111541Srgrimes int i; 3121541Srgrimes struct addrinfo hints, *res; 3131541Srgrimes const char *servname; 3141541Srgrimes int error; 3151541Srgrimes 3161541Srgrimes openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON); 3171541Srgrimes 3181541Srgrimes while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1) 3191541Srgrimes switch(ch) { 3201541Srgrimes case 'd': 3211541Srgrimes debug = 1; 3221541Srgrimes options |= SO_DEBUG; 3231541Srgrimes break; 32429584Sphk case 'l': 32598183Ssemenu log = 1; 3261541Srgrimes break; 3271541Srgrimes case 'R': 3281541Srgrimes getvalue(optarg, &toomany, 3291541Srgrimes "-R %s: bad value for service invocation rate"); 3301541Srgrimes break; 3311541Srgrimes case 'c': 33222521Sdyson getvalue(optarg, &maxchild, 33322521Sdyson "-c %s: bad value for maximum children"); 33422521Sdyson break; 33522521Sdyson case 'C': 33622521Sdyson getvalue(optarg, &maxcpm, 33722521Sdyson "-C %s: bad value for maximum children/minute"); 338140728Sphk break; 33922521Sdyson case 'a': 34022521Sdyson hostname = optarg; 34166356Sbp break; 34222521Sdyson case 'p': 34366356Sbp pid_file = optarg; 34422521Sdyson break; 3451541Srgrimes case 'w': 34666356Sbp wrap_ex++; 34722521Sdyson break; 34822521Sdyson case 'W': 34966356Sbp wrap_bi++; 35066356Sbp break; 35166356Sbp case '?': 35266356Sbp default: 35366356Sbp syslog(LOG_ERR, 35466356Sbp "usage: inetd [-dlwW] [-a address] [-R rate]" 35566356Sbp " [-c maximum] [-C rate]" 35622521Sdyson " [-p pidfile] [conf-file]"); 35766356Sbp exit(EX_USAGE); 35822521Sdyson } 35922521Sdyson /* 36066356Sbp * Initialize Bind Addrs. 36166356Sbp * When hostname is NULL, wild card bind addrs are obtained from 36266356Sbp * getaddrinfo(). But getaddrinfo() requires at least one of 36366356Sbp * hostname or servname is non NULL. 36466356Sbp * So when hostname is NULL, set dummy value to servname. 36566356Sbp */ 36666356Sbp servname = (hostname == NULL) ? "discard" /* dummy */ : NULL; 36798183Ssemenu 368229431Skib bzero(&hints, sizeof(struct addrinfo)); 369185335Skib hints.ai_flags = AI_PASSIVE; 37066356Sbp hints.ai_family = AF_UNSPEC; 37122521Sdyson error = getaddrinfo(hostname, servname, &hints, &res); 37222521Sdyson if (error != 0) { 37322521Sdyson syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error)); 37422521Sdyson if (error == EAI_SYSTEM) 375140776Sphk syslog(LOG_ERR, "%s", strerror(errno)); 376140776Sphk exit(EX_USAGE); 377140776Sphk } 378140776Sphk do { 379140776Sphk if (res->ai_addr == NULL) { 380140776Sphk syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); 381140776Sphk exit(EX_USAGE); 382140776Sphk } 383140776Sphk switch (res->ai_addr->sa_family) { 384140776Sphk case AF_INET: 385140776Sphk if (no_v4bind == 0) 386140776Sphk continue; 387140776Sphk bind_sa4 = (struct sockaddr_in *)res->ai_addr; 388140776Sphk /* init port num in case servname is dummy */ 3891541Srgrimes bind_sa4->sin_port = 0; 39022521Sdyson no_v4bind = 0; 39122521Sdyson continue; 392105211Sphk#ifdef INET6 393140728Sphk case AF_INET6: 39422521Sdyson if (no_v6bind == 0) 39522521Sdyson continue; 39622521Sdyson bind_sa6 = (struct sockaddr_in6 *)res->ai_addr; 39722521Sdyson /* init port num in case servname is dummy */ 39822521Sdyson bind_sa6->sin6_port = 0; 39922597Smpp no_v6bind = 0; 40022597Smpp continue; 40122521Sdyson#endif 40222521Sdyson } 40322521Sdyson if (no_v4bind == 0 40422521Sdyson#ifdef INET6 40522521Sdyson && no_v6bind == 0 40622521Sdyson#endif 40722521Sdyson ) 40822521Sdyson break; 40922521Sdyson } while ((res = res->ai_next) != NULL); 41022521Sdyson if (no_v4bind != 0 41136840Speter#ifdef INET6 41236840Speter && no_v6bind != 0 41322521Sdyson#endif 41422521Sdyson ) { 41522521Sdyson syslog(LOG_ERR, "-a %s: unknown address family", hostname); 41622521Sdyson exit(EX_USAGE); 41722521Sdyson } 41822521Sdyson 41922521Sdyson euid = geteuid(); 42022521Sdyson egid = getegid(); 42122521Sdyson umask(mask = umask(0777)); 42222521Sdyson 42322521Sdyson argc -= optind; 42422521Sdyson argv += optind; 42566356Sbp 42622607Smpp if (argc > 0) 42722521Sdyson CONFIG = argv[0]; 42822521Sdyson if (debug == 0) { 42922521Sdyson FILE *fp; 4301541Srgrimes if (daemon(0, 0) < 0) { 4311541Srgrimes syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 43212769Sphk } 433140728Sphk /* From now on we don't want syslog messages going to stderr. */ 4341541Srgrimes closelog(); 4351541Srgrimes openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 43622521Sdyson /* 43743311Sdillon * In case somebody has started inetd manually, we need to 4381541Srgrimes * clear the logname, so that old servers run as root do not 43965467Sbp * get the user's logname.. 44065467Sbp */ 4411541Srgrimes if (setlogin("") < 0) { 4421541Srgrimes syslog(LOG_WARNING, "cannot clear logname: %m"); 4431541Srgrimes /* no big deal if it fails.. */ 44466356Sbp } 44566356Sbp pid = getpid(); 44666356Sbp fp = fopen(pid_file, "w"); 44722521Sdyson if (fp) { 448140728Sphk fprintf(fp, "%ld\n", (long)pid); 44922521Sdyson fclose(fp); 45022521Sdyson } else { 451184413Strasz syslog(LOG_WARNING, "%s: %m", pid_file); 4521541Srgrimes } 45322521Sdyson } 45422521Sdyson sa.sa_flags = 0; 45522521Sdyson sigemptyset(&sa.sa_mask); 45696755Strhodes sigaddset(&sa.sa_mask, SIGALRM); 45722521Sdyson sigaddset(&sa.sa_mask, SIGCHLD); 458184413Strasz sigaddset(&sa.sa_mask, SIGHUP); 45922521Sdyson sa.sa_handler = flag_retry; 46022521Sdyson sigaction(SIGALRM, &sa, &saalrm); 46122521Sdyson config(); 46222521Sdyson sa.sa_handler = flag_config; 46322521Sdyson sigaction(SIGHUP, &sa, &sahup); 46422521Sdyson sa.sa_handler = flag_reapchild; 46522521Sdyson sigaction(SIGCHLD, &sa, &sachld); 46643305Sdillon sa.sa_handler = SIG_IGN; 46743305Sdillon sigaction(SIGPIPE, &sa, &sapipe); 46822521Sdyson 46922521Sdyson { 47022607Smpp /* space for daemons to overwrite environment for ps */ 47122521Sdyson#define DUMMYSIZE 100 47222521Sdyson char dummy[DUMMYSIZE]; 473193092Strasz 474193092Strasz (void)memset(dummy, 'x', DUMMYSIZE - 1); 475193092Strasz dummy[DUMMYSIZE - 1] = '\0'; 476193092Strasz (void)setenv("inetd_dummy", dummy, 1); 477193092Strasz } 478193092Strasz 479193092Strasz if (pipe(signalpipe) != 0) { 480193092Strasz syslog(LOG_ERR, "pipe: %m"); 481193092Strasz exit(EX_OSERR); 482193092Strasz } 483193092Strasz FD_SET(signalpipe[0], &allsock); 484193092Strasz#ifdef SANITY_CHECK 485193092Strasz nsock++; 486193092Strasz#endif 487193092Strasz if (signalpipe[0] > maxsock) 488193092Strasz maxsock = signalpipe[0]; 489193092Strasz if (signalpipe[1] > maxsock) 490193092Strasz maxsock = signalpipe[1]; 491193092Strasz 492193092Strasz for (;;) { 493193092Strasz int n, ctrl; 494193092Strasz fd_set readable; 495193092Strasz 496193092Strasz#ifdef SANITY_CHECK 497193092Strasz if (nsock == 0) { 498193092Strasz syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 49922521Sdyson exit(EX_SOFTWARE); 500212043Srmacklem } 501212043Srmacklem#endif 502212043Srmacklem readable = allsock; 503212043Srmacklem if ((n = select(maxsock + 1, &readable, (fd_set *)0, 504212043Srmacklem (fd_set *)0, (struct timeval *)0)) <= 0) { 505212043Srmacklem if (n < 0 && errno != EINTR) { 506212043Srmacklem syslog(LOG_WARNING, "select: %m"); 507212043Srmacklem sleep(1); 508212043Srmacklem } 509212043Srmacklem continue; 510212043Srmacklem } 511212043Srmacklem /* handle any queued signal flags */ 512212043Srmacklem if (FD_ISSET(signalpipe[0], &readable)) { 513212043Srmacklem int nsig; 514212043Srmacklem if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) { 515212043Srmacklem syslog(LOG_ERR, "ioctl: %m"); 516212043Srmacklem exit(EX_OSERR); 517212043Srmacklem } 518212043Srmacklem while (--nsig >= 0) { 519212043Srmacklem char c; 520212043Srmacklem if (read(signalpipe[0], &c, 1) != 1) { 521212043Srmacklem syslog(LOG_ERR, "read: %m"); 522212043Srmacklem exit(EX_OSERR); 523212043Srmacklem } 524212043Srmacklem if (debug) 525212043Srmacklem warnx("handling signal flag %c", c); 52665467Sbp switch(c) { 52765467Sbp case 'A': /* sigalrm */ 52865467Sbp retry(); 52965467Sbp break; 53065467Sbp case 'C': /* sigchld */ 531140728Sphk reapchild(); 53265467Sbp break; 53365467Sbp case 'H': /* sighup */ 53465467Sbp config(); 53565467Sbp break; 53665467Sbp } 53765467Sbp } 53865467Sbp } 53965467Sbp for (sep = servtab; n && sep; sep = sep->se_next) 54065467Sbp if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 54165467Sbp n--; 54265467Sbp if (debug) 54365467Sbp warnx("someone wants %s", sep->se_service); 54465467Sbp if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 54565467Sbp i = 1; 54665467Sbp if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 54765467Sbp syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m"); 54865467Sbp ctrl = accept(sep->se_fd, (struct sockaddr *)0, 54965467Sbp (socklen_t *)0); 55065467Sbp if (debug) 55165467Sbp warnx("accept, ctrl %d", ctrl); 55265467Sbp if (ctrl < 0) { 55365467Sbp if (errno != EINTR) 55465467Sbp syslog(LOG_WARNING, 55565467Sbp "accept (for %s): %m", 55622521Sdyson sep->se_service); 55722521Sdyson if (sep->se_accept && 55822521Sdyson sep->se_socktype == SOCK_STREAM) 55922521Sdyson close(ctrl); 56022597Smpp continue; 561169671Skib } 56222521Sdyson i = 0; 56366356Sbp if (ioctl(sep->se_fd, FIONBIO, &i) < 0) 56466356Sbp syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m"); 565143642Sjeff if (ioctl(ctrl, FIONBIO, &i) < 0) 56666356Sbp syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m"); 56766356Sbp if (cpmip(sep, ctrl) < 0) { 56822521Sdyson close(ctrl); 56966356Sbp continue; 570143513Sjeff } 571143513Sjeff } else 572143642Sjeff ctrl = sep->se_fd; 573143513Sjeff if (log && !ISWRAP(sep)) { 574143642Sjeff char pname[INET6_ADDRSTRLEN] = "unknown"; 575143642Sjeff socklen_t sl; 576143642Sjeff sl = sizeof peermax; 577143642Sjeff if (getpeername(ctrl, (struct sockaddr *) 578143642Sjeff &peermax, &sl)) { 579143642Sjeff sl = sizeof peermax; 580143642Sjeff if (recvfrom(ctrl, buf, sizeof(buf), 581145424Sjeff MSG_PEEK, 582116469Stjr (struct sockaddr *)&peermax, 58366356Sbp &sl) >= 0) { 584143642Sjeff getnameinfo((struct sockaddr *)&peermax, 585143642Sjeff peer.sa_len, 586143642Sjeff pname, sizeof(pname), 587143642Sjeff NULL, 0, 588143642Sjeff NI_NUMERICHOST| 589143642Sjeff NI_WITHSCOPEID); 590143642Sjeff } 591143642Sjeff } else { 592143642Sjeff getnameinfo((struct sockaddr *)&peermax, 59366356Sbp peer.sa_len, 594143642Sjeff pname, sizeof(pname), 595175294Sattilio NULL, 0, 596150181Skan NI_NUMERICHOST| 597150181Skan NI_WITHSCOPEID); 598150181Skan } 599150181Skan syslog(LOG_INFO,"%s from %s", sep->se_service, pname); 600150181Skan } 601150181Skan (void) sigblock(SIGBLOCK); 602150181Skan pid = 0; 603150181Skan /* 604150181Skan * Fork for all external services, builtins which need to 605150181Skan * fork and anything we're wrapping (as wrapping might 606150181Skan * block or use hosts_options(5) twist). 607150181Skan */ 608150181Skan dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 609150181Skan if (dofork) { 610150181Skan if (sep->se_count++ == 0) 611150181Skan (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 612150181Skan else if (toomany > 0 && sep->se_count >= toomany) { 613150181Skan struct timeval now; 614150181Skan 615150181Skan (void)gettimeofday(&now, (struct timezone *)NULL); 616150181Skan if (now.tv_sec - sep->se_time.tv_sec > 617175294Sattilio CNT_INTVL) { 618150181Skan sep->se_time = now; 619150181Skan sep->se_count = 1; 620143642Sjeff } else { 621143642Sjeff syslog(LOG_ERR, 622143642Sjeff "%s/%s server failing (looping), service terminated", 623143642Sjeff sep->se_service, sep->se_proto); 624143642Sjeff if (sep->se_accept && 62522521Sdyson sep->se_socktype == SOCK_STREAM) 62622521Sdyson close(ctrl); 62722521Sdyson close_sep(sep); 62822521Sdyson sigsetmask(0L); 62922521Sdyson if (!timingout) { 63022521Sdyson timingout = 1; 63122521Sdyson alarm(RETRYTIME); 63222597Smpp } 633140728Sphk continue; 63422521Sdyson } 63566356Sbp } 63666356Sbp pid = fork(); 637172644Sdaichi } 638143642Sjeff if (pid < 0) { 63966570Sbp syslog(LOG_ERR, "fork: %m"); 640143642Sjeff if (sep->se_accept && 64166356Sbp sep->se_socktype == SOCK_STREAM) 642172644Sdaichi close(ctrl); 643172644Sdaichi sigsetmask(0L); 644172644Sdaichi sleep(1); 645172644Sdaichi continue; 646172644Sdaichi } 64766356Sbp if (pid) 648143642Sjeff addchild(sep, pid); 649172644Sdaichi sigsetmask(0L); 650172644Sdaichi if (pid == 0) { 651172644Sdaichi if (dofork) { 652172644Sdaichi if (debug) 653172644Sdaichi warnx("+ closing from %d", maxsock); 654175294Sattilio for (tmpint = maxsock; tmpint > 2; tmpint--) 655172644Sdaichi if (tmpint != ctrl) 656172644Sdaichi (void) close(tmpint); 657172644Sdaichi sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 658172644Sdaichi sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 659172644Sdaichi sigaction(SIGHUP, &sahup, (struct sigaction *)0); 660172644Sdaichi /* SIGPIPE reset before exec */ 661143642Sjeff } 662172644Sdaichi /* 663143642Sjeff * Call tcpmux to find the real service to exec. 664143642Sjeff */ 66522521Sdyson if (sep->se_bi && 66622521Sdyson sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) { 66766356Sbp sep = tcpmux(ctrl); 66866356Sbp if (sep == NULL) { 669182943Sed close(ctrl); 67066356Sbp _exit(0); 67198183Ssemenu } 67298183Ssemenu } 673218965Sbrucec if (ISWRAP(sep)) { 67498183Ssemenu inetd_setproctitle("wrapping", ctrl); 67598183Ssemenu service = sep->se_server_name ? 67666356Sbp sep->se_server_name : sep->se_service; 67766356Sbp request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL); 678140728Sphk fromhost(&req); 6791541Srgrimes deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 68030636Sroberto allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 68198175Ssemenu denied = !hosts_access(&req); 68292540Smckusick if (denied) { 683141447Sphk syslog(deny_severity, 68498175Ssemenu "refused connection from %.500s, service %s (%s%s)", 68592540Smckusick eval_client(&req), service, sep->se_proto, 68692540Smckusick (((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : ""); 68792540Smckusick if (sep->se_socktype != SOCK_STREAM) 68892540Smckusick recv(ctrl, buf, sizeof (buf), 0); 689140936Sphk if (dofork) { 69098175Ssemenu sleep(1); 69192540Smckusick _exit(0); 69292540Smckusick } 69392540Smckusick } 69492540Smckusick if (log) { 69598183Ssemenu syslog(allow_severity, 69692540Smckusick "connection from %.500s, service %s (%s%s)", 69792540Smckusick eval_client(&req), service, sep->se_proto, 698140728Sphk (((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : ""); 69992540Smckusick } 70092540Smckusick } 70130636Sroberto if (sep->se_bi) { 70230636Sroberto (*sep->se_bi->bi_fn)(ctrl, sep); 70366356Sbp } else { 704155899Sjeff if (debug) 705155899Sjeff warnx("%d execl %s", 706143744Sjeff getpid(), sep->se_server); 707143744Sjeff dup2(ctrl, 0); 708143744Sjeff close(ctrl); 709143744Sjeff dup2(0, 1); 710193172Skib dup2(0, 2); 711143744Sjeff if ((pwd = getpwnam(sep->se_user)) == NULL) { 712143744Sjeff syslog(LOG_ERR, 713155899Sjeff "%s/%s: %s: no such user", 714150181Skan sep->se_service, sep->se_proto, 715193172Skib sep->se_user); 716193172Skib if (sep->se_socktype != SOCK_STREAM) 717149722Sssouhlal recv(0, buf, sizeof (buf), 0); 718193172Skib _exit(EX_NOUSER); 719182943Sed } 720184205Sdes grp = NULL; 72166356Sbp if ( sep->se_group != NULL 7221541Srgrimes && (grp = getgrnam(sep->se_group)) == NULL 7231541Srgrimes ) { 7241541Srgrimes syslog(LOG_ERR, 72512769Sphk "%s/%s: %s: no such group", 726140728Sphk sep->se_service, sep->se_proto, 7271541Srgrimes sep->se_group); 728140732Sphk if (sep->se_socktype != SOCK_STREAM) 729155899Sjeff recv(0, buf, sizeof (buf), 0); 730227696Skib _exit(EX_NOUSER); 7311541Srgrimes } 7321541Srgrimes if (grp != NULL) 7331541Srgrimes pwd->pw_gid = grp->gr_gid; 734156585Sjeff#ifdef LOGIN_CAP 735156585Sjeff if ((lc = login_getclass(sep->se_class)) == NULL) { 736156585Sjeff /* error syslogged by getclass */ 737156585Sjeff syslog(LOG_ERR, 738156585Sjeff "%s/%s: %s: login class error", 739156585Sjeff sep->se_service, sep->se_proto, 740156585Sjeff sep->se_class); 741156585Sjeff if (sep->se_socktype != SOCK_STREAM) 742156585Sjeff recv(0, buf, sizeof (buf), 0); 743156585Sjeff _exit(EX_NOUSER); 744156585Sjeff } 745156585Sjeff#endif 746156585Sjeff if (setsid() < 0) { 747156585Sjeff syslog(LOG_ERR, 748156585Sjeff "%s: can't setsid(): %m", 749156585Sjeff sep->se_service); 750156585Sjeff /* _exit(EX_OSERR); not fatal yet */ 751156585Sjeff } 752156585Sjeff#ifdef LOGIN_CAP 753156585Sjeff if (setusercontext(lc, pwd, pwd->pw_uid, 754156585Sjeff LOGIN_SETALL) != 0) { 755156585Sjeff syslog(LOG_ERR, 756156585Sjeff "%s: can't setusercontext(..%s..): %m", 757156585Sjeff sep->se_service, sep->se_user); 758156585Sjeff _exit(EX_OSERR); 759166774Spjd } 760166774Spjd#else 761166774Spjd if (pwd->pw_uid) { 762166774Spjd if (setlogin(sep->se_user) < 0) { 763166774Spjd syslog(LOG_ERR, 764166774Spjd "%s: can't setlogin(%s): %m", 765166774Spjd sep->se_service, sep->se_user); 766166774Spjd /* _exit(EX_OSERR); not yet */ 767166774Spjd } 768193175Skib if (setgid(pwd->pw_gid) < 0) { 769193175Skib syslog(LOG_ERR, 770193175Skib "%s: can't set gid %d: %m", 771193175Skib sep->se_service, pwd->pw_gid); 772193175Skib _exit(EX_OSERR); 773193175Skib } 774194601Skib (void) initgroups(pwd->pw_name, 775193175Skib pwd->pw_gid); 776193175Skib if (setuid(pwd->pw_uid) < 0) { 777193175Skib syslog(LOG_ERR, 778193175Skib "%s: can't set uid %d: %m", 779193175Skib sep->se_service, pwd->pw_uid); 780193175Skib _exit(EX_OSERR); 781193175Skib } 782193175Skib } 783193175Skib#endif 784193175Skib sigaction(SIGPIPE, &sapipe, 785227697Skib (struct sigaction *)0); 786194601Skib execv(sep->se_server, sep->se_argv); 787193175Skib syslog(LOG_ERR, 788193175Skib "cannot execute %s: %m", sep->se_server); 789193175Skib if (sep->se_socktype != SOCK_STREAM) 790193175Skib recv(0, buf, sizeof (buf), 0); 791193175Skib } 792193175Skib if (dofork) 793193175Skib _exit(0); 794193175Skib } 795193175Skib if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 796193175Skib close(ctrl); 797193175Skib } 798193175Skib } 799227697Skib} 800193175Skib 801193175Skib/* 802193175Skib * Add a signal flag to the signal flag queue for later handling 803193175Skib */ 804193175Skib 805193175Skibvoid 806193175Skibflag_signal(int c) 807193175Skib{ 808193175Skib char ch = c; 809227697Skib 810229431Skib if (write(signalpipe[1], &ch, 1) != 1) { 811193175Skib syslog(LOG_ERR, "write: %m"); 812193175Skib _exit(EX_OSERR); 813193175Skib } 814193175Skib} 8151541Srgrimes 8161541Srgrimes/* 8171541Srgrimes * Record a new child pid for this service. If we've reached the 818138290Sphk * limit on children, then stop accepting incoming requests. 819138290Sphk */ 820138290Sphk 821193092Straszvoid 822208128Skibaddchild(struct servtab *sep, pid_t pid) 823138290Sphk{ 824138290Sphk if (sep->se_maxchild <= 0) 825156585Sjeff return; 826138290Sphk#ifdef SANITY_CHECK 827189961Spho if (sep->se_numchild >= sep->se_maxchild) { 828169671Skib syslog(LOG_ERR, "%s: %d >= %d", 829138290Sphk __FUNCTION__, sep->se_numchild, sep->se_maxchild); 830140776Sphk exit(EX_SOFTWARE); 831138290Sphk } 832138290Sphk#endif 833212043Srmacklem sep->se_pids[sep->se_numchild++] = pid; 834138290Sphk if (sep->se_numchild == sep->se_maxchild) 835138290Sphk disable(sep); 836138290Sphk} 837138290Sphk 838193175Skib/* 839166774Spjd * Some child process has exited. See if it's on somebody's list. 8401541Srgrimes */ 841 842void 843flag_reapchild(int signo __unused) 844{ 845 flag_signal('C'); 846} 847 848void 849reapchild(void) 850{ 851 int k, status; 852 pid_t pid; 853 struct servtab *sep; 854 855 for (;;) { 856 pid = wait3(&status, WNOHANG, (struct rusage *)0); 857 if (pid <= 0) 858 break; 859 if (debug) 860 warnx("%d reaped, status %#x", pid, status); 861 for (sep = servtab; sep; sep = sep->se_next) { 862 for (k = 0; k < sep->se_numchild; k++) 863 if (sep->se_pids[k] == pid) 864 break; 865 if (k == sep->se_numchild) 866 continue; 867 if (sep->se_numchild == sep->se_maxchild) 868 enable(sep); 869 sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 870 if (status) 871 syslog(LOG_WARNING, 872 "%s[%d]: exit status 0x%x", 873 sep->se_server, pid, status); 874 break; 875 } 876 } 877} 878 879void 880flag_config(int signo __unused) 881{ 882 flag_signal('H'); 883} 884 885void 886config(void) 887{ 888 struct servtab *sep, *new, **sepp; 889 long omask; 890 891 if (!setconfig()) { 892 syslog(LOG_ERR, "%s: %m", CONFIG); 893 return; 894 } 895 for (sep = servtab; sep; sep = sep->se_next) 896 sep->se_checked = 0; 897 while ((new = getconfigent())) { 898 if (getpwnam(new->se_user) == NULL) { 899 syslog(LOG_ERR, 900 "%s/%s: no such user '%s', service ignored", 901 new->se_service, new->se_proto, new->se_user); 902 continue; 903 } 904 if (new->se_group && getgrnam(new->se_group) == NULL) { 905 syslog(LOG_ERR, 906 "%s/%s: no such group '%s', service ignored", 907 new->se_service, new->se_proto, new->se_group); 908 continue; 909 } 910#ifdef LOGIN_CAP 911 if (login_getclass(new->se_class) == NULL) { 912 /* error syslogged by getclass */ 913 syslog(LOG_ERR, 914 "%s/%s: %s: login class error, service ignored", 915 new->se_service, new->se_proto, new->se_class); 916 continue; 917 } 918#endif 919 for (sep = servtab; sep; sep = sep->se_next) 920 if (strcmp(sep->se_service, new->se_service) == 0 && 921 strcmp(sep->se_proto, new->se_proto) == 0 && 922 sep->se_socktype == new->se_socktype && 923 sep->se_family == new->se_family) 924 break; 925 if (sep != 0) { 926 int i; 927 928#define SWAP(a, b) { __typeof__(a) c = a; a = b; b = c; } 929 omask = sigblock(SIGBLOCK); 930 if (sep->se_nomapped != new->se_nomapped) { 931 sep->se_nomapped = new->se_nomapped; 932 sep->se_reset = 1; 933 } 934 /* copy over outstanding child pids */ 935 if (sep->se_maxchild > 0 && new->se_maxchild > 0) { 936 new->se_numchild = sep->se_numchild; 937 if (new->se_numchild > new->se_maxchild) 938 new->se_numchild = new->se_maxchild; 939 memcpy(new->se_pids, sep->se_pids, 940 new->se_numchild * sizeof(*new->se_pids)); 941 } 942 SWAP(sep->se_pids, new->se_pids); 943 sep->se_maxchild = new->se_maxchild; 944 sep->se_numchild = new->se_numchild; 945 sep->se_maxcpm = new->se_maxcpm; 946 sep->se_bi = new->se_bi; 947 /* might need to turn on or off service now */ 948 if (sep->se_fd >= 0) { 949 if (sep->se_maxchild > 0 950 && sep->se_numchild == sep->se_maxchild) { 951 if (FD_ISSET(sep->se_fd, &allsock)) 952 disable(sep); 953 } else { 954 if (!FD_ISSET(sep->se_fd, &allsock)) 955 enable(sep); 956 } 957 } 958 sep->se_accept = new->se_accept; 959 SWAP(sep->se_user, new->se_user); 960 SWAP(sep->se_group, new->se_group); 961#ifdef LOGIN_CAP 962 SWAP(sep->se_class, new->se_class); 963#endif 964 SWAP(sep->se_server, new->se_server); 965 SWAP(sep->se_server_name, new->se_server_name); 966 for (i = 0; i < MAXARGV; i++) 967 SWAP(sep->se_argv[i], new->se_argv[i]); 968#ifdef IPSEC 969 SWAP(sep->se_policy, new->se_policy); 970 ipsecsetup(sep); 971#endif 972 sigsetmask(omask); 973 freeconfig(new); 974 if (debug) 975 print_service("REDO", sep); 976 } else { 977 sep = enter(new); 978 if (debug) 979 print_service("ADD ", sep); 980 } 981 sep->se_checked = 1; 982 if (ISMUX(sep)) { 983 sep->se_fd = -1; 984 continue; 985 } 986 switch (sep->se_family) { 987 case AF_INET: 988 if (no_v4bind != 0) { 989 sep->se_fd = -1; 990 continue; 991 } 992 break; 993#ifdef INET6 994 case AF_INET6: 995 if (no_v6bind != 0) { 996 sep->se_fd = -1; 997 continue; 998 } 999 break; 1000#endif 1001 } 1002 if (!sep->se_rpc) { 1003 if (sep->se_family != AF_UNIX) { 1004 sp = getservbyname(sep->se_service, sep->se_proto); 1005 if (sp == 0) { 1006 syslog(LOG_ERR, "%s/%s: unknown service", 1007 sep->se_service, sep->se_proto); 1008 sep->se_checked = 0; 1009 continue; 1010 } 1011 } 1012 switch (sep->se_family) { 1013 case AF_INET: 1014 if (sp->s_port != sep->se_ctrladdr4.sin_port) { 1015 sep->se_ctrladdr4.sin_port = 1016 sp->s_port; 1017 sep->se_reset = 1; 1018 } 1019 break; 1020#ifdef INET6 1021 case AF_INET6: 1022 if (sp->s_port != 1023 sep->se_ctrladdr6.sin6_port) { 1024 sep->se_ctrladdr6.sin6_port = 1025 sp->s_port; 1026 sep->se_reset = 1; 1027 } 1028 break; 1029#endif 1030 } 1031 if (sep->se_reset != 0 && sep->se_fd >= 0) 1032 close_sep(sep); 1033 } else { 1034 rpc = getrpcbyname(sep->se_service); 1035 if (rpc == 0) { 1036 syslog(LOG_ERR, "%s/%s unknown RPC service", 1037 sep->se_service, sep->se_proto); 1038 if (sep->se_fd != -1) 1039 (void) close(sep->se_fd); 1040 sep->se_fd = -1; 1041 continue; 1042 } 1043 if (rpc->r_number != sep->se_rpc_prog) { 1044 if (sep->se_rpc_prog) 1045 unregisterrpc(sep); 1046 sep->se_rpc_prog = rpc->r_number; 1047 if (sep->se_fd != -1) 1048 (void) close(sep->se_fd); 1049 sep->se_fd = -1; 1050 } 1051 } 1052 if (sep->se_fd == -1) 1053 setup(sep); 1054 } 1055 endconfig(); 1056 /* 1057 * Purge anything not looked at above. 1058 */ 1059 omask = sigblock(SIGBLOCK); 1060 sepp = &servtab; 1061 while ((sep = *sepp)) { 1062 if (sep->se_checked) { 1063 sepp = &sep->se_next; 1064 continue; 1065 } 1066 *sepp = sep->se_next; 1067 if (sep->se_fd >= 0) 1068 close_sep(sep); 1069 if (debug) 1070 print_service("FREE", sep); 1071 if (sep->se_rpc && sep->se_rpc_prog > 0) 1072 unregisterrpc(sep); 1073 freeconfig(sep); 1074 free(sep); 1075 } 1076 (void) sigsetmask(omask); 1077} 1078 1079void 1080unregisterrpc(struct servtab *sep) 1081{ 1082 u_int i; 1083 struct servtab *sepp; 1084 long omask; 1085 1086 omask = sigblock(SIGBLOCK); 1087 for (sepp = servtab; sepp; sepp = sepp->se_next) { 1088 if (sepp == sep) 1089 continue; 1090 if (sep->se_checked == 0 || 1091 !sepp->se_rpc || 1092 sep->se_rpc_prog != sepp->se_rpc_prog) 1093 continue; 1094 return; 1095 } 1096 if (debug) 1097 print_service("UNREG", sep); 1098 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 1099 pmap_unset(sep->se_rpc_prog, i); 1100 if (sep->se_fd != -1) 1101 (void) close(sep->se_fd); 1102 sep->se_fd = -1; 1103 (void) sigsetmask(omask); 1104} 1105 1106void 1107flag_retry(int signo __unused) 1108{ 1109 flag_signal('A'); 1110} 1111 1112void 1113retry(void) 1114{ 1115 struct servtab *sep; 1116 1117 timingout = 0; 1118 for (sep = servtab; sep; sep = sep->se_next) 1119 if (sep->se_fd == -1 && !ISMUX(sep)) 1120 setup(sep); 1121} 1122 1123void 1124setup(struct servtab *sep) 1125{ 1126 int on = 1; 1127 1128 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { 1129 if (debug) 1130 warn("socket failed on %s/%s", 1131 sep->se_service, sep->se_proto); 1132 syslog(LOG_ERR, "%s/%s: socket: %m", 1133 sep->se_service, sep->se_proto); 1134 return; 1135 } 1136#define turnon(fd, opt) \ 1137setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 1138 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 1139 turnon(sep->se_fd, SO_DEBUG) < 0) 1140 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 1141 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 1142 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 1143#ifdef SO_PRIVSTATE 1144 if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 1145 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 1146#endif 1147 /* tftpd opens a new connection then needs more infos */ 1148 if ((sep->se_family == AF_INET6) && 1149 (strcmp(sep->se_proto, "udp") == 0) && 1150 (sep->se_accept == 0) && 1151 (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO, 1152 (char *)&on, sizeof (on)) < 0)) 1153 syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m"); 1154#ifdef IPV6_BINDV6ONLY 1155 if (sep->se_family == AF_INET6) { 1156 int flag = sep->se_nomapped ? 1 : 0; 1157 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY, 1158 (char *)&flag, sizeof (flag)) < 0) 1159 syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m"); 1160 } 1161#endif /* IPV6_BINDV6ONLY */ 1162#undef turnon 1163 if (sep->se_type == TTCP_TYPE) 1164 if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 1165 (char *)&on, sizeof (on)) < 0) 1166 syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 1167#ifdef IPV6_FAITH 1168 if (sep->se_type == FAITH_TYPE) { 1169 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on, 1170 sizeof(on)) < 0) { 1171 syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m"); 1172 } 1173 } 1174#endif 1175#ifdef IPSEC 1176 ipsecsetup(sep); 1177#endif 1178 if (sep->se_family == AF_UNIX) { 1179 (void) unlink(sep->se_ctrladdr_un.sun_path); 1180 umask(0777); /* Make socket with conservative permissions */ 1181 } 1182 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 1183 sep->se_ctrladdr_size) < 0) { 1184 if (debug) 1185 warn("bind failed on %s/%s", 1186 sep->se_service, sep->se_proto); 1187 syslog(LOG_ERR, "%s/%s: bind: %m", 1188 sep->se_service, sep->se_proto); 1189 (void) close(sep->se_fd); 1190 sep->se_fd = -1; 1191 if (!timingout) { 1192 timingout = 1; 1193 alarm(RETRYTIME); 1194 } 1195 if (sep->se_family == AF_UNIX) 1196 umask(mask); 1197 return; 1198 } 1199 if (sep->se_family == AF_UNIX) { 1200 /* Ick - fch{own,mod} don't work on Unix domain sockets */ 1201 if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0) 1202 syslog(LOG_ERR, "chown socket: %m"); 1203 if (chmod(sep->se_service, sep->se_sockmode) < 0) 1204 syslog(LOG_ERR, "chmod socket: %m"); 1205 umask(mask); 1206 } 1207 if (sep->se_rpc) { 1208 u_int i; 1209 socklen_t len = sep->se_ctrladdr_size; 1210 1211 if (sep->se_family != AF_INET) { 1212 syslog(LOG_ERR, 1213 "%s/%s: unsupported address family for rpc", 1214 sep->se_service, sep->se_proto); 1215 (void) close(sep->se_fd); 1216 sep->se_fd = -1; 1217 return; 1218 } 1219 if (getsockname(sep->se_fd, 1220 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 1221 syslog(LOG_ERR, "%s/%s: getsockname: %m", 1222 sep->se_service, sep->se_proto); 1223 (void) close(sep->se_fd); 1224 sep->se_fd = -1; 1225 return; 1226 } 1227 if (debug) 1228 print_service("REG ", sep); 1229 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 1230 pmap_unset(sep->se_rpc_prog, i); 1231 pmap_set(sep->se_rpc_prog, i, 1232 (sep->se_socktype == SOCK_DGRAM) 1233 ? IPPROTO_UDP : IPPROTO_TCP, 1234 ntohs(sep->se_ctrladdr4.sin_port)); 1235 } 1236 } 1237 if (sep->se_socktype == SOCK_STREAM) 1238 listen(sep->se_fd, 64); 1239 enable(sep); 1240 if (debug) { 1241 warnx("registered %s on %d", 1242 sep->se_server, sep->se_fd); 1243 } 1244} 1245 1246#ifdef IPSEC 1247void 1248ipsecsetup(sep) 1249 struct servtab *sep; 1250{ 1251 char *buf; 1252 char *policy_in = NULL; 1253 char *policy_out = NULL; 1254 int level; 1255 int opt; 1256 1257 switch (sep->se_family) { 1258 case AF_INET: 1259 level = IPPROTO_IP; 1260 opt = IP_IPSEC_POLICY; 1261 break; 1262#ifdef INET6 1263 case AF_INET6: 1264 level = IPPROTO_IPV6; 1265 opt = IPV6_IPSEC_POLICY; 1266 break; 1267#endif 1268 default: 1269 return; 1270 } 1271 1272 if (!sep->se_policy || sep->se_policy[0] == '\0') { 1273 static char def_in[] = "in entrust", def_out[] = "out entrust"; 1274 policy_in = def_in; 1275 policy_out = def_out; 1276 } else { 1277 if (!strncmp("in", sep->se_policy, 2)) 1278 policy_in = sep->se_policy; 1279 else if (!strncmp("out", sep->se_policy, 3)) 1280 policy_out = sep->se_policy; 1281 else { 1282 syslog(LOG_ERR, "invalid security policy \"%s\"", 1283 sep->se_policy); 1284 return; 1285 } 1286 } 1287 1288 if (policy_in != NULL) { 1289 buf = ipsec_set_policy(policy_in, strlen(policy_in)); 1290 if (buf != NULL) { 1291 if (setsockopt(sep->se_fd, level, opt, 1292 buf, ipsec_get_policylen(buf)) < 0 && 1293 debug != 0) 1294 warnx("%s/%s: ipsec initialization failed; %s", 1295 sep->se_service, sep->se_proto, 1296 policy_in); 1297 free(buf); 1298 } else 1299 syslog(LOG_ERR, "invalid security policy \"%s\"", 1300 policy_in); 1301 } 1302 if (policy_out != NULL) { 1303 buf = ipsec_set_policy(policy_out, strlen(policy_out)); 1304 if (buf != NULL) { 1305 if (setsockopt(sep->se_fd, level, opt, 1306 buf, ipsec_get_policylen(buf)) < 0 && 1307 debug != 0) 1308 warnx("%s/%s: ipsec initialization failed; %s", 1309 sep->se_service, sep->se_proto, 1310 policy_out); 1311 free(buf); 1312 } else 1313 syslog(LOG_ERR, "invalid security policy \"%s\"", 1314 policy_out); 1315 } 1316} 1317#endif 1318 1319/* 1320 * Finish with a service and its socket. 1321 */ 1322void 1323close_sep(struct servtab *sep) 1324{ 1325 if (sep->se_fd >= 0) { 1326 if (FD_ISSET(sep->se_fd, &allsock)) 1327 disable(sep); 1328 (void) close(sep->se_fd); 1329 sep->se_fd = -1; 1330 } 1331 sep->se_count = 0; 1332 sep->se_numchild = 0; /* forget about any existing children */ 1333} 1334 1335int 1336matchservent(const char *name1, const char *name2, const char *proto) 1337{ 1338 char **alias, *p; 1339 struct servent *se; 1340 1341 if (strcmp(proto, "unix") == 0) { 1342 if ((p = strrchr(name1, '/')) != NULL) 1343 name1 = p + 1; 1344 if ((p = strrchr(name2, '/')) != NULL) 1345 name2 = p + 1; 1346 } 1347 if (strcmp(name1, name2) == 0) 1348 return(1); 1349 if ((se = getservbyname(name1, proto)) != NULL) { 1350 if (strcmp(name2, se->s_name) == 0) 1351 return(1); 1352 for (alias = se->s_aliases; *alias; alias++) 1353 if (strcmp(name2, *alias) == 0) 1354 return(1); 1355 } 1356 return(0); 1357} 1358 1359struct servtab * 1360enter(struct servtab *cp) 1361{ 1362 struct servtab *sep; 1363 long omask; 1364 1365 sep = (struct servtab *)malloc(sizeof (*sep)); 1366 if (sep == (struct servtab *)0) { 1367 syslog(LOG_ERR, "malloc: %m"); 1368 exit(EX_OSERR); 1369 } 1370 *sep = *cp; 1371 sep->se_fd = -1; 1372 omask = sigblock(SIGBLOCK); 1373 sep->se_next = servtab; 1374 servtab = sep; 1375 sigsetmask(omask); 1376 return (sep); 1377} 1378 1379void 1380enable(struct servtab *sep) 1381{ 1382 if (debug) 1383 warnx( 1384 "enabling %s, fd %d", sep->se_service, sep->se_fd); 1385#ifdef SANITY_CHECK 1386 if (sep->se_fd < 0) { 1387 syslog(LOG_ERR, 1388 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1389 exit(EX_SOFTWARE); 1390 } 1391 if (ISMUX(sep)) { 1392 syslog(LOG_ERR, 1393 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1394 exit(EX_SOFTWARE); 1395 } 1396 if (FD_ISSET(sep->se_fd, &allsock)) { 1397 syslog(LOG_ERR, 1398 "%s: %s: not off", __FUNCTION__, sep->se_service); 1399 exit(EX_SOFTWARE); 1400 } 1401 nsock++; 1402#endif 1403 FD_SET(sep->se_fd, &allsock); 1404 if (sep->se_fd > maxsock) 1405 maxsock = sep->se_fd; 1406} 1407 1408void 1409disable(struct servtab *sep) 1410{ 1411 if (debug) 1412 warnx( 1413 "disabling %s, fd %d", sep->se_service, sep->se_fd); 1414#ifdef SANITY_CHECK 1415 if (sep->se_fd < 0) { 1416 syslog(LOG_ERR, 1417 "%s: %s: bad fd", __FUNCTION__, sep->se_service); 1418 exit(EX_SOFTWARE); 1419 } 1420 if (ISMUX(sep)) { 1421 syslog(LOG_ERR, 1422 "%s: %s: is mux", __FUNCTION__, sep->se_service); 1423 exit(EX_SOFTWARE); 1424 } 1425 if (!FD_ISSET(sep->se_fd, &allsock)) { 1426 syslog(LOG_ERR, 1427 "%s: %s: not on", __FUNCTION__, sep->se_service); 1428 exit(EX_SOFTWARE); 1429 } 1430 if (nsock == 0) { 1431 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 1432 exit(EX_SOFTWARE); 1433 } 1434 nsock--; 1435#endif 1436 FD_CLR(sep->se_fd, &allsock); 1437 if (sep->se_fd == maxsock) 1438 maxsock--; 1439} 1440 1441FILE *fconfig = NULL; 1442struct servtab serv; 1443char line[LINE_MAX]; 1444 1445int 1446setconfig(void) 1447{ 1448 1449 if (fconfig != NULL) { 1450 fseek(fconfig, 0L, SEEK_SET); 1451 return (1); 1452 } 1453 fconfig = fopen(CONFIG, "r"); 1454 return (fconfig != NULL); 1455} 1456 1457void 1458endconfig(void) 1459{ 1460 if (fconfig) { 1461 (void) fclose(fconfig); 1462 fconfig = NULL; 1463 } 1464} 1465 1466struct servtab * 1467getconfigent(void) 1468{ 1469 struct servtab *sep = &serv; 1470 int argc; 1471 char *cp, *arg, *s; 1472 char *versp; 1473 static char TCPMUX_TOKEN[] = "tcpmux/"; 1474#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 1475#ifdef IPSEC 1476 char *policy = NULL; 1477#endif 1478 int v4bind = 0; 1479#ifdef INET6 1480 int v6bind = 0; 1481#endif 1482 1483more: 1484 while ((cp = nextline(fconfig)) != NULL) { 1485#ifdef IPSEC 1486 /* lines starting with #@ is not a comment, but the policy */ 1487 if (cp[0] == '#' && cp[1] == '@') { 1488 char *p; 1489 for (p = cp + 2; p && *p && isspace(*p); p++) 1490 ; 1491 if (*p == '\0') { 1492 if (policy) 1493 free(policy); 1494 policy = NULL; 1495 } else if (ipsec_get_policylen(p) >= 0) { 1496 if (policy) 1497 free(policy); 1498 policy = newstr(p); 1499 } else { 1500 syslog(LOG_ERR, 1501 "%s: invalid ipsec policy \"%s\"", 1502 CONFIG, p); 1503 exit(EX_CONFIG); 1504 } 1505 } 1506#endif 1507 if (*cp == '#' || *cp == '\0') 1508 continue; 1509 break; 1510 } 1511 if (cp == NULL) 1512 return ((struct servtab *)0); 1513 /* 1514 * clear the static buffer, since some fields (se_ctrladdr, 1515 * for example) don't get initialized here. 1516 */ 1517 memset(sep, 0, sizeof *sep); 1518 arg = skip(&cp); 1519 if (cp == NULL) { 1520 /* got an empty line containing just blanks/tabs. */ 1521 goto more; 1522 } 1523 if (arg[0] == ':') { /* :user:group:perm: */ 1524 char *user, *group, *perm; 1525 struct passwd *pw; 1526 struct group *gr; 1527 user = arg+1; 1528 if ((group = strchr(user, ':')) == NULL) { 1529 syslog(LOG_ERR, "no group after user '%s'", user); 1530 goto more; 1531 } 1532 *group++ = '\0'; 1533 if ((perm = strchr(group, ':')) == NULL) { 1534 syslog(LOG_ERR, "no mode after group '%s'", group); 1535 goto more; 1536 } 1537 *perm++ = '\0'; 1538 if ((pw = getpwnam(user)) == NULL) { 1539 syslog(LOG_ERR, "no such user '%s'", user); 1540 goto more; 1541 } 1542 sep->se_sockuid = pw->pw_uid; 1543 if ((gr = getgrnam(group)) == NULL) { 1544 syslog(LOG_ERR, "no such user '%s'", group); 1545 goto more; 1546 } 1547 sep->se_sockgid = gr->gr_gid; 1548 sep->se_sockmode = strtol(perm, &arg, 8); 1549 if (*arg != ':') { 1550 syslog(LOG_ERR, "bad mode '%s'", perm); 1551 goto more; 1552 } 1553 *arg++ = '\0'; 1554 } else { 1555 sep->se_sockuid = euid; 1556 sep->se_sockgid = egid; 1557 sep->se_sockmode = 0200; 1558 } 1559 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 1560 char *c = arg + MUX_LEN; 1561 if (*c == '+') { 1562 sep->se_type = MUXPLUS_TYPE; 1563 c++; 1564 } else 1565 sep->se_type = MUX_TYPE; 1566 sep->se_service = newstr(c); 1567 } else { 1568 sep->se_service = newstr(arg); 1569 sep->se_type = NORM_TYPE; 1570 } 1571 arg = sskip(&cp); 1572 if (strcmp(arg, "stream") == 0) 1573 sep->se_socktype = SOCK_STREAM; 1574 else if (strcmp(arg, "dgram") == 0) 1575 sep->se_socktype = SOCK_DGRAM; 1576 else if (strcmp(arg, "rdm") == 0) 1577 sep->se_socktype = SOCK_RDM; 1578 else if (strcmp(arg, "seqpacket") == 0) 1579 sep->se_socktype = SOCK_SEQPACKET; 1580 else if (strcmp(arg, "raw") == 0) 1581 sep->se_socktype = SOCK_RAW; 1582 else 1583 sep->se_socktype = -1; 1584 1585 arg = sskip(&cp); 1586 if (strncmp(arg, "tcp", 3) == 0) { 1587 sep->se_proto = newstr(strsep(&arg, "/")); 1588 if (arg != NULL) { 1589 if (strcmp(arg, "ttcp") == 0) 1590 sep->se_type = TTCP_TYPE; 1591 else if (strcmp(arg, "faith") == 0) 1592 sep->se_type = FAITH_TYPE; 1593 } 1594 } else { 1595 if (sep->se_type == NORM_TYPE && 1596 strncmp(arg, "faith/", 6) == 0) { 1597 arg += 6; 1598 sep->se_type = FAITH_TYPE; 1599 } 1600 sep->se_proto = newstr(arg); 1601 } 1602 if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 1603 if (no_v4bind != 0) { 1604 syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1605 sep->se_service); 1606 freeconfig(sep); 1607 goto more; 1608 } 1609 memmove(sep->se_proto, sep->se_proto + 4, 1610 strlen(sep->se_proto) + 1 - 4); 1611 sep->se_rpc = 1; 1612 sep->se_rpc_prog = sep->se_rpc_lowvers = 1613 sep->se_rpc_lowvers = 0; 1614 memcpy(&sep->se_ctrladdr4, bind_sa4, 1615 sizeof(sep->se_ctrladdr4)); 1616 if ((versp = rindex(sep->se_service, '/'))) { 1617 *versp++ = '\0'; 1618 switch (sscanf(versp, "%d-%d", 1619 &sep->se_rpc_lowvers, 1620 &sep->se_rpc_highvers)) { 1621 case 2: 1622 break; 1623 case 1: 1624 sep->se_rpc_highvers = 1625 sep->se_rpc_lowvers; 1626 break; 1627 default: 1628 syslog(LOG_ERR, 1629 "bad RPC version specifier; %s", 1630 sep->se_service); 1631 freeconfig(sep); 1632 goto more; 1633 } 1634 } 1635 else { 1636 sep->se_rpc_lowvers = 1637 sep->se_rpc_highvers = 1; 1638 } 1639 } 1640 sep->se_nomapped = 0; 1641 while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) { 1642#ifdef INET6 1643 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') { 1644 if (no_v6bind != 0) { 1645 syslog(LOG_NOTICE, "IPv6 bind is ignored for %s", 1646 sep->se_service); 1647 freeconfig(sep); 1648 goto more; 1649 } 1650 sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1651 v6bind = 1; 1652 continue; 1653 } 1654#endif 1655 if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') { 1656 sep->se_proto[strlen(sep->se_proto) - 1] = '\0'; 1657 v4bind = 1; 1658 continue; 1659 } 1660 /* illegal version num */ 1661 syslog(LOG_ERR, "bad IP version for %s", sep->se_proto); 1662 freeconfig(sep); 1663 goto more; 1664 } 1665 if (strcmp(sep->se_proto, "unix") == 0) { 1666 sep->se_family = AF_UNIX; 1667 } else 1668#ifdef INET6 1669 if (v6bind != 0) { 1670 sep->se_family = AF_INET6; 1671 if (v4bind == 0 || no_v4bind != 0) 1672 sep->se_nomapped = 1; 1673 } else 1674#endif 1675 { /* default to v4 bind if not v6 bind */ 1676 if (no_v4bind != 0) { 1677 syslog(LOG_NOTICE, "IPv4 bind is ignored for %s", 1678 sep->se_service); 1679 freeconfig(sep); 1680 goto more; 1681 } 1682 sep->se_family = AF_INET; 1683 } 1684 /* init ctladdr */ 1685 switch(sep->se_family) { 1686 case AF_INET: 1687 memcpy(&sep->se_ctrladdr4, bind_sa4, 1688 sizeof(sep->se_ctrladdr4)); 1689 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4); 1690 break; 1691#ifdef INET6 1692 case AF_INET6: 1693 memcpy(&sep->se_ctrladdr6, bind_sa6, 1694 sizeof(sep->se_ctrladdr6)); 1695 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6); 1696 break; 1697#endif 1698 case AF_UNIX: 1699 if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) { 1700 syslog(LOG_ERR, 1701 "domain socket pathname too long for service %s", 1702 sep->se_service); 1703 goto more; 1704 } 1705 memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr)); 1706 sep->se_ctrladdr_un.sun_family = sep->se_family; 1707 sep->se_ctrladdr_un.sun_len = strlen(sep->se_service); 1708 strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service); 1709 sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un); 1710 } 1711 arg = sskip(&cp); 1712 if (!strncmp(arg, "wait", 4)) 1713 sep->se_accept = 0; 1714 else if (!strncmp(arg, "nowait", 6)) 1715 sep->se_accept = 1; 1716 else { 1717 syslog(LOG_ERR, 1718 "%s: bad wait/nowait for service %s", 1719 CONFIG, sep->se_service); 1720 goto more; 1721 } 1722 sep->se_maxchild = -1; 1723 sep->se_maxcpm = -1; 1724 if ((s = strchr(arg, '/')) != NULL) { 1725 char *eptr; 1726 u_long val; 1727 1728 val = strtoul(s + 1, &eptr, 10); 1729 if (eptr == s + 1 || val > MAX_MAXCHLD) { 1730 syslog(LOG_ERR, 1731 "%s: bad max-child for service %s", 1732 CONFIG, sep->se_service); 1733 goto more; 1734 } 1735 if (debug) 1736 if (!sep->se_accept && val != 1) 1737 warnx("maxchild=%lu for wait service %s" 1738 " not recommended", val, sep->se_service); 1739 sep->se_maxchild = val; 1740 if (*eptr == '/') 1741 sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 1742 /* 1743 * explicitly do not check for \0 for future expansion / 1744 * backwards compatibility 1745 */ 1746 } 1747 if (ISMUX(sep)) { 1748 /* 1749 * Silently enforce "nowait" mode for TCPMUX services 1750 * since they don't have an assigned port to listen on. 1751 */ 1752 sep->se_accept = 1; 1753 if (strcmp(sep->se_proto, "tcp")) { 1754 syslog(LOG_ERR, 1755 "%s: bad protocol for tcpmux service %s", 1756 CONFIG, sep->se_service); 1757 goto more; 1758 } 1759 if (sep->se_socktype != SOCK_STREAM) { 1760 syslog(LOG_ERR, 1761 "%s: bad socket type for tcpmux service %s", 1762 CONFIG, sep->se_service); 1763 goto more; 1764 } 1765 } 1766 sep->se_user = newstr(sskip(&cp)); 1767#ifdef LOGIN_CAP 1768 if ((s = strrchr(sep->se_user, '/')) != NULL) { 1769 *s = '\0'; 1770 sep->se_class = newstr(s + 1); 1771 } else 1772 sep->se_class = newstr(RESOURCE_RC); 1773#endif 1774 if ((s = strrchr(sep->se_user, ':')) != NULL) { 1775 *s = '\0'; 1776 sep->se_group = newstr(s + 1); 1777 } else 1778 sep->se_group = NULL; 1779 sep->se_server = newstr(sskip(&cp)); 1780 if ((sep->se_server_name = rindex(sep->se_server, '/'))) 1781 sep->se_server_name++; 1782 if (strcmp(sep->se_server, "internal") == 0) { 1783 struct biltin *bi; 1784 1785 for (bi = biltins; bi->bi_service; bi++) 1786 if (bi->bi_socktype == sep->se_socktype && 1787 matchservent(bi->bi_service, sep->se_service, 1788 sep->se_proto)) 1789 break; 1790 if (bi->bi_service == 0) { 1791 syslog(LOG_ERR, "internal service %s unknown", 1792 sep->se_service); 1793 goto more; 1794 } 1795 sep->se_accept = 1; /* force accept mode for built-ins */ 1796 sep->se_bi = bi; 1797 } else 1798 sep->se_bi = NULL; 1799 if (sep->se_maxcpm < 0) 1800 sep->se_maxcpm = maxcpm; 1801 if (sep->se_maxchild < 0) { /* apply default max-children */ 1802 if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 1803 sep->se_maxchild = sep->se_bi->bi_maxchild; 1804 else if (sep->se_accept) 1805 sep->se_maxchild = maxchild > 0 ? maxchild : 0; 1806 else 1807 sep->se_maxchild = 1; 1808 } 1809 if (sep->se_maxchild > 0) { 1810 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 1811 if (sep->se_pids == NULL) { 1812 syslog(LOG_ERR, "malloc: %m"); 1813 exit(EX_OSERR); 1814 } 1815 } 1816 argc = 0; 1817 for (arg = skip(&cp); cp; arg = skip(&cp)) 1818 if (argc < MAXARGV) { 1819 sep->se_argv[argc++] = newstr(arg); 1820 } else { 1821 syslog(LOG_ERR, 1822 "%s: too many arguments for service %s", 1823 CONFIG, sep->se_service); 1824 goto more; 1825 } 1826 while (argc <= MAXARGV) 1827 sep->se_argv[argc++] = NULL; 1828#ifdef IPSEC 1829 sep->se_policy = policy ? newstr(policy) : NULL; 1830#endif 1831 return (sep); 1832} 1833 1834void 1835freeconfig(struct servtab *cp) 1836{ 1837 int i; 1838 1839 if (cp->se_service) 1840 free(cp->se_service); 1841 if (cp->se_proto) 1842 free(cp->se_proto); 1843 if (cp->se_user) 1844 free(cp->se_user); 1845 if (cp->se_group) 1846 free(cp->se_group); 1847#ifdef LOGIN_CAP 1848 if (cp->se_class) 1849 free(cp->se_class); 1850#endif 1851 if (cp->se_server) 1852 free(cp->se_server); 1853 if (cp->se_pids) 1854 free(cp->se_pids); 1855 for (i = 0; i < MAXARGV; i++) 1856 if (cp->se_argv[i]) 1857 free(cp->se_argv[i]); 1858#ifdef IPSEC 1859 if (cp->se_policy) 1860 free(cp->se_policy); 1861#endif 1862} 1863 1864 1865/* 1866 * Safe skip - if skip returns null, log a syntax error in the 1867 * configuration file and exit. 1868 */ 1869char * 1870sskip(char **cpp) 1871{ 1872 char *cp; 1873 1874 cp = skip(cpp); 1875 if (cp == NULL) { 1876 syslog(LOG_ERR, "%s: syntax error", CONFIG); 1877 exit(EX_DATAERR); 1878 } 1879 return (cp); 1880} 1881 1882char * 1883skip(char **cpp) 1884{ 1885 char *cp = *cpp; 1886 char *start; 1887 char quote = '\0'; 1888 1889again: 1890 while (*cp == ' ' || *cp == '\t') 1891 cp++; 1892 if (*cp == '\0') { 1893 int c; 1894 1895 c = getc(fconfig); 1896 (void) ungetc(c, fconfig); 1897 if (c == ' ' || c == '\t') 1898 if ((cp = nextline(fconfig))) 1899 goto again; 1900 *cpp = (char *)0; 1901 return ((char *)0); 1902 } 1903 if (*cp == '"' || *cp == '\'') 1904 quote = *cp++; 1905 start = cp; 1906 if (quote) 1907 while (*cp && *cp != quote) 1908 cp++; 1909 else 1910 while (*cp && *cp != ' ' && *cp != '\t') 1911 cp++; 1912 if (*cp != '\0') 1913 *cp++ = '\0'; 1914 *cpp = cp; 1915 return (start); 1916} 1917 1918char * 1919nextline(FILE *fd) 1920{ 1921 char *cp; 1922 1923 if (fgets(line, sizeof (line), fd) == NULL) 1924 return ((char *)0); 1925 cp = strchr(line, '\n'); 1926 if (cp) 1927 *cp = '\0'; 1928 return (line); 1929} 1930 1931char * 1932newstr(const char *cp) 1933{ 1934 char *cr; 1935 1936 if ((cr = strdup(cp != NULL ? cp : ""))) 1937 return (cr); 1938 syslog(LOG_ERR, "strdup: %m"); 1939 exit(EX_OSERR); 1940} 1941 1942void 1943inetd_setproctitle(const char *a, int s) 1944{ 1945 socklen_t size; 1946 struct sockaddr_storage ss; 1947 char buf[80], pbuf[INET6_ADDRSTRLEN]; 1948 1949 size = sizeof(ss); 1950 if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) { 1951 getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf), 1952 NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID); 1953 (void) sprintf(buf, "%s [%s]", a, pbuf); 1954 } else 1955 (void) sprintf(buf, "%s", a); 1956 setproctitle("%s", buf); 1957} 1958 1959int 1960check_loop(const struct sockaddr *sa, const struct servtab *sep) 1961{ 1962 struct servtab *se2; 1963 char pname[INET6_ADDRSTRLEN]; 1964 1965 for (se2 = servtab; se2; se2 = se2->se_next) { 1966 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 1967 continue; 1968 1969 switch (se2->se_family) { 1970 case AF_INET: 1971 if (((const struct sockaddr_in *)sa)->sin_port == 1972 se2->se_ctrladdr4.sin_port) 1973 goto isloop; 1974 continue; 1975#ifdef INET6 1976 case AF_INET6: 1977 if (((const struct sockaddr_in *)sa)->sin_port == 1978 se2->se_ctrladdr4.sin_port) 1979 goto isloop; 1980 continue; 1981#endif 1982 default: 1983 continue; 1984 } 1985 isloop: 1986 getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0, 1987 NI_NUMERICHOST|NI_WITHSCOPEID); 1988 syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", 1989 sep->se_service, sep->se_proto, 1990 se2->se_service, se2->se_proto, 1991 pname); 1992 return 1; 1993 } 1994 return 0; 1995} 1996 1997/* 1998 * print_service: 1999 * Dump relevant information to stderr 2000 */ 2001void 2002print_service(const char *action, const struct servtab *sep) 2003{ 2004 fprintf(stderr, 2005 "%s: %s proto=%s accept=%d max=%d user=%s group=%s" 2006#ifdef LOGIN_CAP 2007 "class=%s" 2008#endif 2009 " builtin=%p server=%s" 2010#ifdef IPSEC 2011 " policy=\"%s\"" 2012#endif 2013 "\n", 2014 action, sep->se_service, sep->se_proto, 2015 sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 2016#ifdef LOGIN_CAP 2017 sep->se_class, 2018#endif 2019 (void *) sep->se_bi, sep->se_server 2020#ifdef IPSEC 2021 , (sep->se_policy ? sep->se_policy : "") 2022#endif 2023 ); 2024} 2025 2026#define CPMHSIZE 256 2027#define CPMHMASK (CPMHSIZE-1) 2028#define CHTGRAN 10 2029#define CHTSIZE 6 2030 2031typedef struct CTime { 2032 unsigned long ct_Ticks; 2033 int ct_Count; 2034} CTime; 2035 2036typedef struct CHash { 2037 union { 2038 struct in_addr c4_Addr; 2039 struct in6_addr c6_Addr; 2040 } cu_Addr; 2041#define ch_Addr4 cu_Addr.c4_Addr 2042#define ch_Addr6 cu_Addr.c6_Addr 2043 int ch_Family; 2044 time_t ch_LTime; 2045 char *ch_Service; 2046 CTime ch_Times[CHTSIZE]; 2047} CHash; 2048 2049CHash CHashAry[CPMHSIZE]; 2050 2051int 2052cpmip(const struct servtab *sep, int ctrl) 2053{ 2054 struct sockaddr_storage rss; 2055 socklen_t rssLen = sizeof(rss); 2056 int r = 0; 2057 2058 /* 2059 * If getpeername() fails, just let it through (if logging is 2060 * enabled the condition is caught elsewhere) 2061 */ 2062 2063 if (sep->se_maxcpm > 0 && 2064 getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) { 2065 time_t t = time(NULL); 2066 int hv = 0xABC3D20F; 2067 int i; 2068 int cnt = 0; 2069 CHash *chBest = NULL; 2070 unsigned int ticks = t / CHTGRAN; 2071 struct sockaddr_in *sin4; 2072#ifdef INET6 2073 struct sockaddr_in6 *sin6; 2074#endif 2075 2076 sin4 = (struct sockaddr_in *)&rss; 2077#ifdef INET6 2078 sin6 = (struct sockaddr_in6 *)&rss; 2079#endif 2080 { 2081 char *p; 2082 int addrlen; 2083 2084 switch (rss.ss_family) { 2085 case AF_INET: 2086 p = (char *)&sin4->sin_addr; 2087 addrlen = sizeof(struct in_addr); 2088 break; 2089#ifdef INET6 2090 case AF_INET6: 2091 p = (char *)&sin6->sin6_addr; 2092 addrlen = sizeof(struct in6_addr); 2093 break; 2094#endif 2095 default: 2096 /* should not happen */ 2097 return -1; 2098 } 2099 2100 for (i = 0; i < addrlen; ++i, ++p) { 2101 hv = (hv << 5) ^ (hv >> 23) ^ *p; 2102 } 2103 hv = (hv ^ (hv >> 16)); 2104 } 2105 for (i = 0; i < 5; ++i) { 2106 CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 2107 2108 if (rss.ss_family == AF_INET && 2109 ch->ch_Family == AF_INET && 2110 sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr && 2111 ch->ch_Service && strcmp(sep->se_service, 2112 ch->ch_Service) == 0) { 2113 chBest = ch; 2114 break; 2115 } 2116#ifdef INET6 2117 if (rss.ss_family == AF_INET6 && 2118 ch->ch_Family == AF_INET6 && 2119 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 2120 &ch->ch_Addr6) != 0 && 2121 ch->ch_Service && strcmp(sep->se_service, 2122 ch->ch_Service) == 0) { 2123 chBest = ch; 2124 break; 2125 } 2126#endif 2127 if (chBest == NULL || ch->ch_LTime == 0 || 2128 ch->ch_LTime < chBest->ch_LTime) { 2129 chBest = ch; 2130 } 2131 } 2132 if ((rss.ss_family == AF_INET && 2133 (chBest->ch_Family != AF_INET || 2134 sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) || 2135 chBest->ch_Service == NULL || 2136 strcmp(sep->se_service, chBest->ch_Service) != 0) { 2137 chBest->ch_Family = sin4->sin_family; 2138 chBest->ch_Addr4 = sin4->sin_addr; 2139 if (chBest->ch_Service) 2140 free(chBest->ch_Service); 2141 chBest->ch_Service = strdup(sep->se_service); 2142 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 2143 } 2144#ifdef INET6 2145 if ((rss.ss_family == AF_INET6 && 2146 (chBest->ch_Family != AF_INET6 || 2147 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 2148 &chBest->ch_Addr6) == 0)) || 2149 chBest->ch_Service == NULL || 2150 strcmp(sep->se_service, chBest->ch_Service) != 0) { 2151 chBest->ch_Family = sin6->sin6_family; 2152 chBest->ch_Addr6 = sin6->sin6_addr; 2153 if (chBest->ch_Service) 2154 free(chBest->ch_Service); 2155 chBest->ch_Service = strdup(sep->se_service); 2156 bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 2157 } 2158#endif 2159 chBest->ch_LTime = t; 2160 { 2161 CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 2162 if (ct->ct_Ticks != ticks) { 2163 ct->ct_Ticks = ticks; 2164 ct->ct_Count = 0; 2165 } 2166 ++ct->ct_Count; 2167 } 2168 for (i = 0; i < CHTSIZE; ++i) { 2169 CTime *ct = &chBest->ch_Times[i]; 2170 if (ct->ct_Ticks <= ticks && 2171 ct->ct_Ticks >= ticks - CHTSIZE) { 2172 cnt += ct->ct_Count; 2173 } 2174 } 2175 if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 2176 char pname[INET6_ADDRSTRLEN]; 2177 2178 getnameinfo((struct sockaddr *)&rss, 2179 ((struct sockaddr *)&rss)->sa_len, 2180 pname, sizeof(pname), NULL, 0, 2181 NI_NUMERICHOST|NI_WITHSCOPEID); 2182 r = -1; 2183 syslog(LOG_ERR, 2184 "%s from %s exceeded counts/min (limit %d/min)", 2185 sep->se_service, pname, 2186 sep->se_maxcpm); 2187 } 2188 } 2189 return(r); 2190} 2191