inetd.c revision 48981
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1991, 1993, 1994 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 131553Srgrimes * 3. All advertising materials mentioning features or use of this software 141553Srgrimes * must display the following acknowledgement: 151553Srgrimes * This product includes software developed by the University of 161553Srgrimes * California, Berkeley and its contributors. 171553Srgrimes * 4. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311553Srgrimes * SUCH DAMAGE. 321553Srgrimes */ 331553Srgrimes 341553Srgrimes#ifndef lint 3529602Scharnierstatic const char copyright[] = 361553Srgrimes"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\ 371553Srgrimes The Regents of the University of California. All rights reserved.\n"; 381553Srgrimes#endif /* not lint */ 391553Srgrimes 401553Srgrimes#ifndef lint 4129602Scharnier#if 0 4229602Scharnierstatic char sccsid[] = "@(#)from: inetd.c 8.4 (Berkeley) 4/13/94"; 4329602Scharnier#endif 4429602Scharnierstatic const char rcsid[] = 4548981Ssheldonh "$Id: inetd.c,v 1.63 1999/07/21 16:09:45 sheldonh Exp $"; 461553Srgrimes#endif /* not lint */ 471553Srgrimes 481553Srgrimes/* 491553Srgrimes * Inetd - Internet super-server 501553Srgrimes * 511553Srgrimes * This program invokes all internet services as needed. Connection-oriented 521553Srgrimes * services are invoked each time a connection is made, by creating a process. 531553Srgrimes * This process is passed the connection as file descriptor 0 and is expected 541553Srgrimes * to do a getpeername to find out the source host and port. 551553Srgrimes * 561553Srgrimes * Datagram oriented services are invoked when a datagram 571553Srgrimes * arrives; a process is created and passed a pending message 581553Srgrimes * on file descriptor 0. Datagram servers may either connect 591553Srgrimes * to their peer, freeing up the original socket for inetd 601553Srgrimes * to receive further messages on, or ``take over the socket'', 611553Srgrimes * processing all arriving datagrams and, eventually, timing 621553Srgrimes * out. The first type of server is said to be ``multi-threaded''; 638857Srgrimes * the second type of server ``single-threaded''. 641553Srgrimes * 651553Srgrimes * Inetd uses a configuration file which is read at startup 661553Srgrimes * and, possibly, at some later time in response to a hangup signal. 671553Srgrimes * The configuration file is ``free format'' with fields given in the 681553Srgrimes * order shown below. Continuation lines for an entry must being with 691553Srgrimes * a space or tab. All fields must be present in each entry. 701553Srgrimes * 711553Srgrimes * service name must be in /etc/services or must 721553Srgrimes * name a tcpmux service 731553Srgrimes * socket type stream/dgram/raw/rdm/seqpacket 741553Srgrimes * protocol must be in /etc/protocols 751553Srgrimes * wait/nowait single-threaded/multi-threaded 761553Srgrimes * user user to run daemon as 771553Srgrimes * server program full path name 781553Srgrimes * server program arguments maximum of MAXARGS (20) 791553Srgrimes * 801553Srgrimes * TCP services without official port numbers are handled with the 811553Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 821553Srgrimes * requests. When a connection is made from a foreign host, the service 831553Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list 841553Srgrimes * and returns the proper entry for the service. Tcpmux returns a 851553Srgrimes * negative reply if the service doesn't exist, otherwise the invoked 861553Srgrimes * server is expected to return the positive reply if the service type in 871553Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the 881553Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the 891553Srgrimes * process; this is for compatibility with older server code, and also 901553Srgrimes * allows you to invoke programs that use stdin/stdout without putting any 911553Srgrimes * special server code in them. Services that use tcpmux are "nowait" 921553Srgrimes * because they do not have a well-known port and hence cannot listen 931553Srgrimes * for new requests. 941553Srgrimes * 952657Scsgr * For RPC services 962657Scsgr * service name/version must be in /etc/rpc 972657Scsgr * socket type stream/dgram/raw/rdm/seqpacket 982657Scsgr * protocol must be in /etc/protocols 992657Scsgr * wait/nowait single-threaded/multi-threaded 1002657Scsgr * user user to run daemon as 1012657Scsgr * server program full path name 1022657Scsgr * server program arguments maximum of MAXARGS 1032657Scsgr * 1041553Srgrimes * Comment lines are indicated by a `#' in column 1. 1051553Srgrimes */ 1061553Srgrimes#include <sys/param.h> 1071553Srgrimes#include <sys/ioctl.h> 1081553Srgrimes#include <sys/wait.h> 1091553Srgrimes#include <sys/time.h> 1101553Srgrimes#include <sys/resource.h> 1111553Srgrimes 1121553Srgrimes#include <netinet/in.h> 11336042Sguido#include <netinet/tcp.h> 1141553Srgrimes#include <arpa/inet.h> 1152657Scsgr#include <rpc/rpc.h> 11619617Sjulian#include <rpc/pmap_clnt.h> 1171553Srgrimes 1181553Srgrimes#include <errno.h> 11929602Scharnier#include <err.h> 1201553Srgrimes#include <fcntl.h> 12130807Sache#include <grp.h> 1221553Srgrimes#include <netdb.h> 1231553Srgrimes#include <pwd.h> 1241553Srgrimes#include <signal.h> 1251553Srgrimes#include <stdio.h> 1261553Srgrimes#include <stdlib.h> 1271553Srgrimes#include <string.h> 1281553Srgrimes#include <syslog.h> 12948279Ssheldonh#include <tcpd.h> 1301553Srgrimes#include <unistd.h> 13113142Speter#include <libutil.h> 13219617Sjulian#include <sysexits.h> 1331553Srgrimes 13448981Ssheldonh#include "inetd.h" 13548981Ssheldonh#include "pathnames.h" 13648981Ssheldonh 13745089Smarkm#ifndef LIBWRAP_ALLOW_FACILITY 13845089Smarkm# define LIBWRAP_ALLOW_FACILITY LOG_AUTH 13945089Smarkm#endif 14045089Smarkm#ifndef LIBWRAP_ALLOW_SEVERITY 14145089Smarkm# define LIBWRAP_ALLOW_SEVERITY LOG_INFO 14245089Smarkm#endif 14345089Smarkm#ifndef LIBWRAP_DENY_FACILITY 14445089Smarkm# define LIBWRAP_DENY_FACILITY LOG_AUTH 14545089Smarkm#endif 14645089Smarkm#ifndef LIBWRAP_DENY_SEVERITY 14745089Smarkm# define LIBWRAP_DENY_SEVERITY LOG_WARNING 14845089Smarkm#endif 14945089Smarkm 15048382Ssheldonh#define ISWRAP(sep) \ 15148697Ssheldonh ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \ 15248382Ssheldonh && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \ 15348382Ssheldonh || (sep)->se_socktype == SOCK_DGRAM)) 15448382Ssheldonh 15521640Speter#ifdef LOGIN_CAP 15621640Speter#include <login_cap.h> 15730792Sache 15830792Sache/* see init.c */ 15930792Sache#define RESOURCE_RC "daemon" 16030792Sache 16121640Speter#endif 16221640Speter 16333794Spst#ifndef MAXCHILD 16433794Spst#define MAXCHILD -1 /* maximum number of this service 16533794Spst < 0 = no limit */ 16633794Spst#endif 16733794Spst 16833794Spst#ifndef MAXCPM 16933794Spst#define MAXCPM -1 /* rate limit invocations from a 17033794Spst single remote address, 17133794Spst < 0 = no limit */ 17233794Spst#endif 17333794Spst 1742659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 1751553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 1761553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 17719618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 1781553Srgrimes 1791553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 1801553Srgrimes 18148279Ssheldonhint allow_severity; 18248279Ssheldonhint deny_severity; 18348697Ssheldonhint wrap_ex = 0; 18448279Ssheldonhint wrap_bi = 0; 1851553Srgrimesint debug = 0; 1862659Scsgrint log = 0; 1871553Srgrimesint nsock, maxsock; 1881553Srgrimesfd_set allsock; 1891553Srgrimesint options; 1901553Srgrimesint timingout; 1911553Srgrimesint toomany = TOOMANY; 19248069Ssheldonhint maxchild = MAXCHILD; 19348069Ssheldonhint maxcpm = MAXCPM; 1941553Srgrimesstruct servent *sp; 1952657Scsgrstruct rpcent *rpc; 19617482Sjulianstruct in_addr bind_address; 19742122Sdesint signalpipe[2]; 1981553Srgrimes 19948981Ssheldonhstruct servtab *servtab; 2001553Srgrimes 20148981Ssheldonhextern struct biltin biltins[]; 2021553Srgrimes 2031553Srgrimes#define NUMINT (sizeof(intab) / sizeof(struct inent)) 2041553Srgrimeschar *CONFIG = _PATH_INETDCONF; 20517482Sjulianchar *pid_file = _PATH_INETDPID; 20613142Speter 20713142Speter#ifdef OLD_SETPROCTITLE 2081553Srgrimeschar **Argv; 2091553Srgrimeschar *LastArg; 21013142Speter#endif 2111553Srgrimes 2121553Srgrimesint 21333794Spstgetvalue(arg, value, whine) 21433794Spst char *arg, *whine; 21533794Spst int *value; 21633794Spst{ 21733794Spst int tmp; 21833794Spst char *p; 21933794Spst 22033794Spst tmp = strtol(arg, &p, 0); 22133794Spst if (tmp < 1 || *p) { 22233794Spst syslog(LOG_ERR, whine, arg); 22333794Spst return 1; /* failure */ 22433794Spst } 22533794Spst *value = tmp; 22633794Spst return 0; /* success */ 22733794Spst} 22833794Spst 22933794Spstint 2301553Srgrimesmain(argc, argv, envp) 2311553Srgrimes int argc; 2321553Srgrimes char *argv[], *envp[]; 2331553Srgrimes{ 2341553Srgrimes struct servtab *sep; 2351553Srgrimes struct passwd *pwd; 23630807Sache struct group *grp; 23748962Ssheldonh struct sigaction sa, saalrm, sachld, sahup, sapipe; 2381553Srgrimes int tmpint, ch, dofork; 2391553Srgrimes pid_t pid; 2401553Srgrimes char buf[50]; 24121640Speter#ifdef LOGIN_CAP 24221640Speter login_cap_t *lc = NULL; 24321640Speter#endif 24445089Smarkm struct request_info req; 24545089Smarkm int denied; 24645089Smarkm char *service = NULL; 24748382Ssheldonh char *pnm; 24847972Ssheldonh struct sockaddr_in peer; 24947972Ssheldonh int i; 2501553Srgrimes 25113142Speter 25213142Speter#ifdef OLD_SETPROCTITLE 2531553Srgrimes Argv = argv; 2541553Srgrimes if (envp == 0 || *envp == 0) 2551553Srgrimes envp = argv; 2561553Srgrimes while (*envp) 2571553Srgrimes envp++; 2581553Srgrimes LastArg = envp[-1] + strlen(envp[-1]); 25913142Speter#endif 2601553Srgrimes 2611553Srgrimes openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 2621553Srgrimes 26317482Sjulian bind_address.s_addr = htonl(INADDR_ANY); 26448697Ssheldonh while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1) 2651553Srgrimes switch(ch) { 2661553Srgrimes case 'd': 2671553Srgrimes debug = 1; 2681553Srgrimes options |= SO_DEBUG; 2691553Srgrimes break; 2702659Scsgr case 'l': 2712659Scsgr log = 1; 2722659Scsgr break; 27333794Spst case 'R': 27433794Spst getvalue(optarg, &toomany, 27533794Spst "-R %s: bad value for service invocation rate"); 2761553Srgrimes break; 27733794Spst case 'c': 27833794Spst getvalue(optarg, &maxchild, 27933794Spst "-c %s: bad value for maximum children"); 28033794Spst break; 28133794Spst case 'C': 28233794Spst getvalue(optarg, &maxcpm, 28333794Spst "-C %s: bad value for maximum children/minute"); 28433794Spst break; 28517482Sjulian case 'a': 28617482Sjulian if (!inet_aton(optarg, &bind_address)) { 28717482Sjulian syslog(LOG_ERR, 28817482Sjulian "-a %s: invalid IP address", optarg); 28919617Sjulian exit(EX_USAGE); 29017482Sjulian } 29117482Sjulian break; 29217482Sjulian case 'p': 29317482Sjulian pid_file = optarg; 29417482Sjulian break; 29548279Ssheldonh case 'w': 29648697Ssheldonh wrap_ex++; 29748279Ssheldonh break; 29848697Ssheldonh case 'W': 29948697Ssheldonh wrap_bi++; 30048697Ssheldonh break; 3011553Srgrimes case '?': 3021553Srgrimes default: 3031553Srgrimes syslog(LOG_ERR, 30448697Ssheldonh "usage: inetd [-dlwW] [-a address] [-R rate]" 30533794Spst " [-c maximum] [-C rate]" 30617482Sjulian " [-p pidfile] [conf-file]"); 30719617Sjulian exit(EX_USAGE); 3081553Srgrimes } 3091553Srgrimes argc -= optind; 3101553Srgrimes argv += optind; 3111553Srgrimes 3121553Srgrimes if (argc > 0) 3131553Srgrimes CONFIG = argv[0]; 3141553Srgrimes if (debug == 0) { 31511447Swollman FILE *fp; 31612024Speter if (daemon(0, 0) < 0) { 31712024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 31812024Speter } 31912024Speter /* 32012024Speter * In case somebody has started inetd manually, we need to 32112024Speter * clear the logname, so that old servers run as root do not 32212024Speter * get the user's logname.. 32312024Speter */ 32412024Speter if (setlogin("") < 0) { 32512024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 32612024Speter /* no big deal if it fails.. */ 32712024Speter } 32811447Swollman pid = getpid(); 32917482Sjulian fp = fopen(pid_file, "w"); 33011447Swollman if (fp) { 33111447Swollman fprintf(fp, "%ld\n", (long)pid); 33211447Swollman fclose(fp); 33311447Swollman } else { 33417482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 33511447Swollman } 3361553Srgrimes } 33735948Sbde sa.sa_flags = 0; 33835948Sbde sigemptyset(&sa.sa_mask); 33935948Sbde sigaddset(&sa.sa_mask, SIGALRM); 34035948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 34135948Sbde sigaddset(&sa.sa_mask, SIGHUP); 34242122Sdes sa.sa_handler = flag_retry; 34348962Ssheldonh sigaction(SIGALRM, &sa, &saalrm); 34442122Sdes config(); 34542122Sdes sa.sa_handler = flag_config; 34648962Ssheldonh sigaction(SIGHUP, &sa, &sahup); 34742122Sdes sa.sa_handler = flag_reapchild; 34848962Ssheldonh sigaction(SIGCHLD, &sa, &sachld); 34935848Sguido sa.sa_handler = SIG_IGN; 35035948Sbde sigaction(SIGPIPE, &sa, &sapipe); 3511553Srgrimes 3521553Srgrimes { 3531553Srgrimes /* space for daemons to overwrite environment for ps */ 3541553Srgrimes#define DUMMYSIZE 100 3551553Srgrimes char dummy[DUMMYSIZE]; 3561553Srgrimes 35719298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 3581553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 3591553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 3601553Srgrimes } 3611553Srgrimes 36242250Sdes if (pipe(signalpipe) != 0) { 36342250Sdes syslog(LOG_ERR, "pipe: %%m"); 36442250Sdes exit(EX_OSERR); 36542122Sdes } 36642122Sdes FD_SET(signalpipe[0], &allsock); 36747015Sdes nsock++; 36847015Sdes if (signalpipe[0] > maxsock) 36947015Sdes maxsock = signalpipe[0]; 37041685Sdillon 3711553Srgrimes for (;;) { 3721553Srgrimes int n, ctrl; 3731553Srgrimes fd_set readable; 3741553Srgrimes 3751553Srgrimes if (nsock == 0) { 37647015Sdes syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 37747015Sdes exit(EX_SOFTWARE); 3781553Srgrimes } 3791553Srgrimes readable = allsock; 38042122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 38142122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 38242122Sdes if (n < 0 && errno != EINTR) { 3831553Srgrimes syslog(LOG_WARNING, "select: %m"); 38428907Simp sleep(1); 38528907Simp } 3861553Srgrimes continue; 3871553Srgrimes } 38842122Sdes /* handle any queued signal flags */ 38942250Sdes if (FD_ISSET(signalpipe[0], &readable)) { 39042122Sdes int n; 39142250Sdes if (ioctl(signalpipe[0], FIONREAD, &n) != 0) { 39242122Sdes syslog(LOG_ERR, "ioctl: %m"); 39342122Sdes exit(EX_OSERR); 39442122Sdes } 39542250Sdes while (--n >= 0) { 39642250Sdes char c; 39742250Sdes if (read(signalpipe[0], &c, 1) != 1) { 39842250Sdes syslog(LOG_ERR, "read: %m"); 39942250Sdes exit(EX_OSERR); 40042250Sdes } 40142250Sdes if (debug) 40242250Sdes warnx("Handling signal flag %c", c); 40342250Sdes switch(c) { 40442250Sdes case 'A': /* sigalrm */ 40542250Sdes retry(); 40642250Sdes break; 40742250Sdes case 'C': /* sigchld */ 40842250Sdes reapchild(); 40942250Sdes break; 41042250Sdes case 'H': /* sighup */ 41142250Sdes config(); 41242250Sdes break; 41342250Sdes } 41442250Sdes } 41542122Sdes } 4161553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 4171553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 4181553Srgrimes n--; 4191553Srgrimes if (debug) 42029602Scharnier warnx("someone wants %s", sep->se_service); 42119618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 4221553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 4231553Srgrimes (int *)0); 4241553Srgrimes if (debug) 42529602Scharnier warnx("accept, ctrl %d", ctrl); 4261553Srgrimes if (ctrl < 0) { 4271553Srgrimes if (errno != EINTR) 4281553Srgrimes syslog(LOG_WARNING, 4291553Srgrimes "accept (for %s): %m", 43037844Sphk sep->se_service); 43137816Sphk if (sep->se_accept && 43237816Sphk sep->se_socktype == SOCK_STREAM) 43337816Sphk close(ctrl); 4341553Srgrimes continue; 4351553Srgrimes } 43630847Sdima if (cpmip(sep, ctrl) < 0) { 43730847Sdima close(ctrl); 43830847Sdima continue; 43930847Sdima } 4401553Srgrimes } else 4411553Srgrimes ctrl = sep->se_fd; 44248382Ssheldonh if (log && !ISWRAP(sep)) { 44348382Ssheldonh pnm = "unknown"; 44448382Ssheldonh i = sizeof peer; 44548382Ssheldonh if (getpeername(ctrl, (struct sockaddr *) 44648382Ssheldonh &peer, &i)) { 44748382Ssheldonh i = sizeof peer; 44848382Ssheldonh if (recvfrom(ctrl, buf, sizeof(buf), 44948382Ssheldonh MSG_PEEK, 45048382Ssheldonh (struct sockaddr *)&peer, &i) >= 0) 45148382Ssheldonh pnm = inet_ntoa(peer.sin_addr); 45248382Ssheldonh } 45348382Ssheldonh else 45448382Ssheldonh pnm = inet_ntoa(peer.sin_addr); 45548382Ssheldonh syslog(LOG_INFO,"%s from %s", sep->se_service, pnm); 45648382Ssheldonh } 45742122Sdes (void) sigblock(SIGBLOCK); 4581553Srgrimes pid = 0; 45947972Ssheldonh /* 46048958Ssheldonh * Fork for all external services, builtins which need to 46148958Ssheldonh * fork and anything we're wrapping (as wrapping might 46248958Ssheldonh * block or use hosts_options(5) twist). 46347972Ssheldonh */ 46448382Ssheldonh dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep); 4651553Srgrimes if (dofork) { 4661553Srgrimes if (sep->se_count++ == 0) 46737856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 4681553Srgrimes else if (sep->se_count >= toomany) { 4691553Srgrimes struct timeval now; 4701553Srgrimes 47137856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 4721553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 4731553Srgrimes CNT_INTVL) { 4741553Srgrimes sep->se_time = now; 4751553Srgrimes sep->se_count = 1; 4761553Srgrimes } else { 4771553Srgrimes syslog(LOG_ERR, 4781553Srgrimes "%s/%s server failing (looping), service terminated", 4791553Srgrimes sep->se_service, sep->se_proto); 4801553Srgrimes close_sep(sep); 48142122Sdes sigsetmask(0L); 4821553Srgrimes if (!timingout) { 4831553Srgrimes timingout = 1; 4841553Srgrimes alarm(RETRYTIME); 4851553Srgrimes } 4861553Srgrimes continue; 4871553Srgrimes } 4881553Srgrimes } 4891553Srgrimes pid = fork(); 4901553Srgrimes } 4911553Srgrimes if (pid < 0) { 4921553Srgrimes syslog(LOG_ERR, "fork: %m"); 49319618Sjulian if (sep->se_accept && 4941553Srgrimes sep->se_socktype == SOCK_STREAM) 4951553Srgrimes close(ctrl); 49642122Sdes sigsetmask(0L); 4971553Srgrimes sleep(1); 4981553Srgrimes continue; 4991553Srgrimes } 50019618Sjulian if (pid) 50119618Sjulian addchild(sep, pid); 50242122Sdes sigsetmask(0L); 5031553Srgrimes if (pid == 0) { 5041553Srgrimes if (dofork) { 5051553Srgrimes if (debug) 50629602Scharnier warnx("+ closing from %d", maxsock); 5071553Srgrimes for (tmpint = maxsock; tmpint > 2; tmpint--) 5081553Srgrimes if (tmpint != ctrl) 50919617Sjulian (void) close(tmpint); 51048962Ssheldonh sigaction(SIGALRM, &saalrm, (struct sigaction *)0); 51148962Ssheldonh sigaction(SIGCHLD, &sachld, (struct sigaction *)0); 51248962Ssheldonh sigaction(SIGHUP, &sahup, (struct sigaction *)0); 51348962Ssheldonh /* SIGPIPE reset before exec */ 5141553Srgrimes } 51535829Sguido /* 51635829Sguido * Call tcpmux to find the real service to exec. 51735829Sguido */ 51835829Sguido if (sep->se_bi && 51935829Sguido sep->se_bi->bi_fn == (void (*)()) tcpmux) { 52035829Sguido sep = tcpmux(ctrl); 52135829Sguido if (sep == NULL) { 52235829Sguido close(ctrl); 52335829Sguido _exit(0); 52435829Sguido } 52535829Sguido } 52648382Ssheldonh if (ISWRAP(sep)) { 52748698Ssheldonh inetd_setproctitle("wrapping", ctrl); 52847972Ssheldonh service = sep->se_server_name ? 52947972Ssheldonh sep->se_server_name : sep->se_service; 53047972Ssheldonh request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL); 53145089Smarkm fromhost(&req); 53247972Ssheldonh deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY; 53347972Ssheldonh allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY; 53445089Smarkm denied = !hosts_access(&req); 53545089Smarkm if (denied) { 53645089Smarkm syslog(deny_severity, 53745089Smarkm "refused connection from %.500s, service %s (%s)", 53845089Smarkm eval_client(&req), service, sep->se_proto); 53948382Ssheldonh if (sep->se_socktype != SOCK_STREAM) 54048382Ssheldonh recv(ctrl, buf, sizeof (buf), 0); 54148382Ssheldonh if (dofork) 54248382Ssheldonh _exit(0); 54345089Smarkm } 54445089Smarkm if (log) { 54545089Smarkm syslog(allow_severity, 54645089Smarkm "connection from %.500s, service %s (%s)", 54745089Smarkm eval_client(&req), service, sep->se_proto); 54845089Smarkm } 54945089Smarkm } 55019617Sjulian if (sep->se_bi) { 5511553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 55219617Sjulian } else { 5531553Srgrimes if (debug) 55429602Scharnier warnx("%d execl %s", 55529602Scharnier getpid(), sep->se_server); 5561553Srgrimes dup2(ctrl, 0); 5571553Srgrimes close(ctrl); 5581553Srgrimes dup2(0, 1); 5591553Srgrimes dup2(0, 2); 5601553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 5611553Srgrimes syslog(LOG_ERR, 5621553Srgrimes "%s/%s: %s: No such user", 5631553Srgrimes sep->se_service, sep->se_proto, 5641553Srgrimes sep->se_user); 5651553Srgrimes if (sep->se_socktype != SOCK_STREAM) 5661553Srgrimes recv(0, buf, sizeof (buf), 0); 56719617Sjulian _exit(EX_NOUSER); 5681553Srgrimes } 56930807Sache grp = NULL; 57030807Sache if ( sep->se_group != NULL 57130807Sache && (grp = getgrnam(sep->se_group)) == NULL 57230807Sache ) { 57330807Sache syslog(LOG_ERR, 57430807Sache "%s/%s: %s: No such group", 57530807Sache sep->se_service, sep->se_proto, 57630807Sache sep->se_group); 57730807Sache if (sep->se_socktype != SOCK_STREAM) 57830807Sache recv(0, buf, sizeof (buf), 0); 57930807Sache _exit(EX_NOUSER); 58030807Sache } 58130807Sache if (grp != NULL) 58230807Sache pwd->pw_gid = grp->gr_gid; 58321640Speter#ifdef LOGIN_CAP 58430792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 58530792Sache /* error syslogged by getclass */ 58630792Sache syslog(LOG_ERR, 58730792Sache "%s/%s: %s: login class error", 58837850Sache sep->se_service, sep->se_proto, 58937850Sache sep->se_class); 59030792Sache if (sep->se_socktype != SOCK_STREAM) 59130792Sache recv(0, buf, sizeof (buf), 0); 59230792Sache _exit(EX_NOUSER); 59330792Sache } 59421640Speter#endif 59512024Speter if (setsid() < 0) { 59612024Speter syslog(LOG_ERR, 59712024Speter "%s: can't setsid(): %m", 59812024Speter sep->se_service); 59919617Sjulian /* _exit(EX_OSERR); not fatal yet */ 60012024Speter } 60121640Speter#ifdef LOGIN_CAP 60221640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 60321640Speter LOGIN_SETALL) != 0) { 60421640Speter syslog(LOG_ERR, 60521640Speter "%s: can't setusercontext(..%s..): %m", 60621640Speter sep->se_service, sep->se_user); 60721640Speter _exit(EX_OSERR); 60821640Speter } 60921640Speter#else 6101553Srgrimes if (pwd->pw_uid) { 61112024Speter if (setlogin(sep->se_user) < 0) { 61212024Speter syslog(LOG_ERR, 61312024Speter "%s: can't setlogin(%s): %m", 61412024Speter sep->se_service, sep->se_user); 61519617Sjulian /* _exit(EX_OSERR); not yet */ 61612024Speter } 6171553Srgrimes if (setgid(pwd->pw_gid) < 0) { 6181553Srgrimes syslog(LOG_ERR, 6198857Srgrimes "%s: can't set gid %d: %m", 6201553Srgrimes sep->se_service, pwd->pw_gid); 62119617Sjulian _exit(EX_OSERR); 6221553Srgrimes } 6231553Srgrimes (void) initgroups(pwd->pw_name, 6241553Srgrimes pwd->pw_gid); 6251553Srgrimes if (setuid(pwd->pw_uid) < 0) { 6261553Srgrimes syslog(LOG_ERR, 6278857Srgrimes "%s: can't set uid %d: %m", 6281553Srgrimes sep->se_service, pwd->pw_uid); 62919617Sjulian _exit(EX_OSERR); 6301553Srgrimes } 6311553Srgrimes } 63221640Speter#endif 63335948Sbde sigaction(SIGPIPE, &sapipe, 63435948Sbde (struct sigaction *)0); 6351553Srgrimes execv(sep->se_server, sep->se_argv); 63645089Smarkm syslog(LOG_ERR, 63745089Smarkm "cannot execute %s: %m", sep->se_server); 6381553Srgrimes if (sep->se_socktype != SOCK_STREAM) 6391553Srgrimes recv(0, buf, sizeof (buf), 0); 6401553Srgrimes } 64147972Ssheldonh if (dofork) 64247972Ssheldonh _exit(0); 6431553Srgrimes } 64419618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 6451553Srgrimes close(ctrl); 6461553Srgrimes } 6471553Srgrimes } 6481553Srgrimes} 6491553Srgrimes 65019618Sjulian/* 65142122Sdes * Add a signal flag to the signal flag queue for later handling 65242122Sdes */ 65342122Sdes 65442122Sdesvoid flag_signal(c) 65542122Sdes char c; 65642122Sdes{ 65742250Sdes if (write(signalpipe[1], &c, 1) != 1) { 65842250Sdes syslog(LOG_ERR, "write: %m"); 65942250Sdes exit(EX_OSERR); 66042250Sdes } 66142122Sdes} 66242122Sdes 66342122Sdes/* 66419618Sjulian * Record a new child pid for this service. If we've reached the 66519618Sjulian * limit on children, then stop accepting incoming requests. 66619618Sjulian */ 66719618Sjulian 6681553Srgrimesvoid 66919618Sjulianaddchild(struct servtab *sep, pid_t pid) 67019618Sjulian{ 67119618Sjulian#ifdef SANITY_CHECK 67219618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 67319618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 67419618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 67519618Sjulian exit(EX_SOFTWARE); 67619618Sjulian } 67719618Sjulian#endif 67819618Sjulian if (sep->se_maxchild == 0) 67919618Sjulian return; 68019618Sjulian sep->se_pids[sep->se_numchild++] = pid; 68119618Sjulian if (sep->se_numchild == sep->se_maxchild) 68219618Sjulian disable(sep); 68319618Sjulian} 68419618Sjulian 68519618Sjulian/* 68619618Sjulian * Some child process has exited. See if it's on somebody's list. 68719618Sjulian */ 68819618Sjulian 68919618Sjulianvoid 69042122Sdesflag_reapchild(signo) 6911553Srgrimes int signo; 6921553Srgrimes{ 69342250Sdes flag_signal('C'); 69442122Sdes} 69542122Sdes 69642122Sdesvoid 69742122Sdesreapchild() 69842122Sdes{ 69919618Sjulian int k, status; 7001553Srgrimes pid_t pid; 7011553Srgrimes struct servtab *sep; 7021553Srgrimes 7031553Srgrimes for (;;) { 7041553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 7051553Srgrimes if (pid <= 0) 7061553Srgrimes break; 7071553Srgrimes if (debug) 70829602Scharnier warnx("%d reaped, status %#x", pid, status); 70919618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 71019618Sjulian for (k = 0; k < sep->se_numchild; k++) 71119618Sjulian if (sep->se_pids[k] == pid) 71219618Sjulian break; 71319618Sjulian if (k == sep->se_numchild) 71419618Sjulian continue; 71519618Sjulian if (sep->se_numchild == sep->se_maxchild) 71619618Sjulian enable(sep); 71719618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 71819618Sjulian if (status) 71919618Sjulian syslog(LOG_WARNING, 72019618Sjulian "%s[%d]: exit status 0x%x", 72119618Sjulian sep->se_server, pid, status); 72219618Sjulian break; 72319618Sjulian } 7241553Srgrimes } 7251553Srgrimes} 7261553Srgrimes 7271553Srgrimesvoid 72842122Sdesflag_config(signo) 7291553Srgrimes int signo; 7301553Srgrimes{ 73142250Sdes flag_signal('H'); 73242122Sdes} 73342122Sdes 73442122Sdesvoid config() 73542122Sdes{ 73619618Sjulian struct servtab *sep, *new, **sepp; 73742122Sdes long omask; 7381553Srgrimes 7391553Srgrimes if (!setconfig()) { 7401553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 7411553Srgrimes return; 7421553Srgrimes } 7431553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 7441553Srgrimes sep->se_checked = 0; 74519618Sjulian while ((new = getconfigent())) { 74630807Sache if (getpwnam(new->se_user) == NULL) { 7471553Srgrimes syslog(LOG_ERR, 7481553Srgrimes "%s/%s: No such user '%s', service ignored", 74919618Sjulian new->se_service, new->se_proto, new->se_user); 7501553Srgrimes continue; 7511553Srgrimes } 75230807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 75330807Sache syslog(LOG_ERR, 75430807Sache "%s/%s: No such group '%s', service ignored", 75530807Sache new->se_service, new->se_proto, new->se_group); 75630807Sache continue; 75730807Sache } 75830792Sache#ifdef LOGIN_CAP 75930792Sache if (login_getclass(new->se_class) == NULL) { 76030792Sache /* error syslogged by getclass */ 76130792Sache syslog(LOG_ERR, 76237850Sache "%s/%s: %s: login class error, service ignored", 76337850Sache new->se_service, new->se_proto, new->se_class); 76430792Sache continue; 76530792Sache } 76630792Sache#endif 7671553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 76819618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 76919618Sjulian strcmp(sep->se_proto, new->se_proto) == 0) 7701553Srgrimes break; 7711553Srgrimes if (sep != 0) { 7721553Srgrimes int i; 7731553Srgrimes 77419618Sjulian#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 77542122Sdes omask = sigblock(SIGBLOCK); 77619618Sjulian /* copy over outstanding child pids */ 77719618Sjulian if (sep->se_maxchild && new->se_maxchild) { 77819618Sjulian new->se_numchild = sep->se_numchild; 77919618Sjulian if (new->se_numchild > new->se_maxchild) 78019618Sjulian new->se_numchild = new->se_maxchild; 78119618Sjulian memcpy(new->se_pids, sep->se_pids, 78219618Sjulian new->se_numchild * sizeof(*new->se_pids)); 78319618Sjulian } 78419618Sjulian SWAP(sep->se_pids, new->se_pids); 78519618Sjulian sep->se_maxchild = new->se_maxchild; 78619618Sjulian sep->se_numchild = new->se_numchild; 78730847Sdima sep->se_maxcpm = new->se_maxcpm; 78819618Sjulian /* might need to turn on or off service now */ 78919618Sjulian if (sep->se_fd >= 0) { 79019618Sjulian if (sep->se_maxchild 79119618Sjulian && sep->se_numchild == sep->se_maxchild) { 79219618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 79319618Sjulian disable(sep); 79419618Sjulian } else { 79519618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 79619618Sjulian enable(sep); 79719618Sjulian } 79819618Sjulian } 79919618Sjulian sep->se_accept = new->se_accept; 80030807Sache SWAP(sep->se_user, new->se_user); 80130807Sache SWAP(sep->se_group, new->se_group); 80230792Sache#ifdef LOGIN_CAP 80330807Sache SWAP(sep->se_class, new->se_class); 80430792Sache#endif 80530807Sache SWAP(sep->se_server, new->se_server); 80647972Ssheldonh SWAP(sep->se_server_name, new->se_server_name); 8071553Srgrimes for (i = 0; i < MAXARGV; i++) 80819618Sjulian SWAP(sep->se_argv[i], new->se_argv[i]); 80942122Sdes sigsetmask(omask); 81019618Sjulian freeconfig(new); 8111553Srgrimes if (debug) 8121553Srgrimes print_service("REDO", sep); 8131553Srgrimes } else { 81419618Sjulian sep = enter(new); 8151553Srgrimes if (debug) 8161553Srgrimes print_service("ADD ", sep); 8171553Srgrimes } 8181553Srgrimes sep->se_checked = 1; 8191553Srgrimes if (ISMUX(sep)) { 8201553Srgrimes sep->se_fd = -1; 8211553Srgrimes continue; 8221553Srgrimes } 8232657Scsgr if (!sep->se_rpc) { 8242657Scsgr sp = getservbyname(sep->se_service, sep->se_proto); 8252657Scsgr if (sp == 0) { 8262657Scsgr syslog(LOG_ERR, "%s/%s: unknown service", 8272657Scsgr sep->se_service, sep->se_proto); 8282657Scsgr sep->se_checked = 0; 8292657Scsgr continue; 8302657Scsgr } 8312657Scsgr if (sp->s_port != sep->se_ctrladdr.sin_port) { 8322657Scsgr sep->se_ctrladdr.sin_family = AF_INET; 83322306Sjulian sep->se_ctrladdr.sin_addr = bind_address; 8342657Scsgr sep->se_ctrladdr.sin_port = sp->s_port; 8352657Scsgr if (sep->se_fd >= 0) 8362657Scsgr close_sep(sep); 8372657Scsgr } 8382657Scsgr } else { 8392657Scsgr rpc = getrpcbyname(sep->se_service); 8402657Scsgr if (rpc == 0) { 8412657Scsgr syslog(LOG_ERR, "%s/%s unknown RPC service.", 8422657Scsgr sep->se_service, sep->se_proto); 8432657Scsgr if (sep->se_fd != -1) 8442657Scsgr (void) close(sep->se_fd); 8452657Scsgr sep->se_fd = -1; 8462657Scsgr continue; 8472657Scsgr } 8482657Scsgr if (rpc->r_number != sep->se_rpc_prog) { 8492657Scsgr if (sep->se_rpc_prog) 8502657Scsgr unregisterrpc(sep); 8512657Scsgr sep->se_rpc_prog = rpc->r_number; 8522657Scsgr if (sep->se_fd != -1) 8532657Scsgr (void) close(sep->se_fd); 8542657Scsgr sep->se_fd = -1; 8552657Scsgr } 8561553Srgrimes } 8571553Srgrimes if (sep->se_fd == -1) 8581553Srgrimes setup(sep); 8591553Srgrimes } 8601553Srgrimes endconfig(); 8611553Srgrimes /* 8621553Srgrimes * Purge anything not looked at above. 8631553Srgrimes */ 86442122Sdes omask = sigblock(SIGBLOCK); 8651553Srgrimes sepp = &servtab; 86619617Sjulian while ((sep = *sepp)) { 8671553Srgrimes if (sep->se_checked) { 8681553Srgrimes sepp = &sep->se_next; 8691553Srgrimes continue; 8701553Srgrimes } 8711553Srgrimes *sepp = sep->se_next; 8721553Srgrimes if (sep->se_fd >= 0) 8731553Srgrimes close_sep(sep); 8741553Srgrimes if (debug) 8751553Srgrimes print_service("FREE", sep); 8762657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 8772657Scsgr unregisterrpc(sep); 8781553Srgrimes freeconfig(sep); 8791553Srgrimes free((char *)sep); 8801553Srgrimes } 88142122Sdes (void) sigsetmask(omask); 8821553Srgrimes} 8831553Srgrimes 8841553Srgrimesvoid 8852657Scsgrunregisterrpc(sep) 8862657Scsgr struct servtab *sep; 8872657Scsgr{ 8882657Scsgr int i; 8892657Scsgr struct servtab *sepp; 89042122Sdes long omask; 8912657Scsgr 89242122Sdes omask = sigblock(SIGBLOCK); 8932657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 8942657Scsgr if (sepp == sep) 8952657Scsgr continue; 8962657Scsgr if (sep->se_checked == 0 || 8972657Scsgr !sepp->se_rpc || 8982657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 8992657Scsgr continue; 9002657Scsgr return; 9012657Scsgr } 9022657Scsgr if (debug) 9032657Scsgr print_service("UNREG", sep); 9042657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 9052657Scsgr pmap_unset(sep->se_rpc_prog, i); 9062657Scsgr if (sep->se_fd != -1) 9072657Scsgr (void) close(sep->se_fd); 9082657Scsgr sep->se_fd = -1; 90942122Sdes (void) sigsetmask(omask); 9102657Scsgr} 9112657Scsgr 9122657Scsgrvoid 91342122Sdesflag_retry(signo) 9141553Srgrimes int signo; 9151553Srgrimes{ 91642250Sdes flag_signal('A'); 91742122Sdes} 91842122Sdes 91942122Sdesvoid 92042122Sdesretry() 92142122Sdes{ 9221553Srgrimes struct servtab *sep; 9231553Srgrimes 9241553Srgrimes timingout = 0; 9251553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 92619617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 9271553Srgrimes setup(sep); 9281553Srgrimes} 9291553Srgrimes 9301553Srgrimesvoid 9311553Srgrimessetup(sep) 9321553Srgrimes struct servtab *sep; 9331553Srgrimes{ 9341553Srgrimes int on = 1; 9351553Srgrimes 9361553Srgrimes if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 9371553Srgrimes if (debug) 93829602Scharnier warn("socket failed on %s/%s", 93929602Scharnier sep->se_service, sep->se_proto); 9401553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 9411553Srgrimes sep->se_service, sep->se_proto); 9421553Srgrimes return; 9431553Srgrimes } 9441553Srgrimes#define turnon(fd, opt) \ 9451553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 9461553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 9471553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 9481553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 9491553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 9501553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 95125253Swollman#ifdef SO_PRIVSTATE 95213956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 95313956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 95425253Swollman#endif 9551553Srgrimes#undef turnon 95636042Sguido if (sep->se_type == TTCP_TYPE) 95736042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 95836042Sguido (char *)&on, sizeof (on)) < 0) 95936042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 9601553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 9611553Srgrimes sizeof (sep->se_ctrladdr)) < 0) { 9621553Srgrimes if (debug) 96329602Scharnier warn("bind failed on %s/%s", 96429602Scharnier sep->se_service, sep->se_proto); 9651553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 9661553Srgrimes sep->se_service, sep->se_proto); 9671553Srgrimes (void) close(sep->se_fd); 9681553Srgrimes sep->se_fd = -1; 9691553Srgrimes if (!timingout) { 9701553Srgrimes timingout = 1; 9711553Srgrimes alarm(RETRYTIME); 9721553Srgrimes } 9731553Srgrimes return; 9741553Srgrimes } 9752657Scsgr if (sep->se_rpc) { 9762657Scsgr int i, len = sizeof(struct sockaddr); 9772657Scsgr 9788857Srgrimes if (getsockname(sep->se_fd, 9792657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 9802657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 9812657Scsgr sep->se_service, sep->se_proto); 9822657Scsgr (void) close(sep->se_fd); 9832657Scsgr sep->se_fd = -1; 9848857Srgrimes return; 9852657Scsgr } 9862657Scsgr if (debug) 9872657Scsgr print_service("REG ", sep); 9882657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 9892657Scsgr pmap_unset(sep->se_rpc_prog, i); 9902657Scsgr pmap_set(sep->se_rpc_prog, i, 9912657Scsgr (sep->se_socktype == SOCK_DGRAM) 9922657Scsgr ? IPPROTO_UDP : IPPROTO_TCP, 9932657Scsgr ntohs(sep->se_ctrladdr.sin_port)); 9942657Scsgr } 9958857Srgrimes 9962657Scsgr } 9971553Srgrimes if (sep->se_socktype == SOCK_STREAM) 99817197Sdg listen(sep->se_fd, 64); 99919618Sjulian enable(sep); 10001553Srgrimes if (debug) { 100129602Scharnier warnx("registered %s on %d", 10021553Srgrimes sep->se_server, sep->se_fd); 10031553Srgrimes } 10041553Srgrimes} 10051553Srgrimes 10061553Srgrimes/* 10071553Srgrimes * Finish with a service and its socket. 10081553Srgrimes */ 10091553Srgrimesvoid 10101553Srgrimesclose_sep(sep) 10111553Srgrimes struct servtab *sep; 10121553Srgrimes{ 10131553Srgrimes if (sep->se_fd >= 0) { 101419618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 101519618Sjulian disable(sep); 10161553Srgrimes (void) close(sep->se_fd); 10171553Srgrimes sep->se_fd = -1; 10181553Srgrimes } 10191553Srgrimes sep->se_count = 0; 102019618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 10211553Srgrimes} 10221553Srgrimes 102348467Ssheldonhint 102448467Ssheldonhmatchservent(name1, name2, proto) 102548467Ssheldonh char *name1, *name2, *proto; 102648467Ssheldonh{ 102748467Ssheldonh char **alias; 102848467Ssheldonh struct servent *se; 102948467Ssheldonh 103048467Ssheldonh if ((se = getservbyname(name1, proto)) != NULL) { 103148467Ssheldonh if (strcmp(name2, se->s_name) == 0) 103248467Ssheldonh return(1); 103348467Ssheldonh for (alias = se->s_aliases; *alias; alias++) 103448467Ssheldonh if (strcmp(name2, *alias) == 0) 103548467Ssheldonh return(1); 103648467Ssheldonh } 103748467Ssheldonh return(0); 103848467Ssheldonh} 103948467Ssheldonh 10401553Srgrimesstruct servtab * 10411553Srgrimesenter(cp) 10421553Srgrimes struct servtab *cp; 10431553Srgrimes{ 10441553Srgrimes struct servtab *sep; 104542122Sdes long omask; 10461553Srgrimes 10471553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 10481553Srgrimes if (sep == (struct servtab *)0) { 10491553Srgrimes syslog(LOG_ERR, "Out of memory."); 105019617Sjulian exit(EX_OSERR); 10511553Srgrimes } 10521553Srgrimes *sep = *cp; 10531553Srgrimes sep->se_fd = -1; 105442122Sdes omask = sigblock(SIGBLOCK); 10551553Srgrimes sep->se_next = servtab; 10561553Srgrimes servtab = sep; 105742122Sdes sigsetmask(omask); 10581553Srgrimes return (sep); 10591553Srgrimes} 10601553Srgrimes 106119618Sjulianvoid 106219618Sjulianenable(struct servtab *sep) 106319618Sjulian{ 106419618Sjulian if (debug) 106529602Scharnier warnx( 106619618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 106719618Sjulian#ifdef SANITY_CHECK 106819618Sjulian if (sep->se_fd < 0) { 106919618Sjulian syslog(LOG_ERR, 107019618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 107119618Sjulian exit(EX_SOFTWARE); 107219618Sjulian } 107319618Sjulian if (ISMUX(sep)) { 107419618Sjulian syslog(LOG_ERR, 107519618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 107619618Sjulian exit(EX_SOFTWARE); 107719618Sjulian } 107819618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 107919618Sjulian syslog(LOG_ERR, 108019618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 108119618Sjulian exit(EX_SOFTWARE); 108219618Sjulian } 108319618Sjulian#endif 108419618Sjulian FD_SET(sep->se_fd, &allsock); 108519618Sjulian nsock++; 108619618Sjulian if (sep->se_fd > maxsock) 108719618Sjulian maxsock = sep->se_fd; 108819618Sjulian} 108919618Sjulian 109019618Sjulianvoid 109119618Sjuliandisable(struct servtab *sep) 109219618Sjulian{ 109319618Sjulian if (debug) 109429602Scharnier warnx( 109519618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 109619618Sjulian#ifdef SANITY_CHECK 109719618Sjulian if (sep->se_fd < 0) { 109819618Sjulian syslog(LOG_ERR, 109919618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 110019618Sjulian exit(EX_SOFTWARE); 110119618Sjulian } 110219618Sjulian if (ISMUX(sep)) { 110319618Sjulian syslog(LOG_ERR, 110419618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 110519618Sjulian exit(EX_SOFTWARE); 110619618Sjulian } 110719618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 110819618Sjulian syslog(LOG_ERR, 110919618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 111019618Sjulian exit(EX_SOFTWARE); 111119618Sjulian } 111219618Sjulian if (nsock == 0) { 111319618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 111419618Sjulian exit(EX_SOFTWARE); 111519618Sjulian } 111619618Sjulian#endif 111719618Sjulian FD_CLR(sep->se_fd, &allsock); 111819618Sjulian nsock--; 111919618Sjulian if (sep->se_fd == maxsock) 112019618Sjulian maxsock--; 112119618Sjulian} 112219618Sjulian 11231553SrgrimesFILE *fconfig = NULL; 11241553Srgrimesstruct servtab serv; 11251553Srgrimeschar line[LINE_MAX]; 11261553Srgrimes 11271553Srgrimesint 11281553Srgrimessetconfig() 11291553Srgrimes{ 11301553Srgrimes 11311553Srgrimes if (fconfig != NULL) { 11321553Srgrimes fseek(fconfig, 0L, SEEK_SET); 11331553Srgrimes return (1); 11341553Srgrimes } 11351553Srgrimes fconfig = fopen(CONFIG, "r"); 11361553Srgrimes return (fconfig != NULL); 11371553Srgrimes} 11381553Srgrimes 11391553Srgrimesvoid 11401553Srgrimesendconfig() 11411553Srgrimes{ 11421553Srgrimes if (fconfig) { 11431553Srgrimes (void) fclose(fconfig); 11441553Srgrimes fconfig = NULL; 11451553Srgrimes } 11461553Srgrimes} 11471553Srgrimes 11481553Srgrimesstruct servtab * 11491553Srgrimesgetconfigent() 11501553Srgrimes{ 11511553Srgrimes struct servtab *sep = &serv; 11521553Srgrimes int argc; 115319618Sjulian char *cp, *arg, *s; 11542657Scsgr char *versp; 11551553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 11561553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 11571553Srgrimes 11581553Srgrimesmore: 11591553Srgrimes while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 11601553Srgrimes ; 11611553Srgrimes if (cp == NULL) 11621553Srgrimes return ((struct servtab *)0); 11631553Srgrimes /* 11641553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 11651553Srgrimes * for example) don't get initialized here. 11661553Srgrimes */ 11671553Srgrimes memset((caddr_t)sep, 0, sizeof *sep); 11681553Srgrimes arg = skip(&cp); 11691553Srgrimes if (cp == NULL) { 11701553Srgrimes /* got an empty line containing just blanks/tabs. */ 11711553Srgrimes goto more; 11721553Srgrimes } 11731553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 11741553Srgrimes char *c = arg + MUX_LEN; 11751553Srgrimes if (*c == '+') { 11761553Srgrimes sep->se_type = MUXPLUS_TYPE; 11771553Srgrimes c++; 11781553Srgrimes } else 11791553Srgrimes sep->se_type = MUX_TYPE; 11801553Srgrimes sep->se_service = newstr(c); 11811553Srgrimes } else { 11821553Srgrimes sep->se_service = newstr(arg); 11831553Srgrimes sep->se_type = NORM_TYPE; 11841553Srgrimes } 11851553Srgrimes arg = sskip(&cp); 11861553Srgrimes if (strcmp(arg, "stream") == 0) 11871553Srgrimes sep->se_socktype = SOCK_STREAM; 11881553Srgrimes else if (strcmp(arg, "dgram") == 0) 11891553Srgrimes sep->se_socktype = SOCK_DGRAM; 11901553Srgrimes else if (strcmp(arg, "rdm") == 0) 11911553Srgrimes sep->se_socktype = SOCK_RDM; 11921553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 11931553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 11941553Srgrimes else if (strcmp(arg, "raw") == 0) 11951553Srgrimes sep->se_socktype = SOCK_RAW; 11961553Srgrimes else 11971553Srgrimes sep->se_socktype = -1; 119836042Sguido 119936042Sguido arg = sskip(&cp); 120036042Sguido if (strcmp(arg, "tcp/ttcp") == 0) { 120136042Sguido sep->se_type = TTCP_TYPE; 120236042Sguido sep->se_proto = newstr("tcp"); 120336042Sguido } else { 120436042Sguido sep->se_proto = newstr(arg); 120536042Sguido } 12062657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 120719237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 120819237Sjoerg strlen(sep->se_proto) + 1 - 4); 12092657Scsgr sep->se_rpc = 1; 12102657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 12112657Scsgr sep->se_rpc_lowvers = 0; 12122657Scsgr sep->se_ctrladdr.sin_family = AF_INET; 12132657Scsgr sep->se_ctrladdr.sin_port = 0; 121417482Sjulian sep->se_ctrladdr.sin_addr = bind_address; 12152657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 12162657Scsgr *versp++ = '\0'; 12172657Scsgr switch (sscanf(versp, "%d-%d", 12182657Scsgr &sep->se_rpc_lowvers, 12192657Scsgr &sep->se_rpc_highvers)) { 12202657Scsgr case 2: 12212657Scsgr break; 12222657Scsgr case 1: 12232657Scsgr sep->se_rpc_highvers = 12242657Scsgr sep->se_rpc_lowvers; 12252657Scsgr break; 12262657Scsgr default: 12278857Srgrimes syslog(LOG_ERR, 12288857Srgrimes "bad RPC version specifier; %s\n", 12292657Scsgr sep->se_service); 12302657Scsgr freeconfig(sep); 12312657Scsgr goto more; 12322657Scsgr } 12332657Scsgr } 12342657Scsgr else { 12352657Scsgr sep->se_rpc_lowvers = 12362657Scsgr sep->se_rpc_highvers = 1; 12372657Scsgr } 12382657Scsgr } 12391553Srgrimes arg = sskip(&cp); 124019618Sjulian if (!strncmp(arg, "wait", 4)) 124119618Sjulian sep->se_accept = 0; 124219618Sjulian else if (!strncmp(arg, "nowait", 6)) 124319618Sjulian sep->se_accept = 1; 124419618Sjulian else { 124519618Sjulian syslog(LOG_ERR, 124619618Sjulian "%s: bad wait/nowait for service %s", 124719618Sjulian CONFIG, sep->se_service); 124819618Sjulian goto more; 124919618Sjulian } 125048069Ssheldonh sep->se_maxchild = -1; 125148069Ssheldonh sep->se_maxcpm = -1; 125219618Sjulian if ((s = strchr(arg, '/')) != NULL) { 125319618Sjulian char *eptr; 125419618Sjulian u_long val; 125519618Sjulian 125619618Sjulian val = strtoul(s + 1, &eptr, 10); 125730847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 125819618Sjulian syslog(LOG_ERR, 125919618Sjulian "%s: bad max-child for service %s", 126019618Sjulian CONFIG, sep->se_service); 126119618Sjulian goto more; 126219618Sjulian } 126348069Ssheldonh if (debug) 126448069Ssheldonh if (!sep->se_accept && val != 1) 126548069Ssheldonh warnx("maxchild=%lu for wait service %s" 126648069Ssheldonh " not recommended", val, sep->se_service); 126719618Sjulian sep->se_maxchild = val; 126830847Sdima if (*eptr == '/') 126930847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 127030847Sdima /* 127130847Sdima * explicitly do not check for \0 for future expansion / 127230847Sdima * backwards compatibility 127330847Sdima */ 127419618Sjulian } 12751553Srgrimes if (ISMUX(sep)) { 12761553Srgrimes /* 127719618Sjulian * Silently enforce "nowait" mode for TCPMUX services 127819618Sjulian * since they don't have an assigned port to listen on. 12791553Srgrimes */ 128019618Sjulian sep->se_accept = 1; 12811553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 12828857Srgrimes syslog(LOG_ERR, 12831553Srgrimes "%s: bad protocol for tcpmux service %s", 12841553Srgrimes CONFIG, sep->se_service); 12851553Srgrimes goto more; 12861553Srgrimes } 12871553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 12888857Srgrimes syslog(LOG_ERR, 12891553Srgrimes "%s: bad socket type for tcpmux service %s", 12901553Srgrimes CONFIG, sep->se_service); 12911553Srgrimes goto more; 12921553Srgrimes } 12931553Srgrimes } 12941553Srgrimes sep->se_user = newstr(sskip(&cp)); 129530792Sache#ifdef LOGIN_CAP 129630792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 129730792Sache *s = '\0'; 129830792Sache sep->se_class = newstr(s + 1); 129930792Sache } else 130030792Sache sep->se_class = newstr(RESOURCE_RC); 130130792Sache#endif 130230807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 130330807Sache *s = '\0'; 130430807Sache sep->se_group = newstr(s + 1); 130530807Sache } else 130630807Sache sep->se_group = NULL; 13071553Srgrimes sep->se_server = newstr(sskip(&cp)); 130845588Smarkm if ((sep->se_server_name = rindex(sep->se_server, '/'))) 130945588Smarkm sep->se_server_name++; 13101553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 13111553Srgrimes struct biltin *bi; 13121553Srgrimes 13131553Srgrimes for (bi = biltins; bi->bi_service; bi++) 131448467Ssheldonh if ((bi->bi_socktype == sep->se_socktype && 131548467Ssheldonh strcmp(bi->bi_service, sep->se_service) == 0) || 131648467Ssheldonh matchservent(bi->bi_service, sep->se_service, 131748467Ssheldonh sep->se_proto)) 13181553Srgrimes break; 13191553Srgrimes if (bi->bi_service == 0) { 13201553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 13211553Srgrimes sep->se_service); 13221553Srgrimes goto more; 13231553Srgrimes } 132419618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 13251553Srgrimes sep->se_bi = bi; 13261553Srgrimes } else 13271553Srgrimes sep->se_bi = NULL; 132848069Ssheldonh if (sep->se_maxcpm < 0) 132948069Ssheldonh sep->se_maxcpm = maxcpm; 133045588Smarkm if (sep->se_maxchild < 0) { /* apply default max-children */ 133148069Ssheldonh if (sep->se_bi && sep->se_bi->bi_maxchild >= 0) 133219618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 133348069Ssheldonh else if (sep->se_accept) 133448069Ssheldonh sep->se_maxchild = maxchild > 0 ? maxchild : 0; 133519618Sjulian else 133648069Ssheldonh sep->se_maxchild = 1; 133745588Smarkm } 133819618Sjulian if (sep->se_maxchild) { 133919618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 134019618Sjulian if (sep->se_pids == NULL) { 134119618Sjulian syslog(LOG_ERR, "Out of memory."); 134219618Sjulian exit(EX_OSERR); 134319618Sjulian } 134419618Sjulian } 13451553Srgrimes argc = 0; 13461553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 134719618Sjulian if (argc < MAXARGV) { 13481553Srgrimes sep->se_argv[argc++] = newstr(arg); 134919618Sjulian } else { 135019618Sjulian syslog(LOG_ERR, 135119618Sjulian "%s: too many arguments for service %s", 135219618Sjulian CONFIG, sep->se_service); 135319618Sjulian goto more; 135419618Sjulian } 13551553Srgrimes while (argc <= MAXARGV) 13561553Srgrimes sep->se_argv[argc++] = NULL; 13571553Srgrimes return (sep); 13581553Srgrimes} 13591553Srgrimes 13601553Srgrimesvoid 13611553Srgrimesfreeconfig(cp) 13621553Srgrimes struct servtab *cp; 13631553Srgrimes{ 13641553Srgrimes int i; 13651553Srgrimes 13661553Srgrimes if (cp->se_service) 13671553Srgrimes free(cp->se_service); 13681553Srgrimes if (cp->se_proto) 13691553Srgrimes free(cp->se_proto); 13701553Srgrimes if (cp->se_user) 13711553Srgrimes free(cp->se_user); 137230807Sache if (cp->se_group) 137330807Sache free(cp->se_group); 137430792Sache#ifdef LOGIN_CAP 137530792Sache if (cp->se_class) 137630792Sache free(cp->se_class); 137730792Sache#endif 13781553Srgrimes if (cp->se_server) 13791553Srgrimes free(cp->se_server); 138019618Sjulian if (cp->se_pids) 138119618Sjulian free(cp->se_pids); 13821553Srgrimes for (i = 0; i < MAXARGV; i++) 13831553Srgrimes if (cp->se_argv[i]) 13841553Srgrimes free(cp->se_argv[i]); 13851553Srgrimes} 13861553Srgrimes 13871553Srgrimes 13881553Srgrimes/* 13891553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 13901553Srgrimes * configuration file and exit. 13911553Srgrimes */ 13921553Srgrimeschar * 13931553Srgrimessskip(cpp) 13941553Srgrimes char **cpp; 13951553Srgrimes{ 13961553Srgrimes char *cp; 13971553Srgrimes 13981553Srgrimes cp = skip(cpp); 13991553Srgrimes if (cp == NULL) { 14001553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 140119617Sjulian exit(EX_DATAERR); 14021553Srgrimes } 14031553Srgrimes return (cp); 14041553Srgrimes} 14051553Srgrimes 14061553Srgrimeschar * 14071553Srgrimesskip(cpp) 14081553Srgrimes char **cpp; 14091553Srgrimes{ 14101553Srgrimes char *cp = *cpp; 14111553Srgrimes char *start; 141211933Sadam char quote = '\0'; 14131553Srgrimes 14141553Srgrimesagain: 14151553Srgrimes while (*cp == ' ' || *cp == '\t') 14161553Srgrimes cp++; 14171553Srgrimes if (*cp == '\0') { 14181553Srgrimes int c; 14191553Srgrimes 14201553Srgrimes c = getc(fconfig); 14211553Srgrimes (void) ungetc(c, fconfig); 14221553Srgrimes if (c == ' ' || c == '\t') 142319617Sjulian if ((cp = nextline(fconfig))) 14241553Srgrimes goto again; 14251553Srgrimes *cpp = (char *)0; 14261553Srgrimes return ((char *)0); 14271553Srgrimes } 142811933Sadam if (*cp == '"' || *cp == '\'') 142911933Sadam quote = *cp++; 14301553Srgrimes start = cp; 143111933Sadam if (quote) 143211933Sadam while (*cp && *cp != quote) 143311933Sadam cp++; 143411933Sadam else 143511933Sadam while (*cp && *cp != ' ' && *cp != '\t') 143611933Sadam cp++; 14371553Srgrimes if (*cp != '\0') 14381553Srgrimes *cp++ = '\0'; 14391553Srgrimes *cpp = cp; 14401553Srgrimes return (start); 14411553Srgrimes} 14421553Srgrimes 14431553Srgrimeschar * 14441553Srgrimesnextline(fd) 14451553Srgrimes FILE *fd; 14461553Srgrimes{ 14471553Srgrimes char *cp; 14481553Srgrimes 14491553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 14501553Srgrimes return ((char *)0); 14511553Srgrimes cp = strchr(line, '\n'); 14521553Srgrimes if (cp) 14531553Srgrimes *cp = '\0'; 14541553Srgrimes return (line); 14551553Srgrimes} 14561553Srgrimes 14571553Srgrimeschar * 14581553Srgrimesnewstr(cp) 14591553Srgrimes char *cp; 14601553Srgrimes{ 146119617Sjulian if ((cp = strdup(cp ? cp : ""))) 14621553Srgrimes return (cp); 14631553Srgrimes syslog(LOG_ERR, "strdup: %m"); 146419617Sjulian exit(EX_OSERR); 14651553Srgrimes} 14661553Srgrimes 146713142Speter#ifdef OLD_SETPROCTITLE 14681553Srgrimesvoid 146913142Speterinetd_setproctitle(a, s) 14701553Srgrimes char *a; 14711553Srgrimes int s; 14721553Srgrimes{ 14731553Srgrimes int size; 14741553Srgrimes char *cp; 14751553Srgrimes struct sockaddr_in sin; 14761553Srgrimes char buf[80]; 14771553Srgrimes 14781553Srgrimes cp = Argv[0]; 14791553Srgrimes size = sizeof(sin); 14801553Srgrimes if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 14818857Srgrimes (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 14821553Srgrimes else 14838857Srgrimes (void) sprintf(buf, "-%s", a); 14841553Srgrimes strncpy(cp, buf, LastArg - cp); 14851553Srgrimes cp += strlen(cp); 14861553Srgrimes while (cp < LastArg) 14871553Srgrimes *cp++ = ' '; 14881553Srgrimes} 148913142Speter#else 149013142Spetervoid 149113142Speterinetd_setproctitle(a, s) 149213142Speter char *a; 149313142Speter int s; 149413142Speter{ 149513142Speter int size; 149613142Speter struct sockaddr_in sin; 149713142Speter char buf[80]; 14981553Srgrimes 149913142Speter size = sizeof(sin); 150013142Speter if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 150113142Speter (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 150213142Speter else 150313142Speter (void) sprintf(buf, "%s", a); 150413142Speter setproctitle("%s", buf); 150513142Speter} 150613142Speter#endif 150713142Speter 150813142Speter 15091553Srgrimes/* 15101553Srgrimes * Internet services provided internally by inetd: 15111553Srgrimes */ 15121553Srgrimes 15135182Swollmanint check_loop(sin, sep) 15145182Swollman struct sockaddr_in *sin; 15155182Swollman struct servtab *sep; 15165182Swollman{ 15175182Swollman struct servtab *se2; 15185182Swollman 15195182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 15205182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 15215182Swollman continue; 15225182Swollman 15235182Swollman if (sin->sin_port == se2->se_ctrladdr.sin_port) { 15245182Swollman syslog(LOG_WARNING, 15255182Swollman "%s/%s:%s/%s loop request REFUSED from %s", 15268857Srgrimes sep->se_service, sep->se_proto, 15275182Swollman se2->se_service, se2->se_proto, 15285182Swollman inet_ntoa(sin->sin_addr)); 15295182Swollman return 1; 15305182Swollman } 15315182Swollman } 15325182Swollman return 0; 15335182Swollman} 15345182Swollman 15351553Srgrimes/* 15361553Srgrimes * print_service: 15371553Srgrimes * Dump relevant information to stderr 15381553Srgrimes */ 15391553Srgrimesvoid 15401553Srgrimesprint_service(action, sep) 15411553Srgrimes char *action; 15421553Srgrimes struct servtab *sep; 15431553Srgrimes{ 154419617Sjulian fprintf(stderr, 154530792Sache#ifdef LOGIN_CAP 154638380Sjb "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n", 154730792Sache#else 154838380Sjb "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n", 154930792Sache#endif 155019617Sjulian action, sep->se_service, sep->se_proto, 155130807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 155230792Sache#ifdef LOGIN_CAP 155330792Sache sep->se_class, 155430792Sache#endif 155538417Sjb (void *) sep->se_bi, sep->se_server); 15561553Srgrimes} 15571553Srgrimes 155830847Sdima#define CPMHSIZE 256 155930847Sdima#define CPMHMASK (CPMHSIZE-1) 156030847Sdima#define CHTGRAN 10 156130847Sdima#define CHTSIZE 6 156230847Sdima 156330847Sdimatypedef struct CTime { 156430847Sdima unsigned long ct_Ticks; 156530847Sdima int ct_Count; 156630847Sdima} CTime; 156730847Sdima 156830847Sdimatypedef struct CHash { 156930847Sdima struct in_addr ch_Addr; 157030847Sdima time_t ch_LTime; 157130847Sdima char *ch_Service; 157230847Sdima CTime ch_Times[CHTSIZE]; 157330847Sdima} CHash; 157430847Sdima 157530847SdimaCHash CHashAry[CPMHSIZE]; 157630847Sdima 157730847Sdimaint 157830847Sdimacpmip(sep, ctrl) 157930847Sdima struct servtab *sep; 158030847Sdima int ctrl; 158130847Sdima{ 158230847Sdima struct sockaddr_in rsin; 158330847Sdima int rsinLen = sizeof(rsin); 158430847Sdima int r = 0; 158530847Sdima 158630847Sdima /* 158730847Sdima * If getpeername() fails, just let it through (if logging is 158830847Sdima * enabled the condition is caught elsewhere) 158930847Sdima */ 159030847Sdima 159130847Sdima if (sep->se_maxcpm > 0 && 159230847Sdima getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) { 159330847Sdima time_t t = time(NULL); 159430847Sdima int hv = 0xABC3D20F; 159530847Sdima int i; 159630847Sdima int cnt = 0; 159730847Sdima CHash *chBest = NULL; 159830847Sdima unsigned int ticks = t / CHTGRAN; 159930847Sdima 160030847Sdima { 160130847Sdima char *p; 160230847Sdima int i; 160330847Sdima 160430847Sdima for (i = 0, p = (char *)&rsin.sin_addr; 160530847Sdima i < sizeof(rsin.sin_addr); 160630847Sdima ++i, ++p) { 160730847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 160830847Sdima } 160930847Sdima hv = (hv ^ (hv >> 16)); 161030847Sdima } 161130847Sdima for (i = 0; i < 5; ++i) { 161230847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 161330847Sdima 161430847Sdima if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr && 161530847Sdima ch->ch_Service && strcmp(sep->se_service, 161630847Sdima ch->ch_Service) == 0) { 161730847Sdima chBest = ch; 161830847Sdima break; 161930847Sdima } 162030847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 162130847Sdima ch->ch_LTime < chBest->ch_LTime) { 162230847Sdima chBest = ch; 162330847Sdima } 162430847Sdima } 162530847Sdima if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr || 162630847Sdima chBest->ch_Service == NULL || 162730847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 162830847Sdima chBest->ch_Addr = rsin.sin_addr; 162930847Sdima if (chBest->ch_Service) 163030847Sdima free(chBest->ch_Service); 163130847Sdima chBest->ch_Service = strdup(sep->se_service); 163230847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 163330847Sdima } 163430847Sdima chBest->ch_LTime = t; 163530847Sdima { 163630847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 163730847Sdima if (ct->ct_Ticks != ticks) { 163830847Sdima ct->ct_Ticks = ticks; 163930847Sdima ct->ct_Count = 0; 164030847Sdima } 164130847Sdima ++ct->ct_Count; 164230847Sdima } 164330847Sdima for (i = 0; i < CHTSIZE; ++i) { 164430847Sdima CTime *ct = &chBest->ch_Times[i]; 164530847Sdima if (ct->ct_Ticks <= ticks && 164630847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 164730847Sdima cnt += ct->ct_Count; 164830847Sdima } 164930847Sdima } 165030847Sdima if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 165130847Sdima r = -1; 165230847Sdima syslog(LOG_ERR, 165333794Spst "%s from %s exceeded counts/min (limit %d/min)", 165433794Spst sep->se_service, inet_ntoa(rsin.sin_addr), 165533794Spst sep->se_maxcpm); 165630847Sdima } 165730847Sdima } 165830847Sdima return(r); 165930847Sdima} 1660