inetd.c revision 42122
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[] = 4542122Sdes "$Id: inetd.c,v 1.41 1998/11/04 19:39:46 phk 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/stat.h> 1081553Srgrimes#include <sys/ioctl.h> 1091553Srgrimes#include <sys/socket.h> 1101553Srgrimes#include <sys/wait.h> 1111553Srgrimes#include <sys/time.h> 1121553Srgrimes#include <sys/resource.h> 1131553Srgrimes 1141553Srgrimes#include <netinet/in.h> 11536042Sguido#include <netinet/tcp.h> 1161553Srgrimes#include <arpa/inet.h> 1172657Scsgr#include <rpc/rpc.h> 11819617Sjulian#include <rpc/pmap_clnt.h> 1191553Srgrimes 1201553Srgrimes#include <errno.h> 12129602Scharnier#include <err.h> 1221553Srgrimes#include <fcntl.h> 12330807Sache#include <grp.h> 1241553Srgrimes#include <netdb.h> 1251553Srgrimes#include <pwd.h> 1261553Srgrimes#include <signal.h> 1271553Srgrimes#include <stdio.h> 1281553Srgrimes#include <stdlib.h> 1291553Srgrimes#include <string.h> 1301553Srgrimes#include <syslog.h> 1311553Srgrimes#include <unistd.h> 13213142Speter#include <libutil.h> 13319617Sjulian#include <sysexits.h> 1341553Srgrimes 13521640Speter#ifdef LOGIN_CAP 13621640Speter#include <login_cap.h> 13730792Sache 13830792Sache/* see init.c */ 13930792Sache#define RESOURCE_RC "daemon" 14030792Sache 14121640Speter#endif 14221640Speter 1431553Srgrimes#include "pathnames.h" 1441553Srgrimes 14533794Spst#ifndef MAXCHILD 14633794Spst#define MAXCHILD -1 /* maximum number of this service 14733794Spst < 0 = no limit */ 14833794Spst#endif 14933794Spst 15033794Spst#ifndef MAXCPM 15133794Spst#define MAXCPM -1 /* rate limit invocations from a 15233794Spst single remote address, 15333794Spst < 0 = no limit */ 15433794Spst#endif 15533794Spst 1562659Scsgr#define TOOMANY 256 /* don't start more than TOOMANY */ 1571553Srgrimes#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 1581553Srgrimes#define RETRYTIME (60*10) /* retry after bind or server fail */ 15919618Sjulian#define MAX_MAXCHLD 32767 /* max allowable max children */ 1601553Srgrimes 1611553Srgrimes#define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 1621553Srgrimes 1631553Srgrimesint debug = 0; 1642659Scsgrint log = 0; 1651553Srgrimesint nsock, maxsock; 1661553Srgrimesfd_set allsock; 1671553Srgrimesint options; 1681553Srgrimesint timingout; 1691553Srgrimesint toomany = TOOMANY; 17033794Spstint maxchild = MAXCPM; 17133794Spstint maxcpm = MAXCHILD; 1721553Srgrimesstruct servent *sp; 1732657Scsgrstruct rpcent *rpc; 17417482Sjulianstruct in_addr bind_address; 17542122Sdesint signalpipe[2]; 1761553Srgrimes 1771553Srgrimesstruct servtab { 1781553Srgrimes char *se_service; /* name of service */ 1791553Srgrimes int se_socktype; /* type of socket to use */ 1801553Srgrimes char *se_proto; /* protocol used */ 18130847Sdima int se_maxchild; /* max number of children */ 18230847Sdima int se_maxcpm; /* max connects per IP per minute */ 18330847Sdima int se_numchild; /* current number of children */ 18419618Sjulian pid_t *se_pids; /* array of child pids */ 1851553Srgrimes char *se_user; /* user name to run as */ 18630807Sache char *se_group; /* group name to run as */ 18730792Sache#ifdef LOGIN_CAP 18830792Sache char *se_class; /* login class name to run with */ 18930792Sache#endif 1901553Srgrimes struct biltin *se_bi; /* if built-in, description */ 1911553Srgrimes char *se_server; /* server program */ 1921553Srgrimes#define MAXARGV 20 1931553Srgrimes char *se_argv[MAXARGV+1]; /* program arguments */ 1941553Srgrimes int se_fd; /* open descriptor */ 1951553Srgrimes struct sockaddr_in se_ctrladdr;/* bound address */ 19619618Sjulian u_char se_type; /* type: normal, mux, or mux+ */ 19719618Sjulian u_char se_checked; /* looked at during merge */ 19819618Sjulian u_char se_accept; /* i.e., wait/nowait mode */ 19919618Sjulian u_char se_rpc; /* ==1 if RPC service */ 2002657Scsgr int se_rpc_prog; /* RPC program number */ 2012657Scsgr u_int se_rpc_lowvers; /* RPC low version */ 2022657Scsgr u_int se_rpc_highvers; /* RPC high version */ 2031553Srgrimes int se_count; /* number started since se_time */ 2041553Srgrimes struct timeval se_time; /* start of se_count */ 2051553Srgrimes struct servtab *se_next; 2061553Srgrimes} *servtab; 2071553Srgrimes 2081553Srgrimes#define NORM_TYPE 0 2091553Srgrimes#define MUX_TYPE 1 2101553Srgrimes#define MUXPLUS_TYPE 2 21136042Sguido#define TTCP_TYPE 3 2121553Srgrimes#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 2131553Srgrimes ((sep)->se_type == MUXPLUS_TYPE)) 2141553Srgrimes#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 21536042Sguido#define ISTTCP(sep) ((sep)->se_type == TTCP_TYPE) 2161553Srgrimes 2171553Srgrimes 2181553Srgrimesvoid chargen_dg __P((int, struct servtab *)); 2191553Srgrimesvoid chargen_stream __P((int, struct servtab *)); 2201553Srgrimesvoid close_sep __P((struct servtab *)); 22142122Sdesvoid flag_signal __P((char)); 22242122Sdesvoid flag_config __P((int)); 22342122Sdesvoid config __P((void)); 2241553Srgrimesvoid daytime_dg __P((int, struct servtab *)); 2251553Srgrimesvoid daytime_stream __P((int, struct servtab *)); 2261553Srgrimesvoid discard_dg __P((int, struct servtab *)); 2271553Srgrimesvoid discard_stream __P((int, struct servtab *)); 2281553Srgrimesvoid echo_dg __P((int, struct servtab *)); 2291553Srgrimesvoid echo_stream __P((int, struct servtab *)); 2301553Srgrimesvoid endconfig __P((void)); 2311553Srgrimesstruct servtab *enter __P((struct servtab *)); 2321553Srgrimesvoid freeconfig __P((struct servtab *)); 2331553Srgrimesstruct servtab *getconfigent __P((void)); 23440910Sphkvoid ident_stream __P((int, struct servtab *)); 2351553Srgrimesvoid machtime_dg __P((int, struct servtab *)); 2361553Srgrimesvoid machtime_stream __P((int, struct servtab *)); 2371553Srgrimeschar *newstr __P((char *)); 2381553Srgrimeschar *nextline __P((FILE *)); 2391553Srgrimesvoid print_service __P((char *, struct servtab *)); 24019618Sjulianvoid addchild __P((struct servtab *, int)); 24142122Sdesvoid flag_reapchild __P((int)); 24242122Sdesvoid reapchild __P((void)); 24319618Sjulianvoid enable __P((struct servtab *)); 24419618Sjulianvoid disable __P((struct servtab *)); 24542122Sdesvoid flag_retry __P((int)); 24642122Sdesvoid retry __P((void)); 2471553Srgrimesint setconfig __P((void)); 2481553Srgrimesvoid setup __P((struct servtab *)); 2491553Srgrimeschar *sskip __P((char **)); 2501553Srgrimeschar *skip __P((char **)); 2511553Srgrimesstruct servtab *tcpmux __P((int)); 25230847Sdimaint cpmip __P((struct servtab *, int)); 2531553Srgrimes 2542657Scsgrvoid unregisterrpc __P((register struct servtab *sep)); 2552657Scsgr 2561553Srgrimesstruct biltin { 2571553Srgrimes char *bi_service; /* internally provided service name */ 2581553Srgrimes int bi_socktype; /* type of socket supported */ 2591553Srgrimes short bi_fork; /* 1 if should fork before call */ 26030847Sdima int bi_maxchild; /* max number of children (default) */ 2611553Srgrimes void (*bi_fn)(); /* function which performs it */ 2621553Srgrimes} biltins[] = { 2631553Srgrimes /* Echo received data */ 2641553Srgrimes { "echo", SOCK_STREAM, 1, 0, echo_stream }, 2651553Srgrimes { "echo", SOCK_DGRAM, 0, 0, echo_dg }, 2661553Srgrimes 2671553Srgrimes /* Internet /dev/null */ 2681553Srgrimes { "discard", SOCK_STREAM, 1, 0, discard_stream }, 2691553Srgrimes { "discard", SOCK_DGRAM, 0, 0, discard_dg }, 2701553Srgrimes 2711553Srgrimes /* Return 32 bit time since 1970 */ 2721553Srgrimes { "time", SOCK_STREAM, 0, 0, machtime_stream }, 2731553Srgrimes { "time", SOCK_DGRAM, 0, 0, machtime_dg }, 2741553Srgrimes 2751553Srgrimes /* Return human-readable time */ 2761553Srgrimes { "daytime", SOCK_STREAM, 0, 0, daytime_stream }, 2771553Srgrimes { "daytime", SOCK_DGRAM, 0, 0, daytime_dg }, 2781553Srgrimes 2791553Srgrimes /* Familiar character generator */ 2801553Srgrimes { "chargen", SOCK_STREAM, 1, 0, chargen_stream }, 2811553Srgrimes { "chargen", SOCK_DGRAM, 0, 0, chargen_dg }, 2821553Srgrimes 2831553Srgrimes { "tcpmux", SOCK_STREAM, 1, 0, (void (*)())tcpmux }, 2841553Srgrimes 28540910Sphk { "ident", SOCK_STREAM, 1, 0, ident_stream }, 28640910Sphk 2871553Srgrimes { NULL } 2881553Srgrimes}; 2891553Srgrimes 2901553Srgrimes#define NUMINT (sizeof(intab) / sizeof(struct inent)) 2911553Srgrimeschar *CONFIG = _PATH_INETDCONF; 29217482Sjulianchar *pid_file = _PATH_INETDPID; 29313142Speter 29413142Speter#ifdef OLD_SETPROCTITLE 2951553Srgrimeschar **Argv; 2961553Srgrimeschar *LastArg; 29713142Speter#endif 2981553Srgrimes 2991553Srgrimesint 30033794Spstgetvalue(arg, value, whine) 30133794Spst char *arg, *whine; 30233794Spst int *value; 30333794Spst{ 30433794Spst int tmp; 30533794Spst char *p; 30633794Spst 30733794Spst tmp = strtol(arg, &p, 0); 30833794Spst if (tmp < 1 || *p) { 30933794Spst syslog(LOG_ERR, whine, arg); 31033794Spst return 1; /* failure */ 31133794Spst } 31233794Spst *value = tmp; 31333794Spst return 0; /* success */ 31433794Spst} 31533794Spst 31633794Spstint 3171553Srgrimesmain(argc, argv, envp) 3181553Srgrimes int argc; 3191553Srgrimes char *argv[], *envp[]; 3201553Srgrimes{ 3211553Srgrimes struct servtab *sep; 3221553Srgrimes struct passwd *pwd; 32330807Sache struct group *grp; 32435848Sguido struct sigaction sa, sapipe; 3251553Srgrimes int tmpint, ch, dofork; 3261553Srgrimes pid_t pid; 3271553Srgrimes char buf[50]; 3282659Scsgr struct sockaddr_in peer; 3292659Scsgr int i; 33021640Speter#ifdef LOGIN_CAP 33121640Speter login_cap_t *lc = NULL; 33221640Speter#endif 3331553Srgrimes 33413142Speter 33513142Speter#ifdef OLD_SETPROCTITLE 3361553Srgrimes Argv = argv; 3371553Srgrimes if (envp == 0 || *envp == 0) 3381553Srgrimes envp = argv; 3391553Srgrimes while (*envp) 3401553Srgrimes envp++; 3411553Srgrimes LastArg = envp[-1] + strlen(envp[-1]); 34213142Speter#endif 3431553Srgrimes 3441553Srgrimes openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 3451553Srgrimes 34617482Sjulian bind_address.s_addr = htonl(INADDR_ANY); 34733794Spst while ((ch = getopt(argc, argv, "dlR:a:c:C:p:")) != -1) 3481553Srgrimes switch(ch) { 3491553Srgrimes case 'd': 3501553Srgrimes debug = 1; 3511553Srgrimes options |= SO_DEBUG; 3521553Srgrimes break; 3532659Scsgr case 'l': 3542659Scsgr log = 1; 3552659Scsgr break; 35633794Spst case 'R': 35733794Spst getvalue(optarg, &toomany, 35833794Spst "-R %s: bad value for service invocation rate"); 3591553Srgrimes break; 36033794Spst case 'c': 36133794Spst getvalue(optarg, &maxchild, 36233794Spst "-c %s: bad value for maximum children"); 36333794Spst break; 36433794Spst case 'C': 36533794Spst getvalue(optarg, &maxcpm, 36633794Spst "-C %s: bad value for maximum children/minute"); 36733794Spst break; 36817482Sjulian case 'a': 36917482Sjulian if (!inet_aton(optarg, &bind_address)) { 37017482Sjulian syslog(LOG_ERR, 37117482Sjulian "-a %s: invalid IP address", optarg); 37219617Sjulian exit(EX_USAGE); 37317482Sjulian } 37417482Sjulian break; 37517482Sjulian case 'p': 37617482Sjulian pid_file = optarg; 37717482Sjulian break; 3781553Srgrimes case '?': 3791553Srgrimes default: 3801553Srgrimes syslog(LOG_ERR, 38117482Sjulian "usage: inetd [-dl] [-a address] [-R rate]" 38233794Spst " [-c maximum] [-C rate]" 38317482Sjulian " [-p pidfile] [conf-file]"); 38419617Sjulian exit(EX_USAGE); 3851553Srgrimes } 3861553Srgrimes argc -= optind; 3871553Srgrimes argv += optind; 3881553Srgrimes 3891553Srgrimes if (argc > 0) 3901553Srgrimes CONFIG = argv[0]; 3911553Srgrimes if (debug == 0) { 39211447Swollman FILE *fp; 39312024Speter if (daemon(0, 0) < 0) { 39412024Speter syslog(LOG_WARNING, "daemon(0,0) failed: %m"); 39512024Speter } 39612024Speter /* 39712024Speter * In case somebody has started inetd manually, we need to 39812024Speter * clear the logname, so that old servers run as root do not 39912024Speter * get the user's logname.. 40012024Speter */ 40112024Speter if (setlogin("") < 0) { 40212024Speter syslog(LOG_WARNING, "cannot clear logname: %m"); 40312024Speter /* no big deal if it fails.. */ 40412024Speter } 40511447Swollman pid = getpid(); 40617482Sjulian fp = fopen(pid_file, "w"); 40711447Swollman if (fp) { 40811447Swollman fprintf(fp, "%ld\n", (long)pid); 40911447Swollman fclose(fp); 41011447Swollman } else { 41117482Sjulian syslog(LOG_WARNING, "%s: %m", pid_file); 41211447Swollman } 4131553Srgrimes } 41435948Sbde sa.sa_flags = 0; 41535948Sbde sigemptyset(&sa.sa_mask); 41635948Sbde sigaddset(&sa.sa_mask, SIGALRM); 41735948Sbde sigaddset(&sa.sa_mask, SIGCHLD); 41835948Sbde sigaddset(&sa.sa_mask, SIGHUP); 41942122Sdes sa.sa_handler = flag_retry; 42035848Sguido sigaction(SIGALRM, &sa, (struct sigaction *)0); 42142122Sdes config(); 42242122Sdes sa.sa_handler = flag_config; 42335848Sguido sigaction(SIGHUP, &sa, (struct sigaction *)0); 42442122Sdes sa.sa_handler = flag_reapchild; 42535848Sguido sigaction(SIGCHLD, &sa, (struct sigaction *)0); 42635848Sguido sa.sa_handler = SIG_IGN; 42735948Sbde sigaction(SIGPIPE, &sa, &sapipe); 4281553Srgrimes 4291553Srgrimes { 4301553Srgrimes /* space for daemons to overwrite environment for ps */ 4311553Srgrimes#define DUMMYSIZE 100 4321553Srgrimes char dummy[DUMMYSIZE]; 4331553Srgrimes 43419298Salex (void)memset(dummy, 'x', DUMMYSIZE - 1); 4351553Srgrimes dummy[DUMMYSIZE - 1] = '\0'; 4361553Srgrimes (void)setenv("inetd_dummy", dummy, 1); 4371553Srgrimes } 4381553Srgrimes 43942122Sdes if (pipe(signalpipe) != 0) 44042122Sdes { 44142122Sdes syslog(LOG_ERR, "pipe: %%m"); 44242122Sdes exit(EX_OSERR); 44342122Sdes } 44442122Sdes FD_SET(signalpipe[0], &allsock); 44542122Sdes if (signalpipe[0]>maxsock) maxsock = signalpipe[0]; 44641685Sdillon 4471553Srgrimes for (;;) { 4481553Srgrimes int n, ctrl; 4491553Srgrimes fd_set readable; 4501553Srgrimes 4511553Srgrimes if (nsock == 0) { 45242122Sdes (void) sigblock(SIGBLOCK); 4531553Srgrimes while (nsock == 0) 4541553Srgrimes sigpause(0L); 45542122Sdes (void) sigsetmask(0L); 4561553Srgrimes } 4571553Srgrimes readable = allsock; 45842122Sdes if ((n = select(maxsock + 1, &readable, (fd_set *)0, 45942122Sdes (fd_set *)0, (struct timeval *)0)) <= 0) { 46042122Sdes if (n < 0 && errno != EINTR) { 4611553Srgrimes syslog(LOG_WARNING, "select: %m"); 46228907Simp sleep(1); 46328907Simp } 4641553Srgrimes continue; 4651553Srgrimes } 46642122Sdes /* handle any queued signal flags */ 46742122Sdes if (FD_ISSET(signalpipe[0], &readable)) 46842122Sdes { 46942122Sdes int n; 47042122Sdes if (ioctl(signalpipe[0], FIONREAD, &n) == 0) 47142122Sdes { 47242122Sdes while (--n >= 0) 47342122Sdes { 47442122Sdes char c; 47542122Sdes if (read(signalpipe[0], &c, 1) == 1) 47642122Sdes { 47742122Sdes if (debug) warnx("Handling signal flag %c", c); 47842122Sdes switch(c) 47942122Sdes { 48042122Sdes case 'A': /* sigalrm */ 48142122Sdes retry(); break; 48242122Sdes case 'C': /* sigchld */ 48342122Sdes reapchild(); break; 48442122Sdes case 'H': /* sighup */ 48542122Sdes config(); break; 48642122Sdes } 48742122Sdes } 48842122Sdes else 48942122Sdes { 49042122Sdes syslog(LOG_ERR, "read: %m"); 49142122Sdes exit(EX_OSERR); 49242122Sdes } 49342122Sdes } 49442122Sdes } 49542122Sdes else 49642122Sdes { 49742122Sdes syslog(LOG_ERR, "ioctl: %m"); 49842122Sdes exit(EX_OSERR); 49942122Sdes } 50042122Sdes } 5011553Srgrimes for (sep = servtab; n && sep; sep = sep->se_next) 5021553Srgrimes if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 5031553Srgrimes n--; 5041553Srgrimes if (debug) 50529602Scharnier warnx("someone wants %s", sep->se_service); 50619618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) { 5071553Srgrimes ctrl = accept(sep->se_fd, (struct sockaddr *)0, 5081553Srgrimes (int *)0); 5091553Srgrimes if (debug) 51029602Scharnier warnx("accept, ctrl %d", ctrl); 5111553Srgrimes if (ctrl < 0) { 5121553Srgrimes if (errno != EINTR) 5131553Srgrimes syslog(LOG_WARNING, 5141553Srgrimes "accept (for %s): %m", 51537844Sphk sep->se_service); 51637816Sphk if (sep->se_accept && 51737816Sphk sep->se_socktype == SOCK_STREAM) 51837816Sphk close(ctrl); 5191553Srgrimes continue; 5201553Srgrimes } 52130847Sdima if (cpmip(sep, ctrl) < 0) { 52230847Sdima close(ctrl); 52330847Sdima continue; 52430847Sdima } 52519617Sjulian if (log) { 5262659Scsgr i = sizeof peer; 52730847Sdima if (getpeername(ctrl, (struct sockaddr *) 5282659Scsgr &peer, &i)) { 5292659Scsgr syslog(LOG_WARNING, 5302659Scsgr "getpeername(for %s): %m", 5312659Scsgr sep->se_service); 53230847Sdima close(ctrl); 5332659Scsgr continue; 5342659Scsgr } 5352659Scsgr syslog(LOG_INFO,"%s from %s", 5362659Scsgr sep->se_service, 5372659Scsgr inet_ntoa(peer.sin_addr)); 5382659Scsgr } 5391553Srgrimes } else 5401553Srgrimes ctrl = sep->se_fd; 54142122Sdes (void) sigblock(SIGBLOCK); 5421553Srgrimes pid = 0; 5431553Srgrimes dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 5441553Srgrimes if (dofork) { 5451553Srgrimes if (sep->se_count++ == 0) 54637856Sache (void)gettimeofday(&sep->se_time, (struct timezone *)NULL); 5471553Srgrimes else if (sep->se_count >= toomany) { 5481553Srgrimes struct timeval now; 5491553Srgrimes 55037856Sache (void)gettimeofday(&now, (struct timezone *)NULL); 5511553Srgrimes if (now.tv_sec - sep->se_time.tv_sec > 5521553Srgrimes CNT_INTVL) { 5531553Srgrimes sep->se_time = now; 5541553Srgrimes sep->se_count = 1; 5551553Srgrimes } else { 5561553Srgrimes syslog(LOG_ERR, 5571553Srgrimes "%s/%s server failing (looping), service terminated", 5581553Srgrimes sep->se_service, sep->se_proto); 5591553Srgrimes close_sep(sep); 56042122Sdes sigsetmask(0L); 5611553Srgrimes if (!timingout) { 5621553Srgrimes timingout = 1; 5631553Srgrimes alarm(RETRYTIME); 5641553Srgrimes } 5651553Srgrimes continue; 5661553Srgrimes } 5671553Srgrimes } 5681553Srgrimes pid = fork(); 5691553Srgrimes } 5701553Srgrimes if (pid < 0) { 5711553Srgrimes syslog(LOG_ERR, "fork: %m"); 57219618Sjulian if (sep->se_accept && 5731553Srgrimes sep->se_socktype == SOCK_STREAM) 5741553Srgrimes close(ctrl); 57542122Sdes sigsetmask(0L); 5761553Srgrimes sleep(1); 5771553Srgrimes continue; 5781553Srgrimes } 57919618Sjulian if (pid) 58019618Sjulian addchild(sep, pid); 58142122Sdes sigsetmask(0L); 5821553Srgrimes if (pid == 0) { 5831553Srgrimes if (dofork) { 5841553Srgrimes if (debug) 58529602Scharnier warnx("+ closing from %d", maxsock); 5861553Srgrimes for (tmpint = maxsock; tmpint > 2; tmpint--) 5871553Srgrimes if (tmpint != ctrl) 58819617Sjulian (void) close(tmpint); 5891553Srgrimes } 59035829Sguido /* 59135829Sguido * Call tcpmux to find the real service to exec. 59235829Sguido */ 59335829Sguido if (sep->se_bi && 59435829Sguido sep->se_bi->bi_fn == (void (*)()) tcpmux) { 59535829Sguido sep = tcpmux(ctrl); 59635829Sguido if (sep == NULL) { 59735829Sguido close(ctrl); 59835829Sguido _exit(0); 59935829Sguido } 60035829Sguido } 60119617Sjulian if (sep->se_bi) { 6021553Srgrimes (*sep->se_bi->bi_fn)(ctrl, sep); 60319617Sjulian /* NOTREACHED */ 60419617Sjulian } else { 6051553Srgrimes if (debug) 60629602Scharnier warnx("%d execl %s", 60729602Scharnier getpid(), sep->se_server); 6081553Srgrimes dup2(ctrl, 0); 6091553Srgrimes close(ctrl); 6101553Srgrimes dup2(0, 1); 6111553Srgrimes dup2(0, 2); 6121553Srgrimes if ((pwd = getpwnam(sep->se_user)) == NULL) { 6131553Srgrimes syslog(LOG_ERR, 6141553Srgrimes "%s/%s: %s: No such user", 6151553Srgrimes sep->se_service, sep->se_proto, 6161553Srgrimes sep->se_user); 6171553Srgrimes if (sep->se_socktype != SOCK_STREAM) 6181553Srgrimes recv(0, buf, sizeof (buf), 0); 61919617Sjulian _exit(EX_NOUSER); 6201553Srgrimes } 62130807Sache grp = NULL; 62230807Sache if ( sep->se_group != NULL 62330807Sache && (grp = getgrnam(sep->se_group)) == NULL 62430807Sache ) { 62530807Sache syslog(LOG_ERR, 62630807Sache "%s/%s: %s: No such group", 62730807Sache sep->se_service, sep->se_proto, 62830807Sache sep->se_group); 62930807Sache if (sep->se_socktype != SOCK_STREAM) 63030807Sache recv(0, buf, sizeof (buf), 0); 63130807Sache _exit(EX_NOUSER); 63230807Sache } 63330807Sache if (grp != NULL) 63430807Sache pwd->pw_gid = grp->gr_gid; 63521640Speter#ifdef LOGIN_CAP 63630792Sache if ((lc = login_getclass(sep->se_class)) == NULL) { 63730792Sache /* error syslogged by getclass */ 63830792Sache syslog(LOG_ERR, 63930792Sache "%s/%s: %s: login class error", 64037850Sache sep->se_service, sep->se_proto, 64137850Sache sep->se_class); 64230792Sache if (sep->se_socktype != SOCK_STREAM) 64330792Sache recv(0, buf, sizeof (buf), 0); 64430792Sache _exit(EX_NOUSER); 64530792Sache } 64621640Speter#endif 64712024Speter if (setsid() < 0) { 64812024Speter syslog(LOG_ERR, 64912024Speter "%s: can't setsid(): %m", 65012024Speter sep->se_service); 65119617Sjulian /* _exit(EX_OSERR); not fatal yet */ 65212024Speter } 65321640Speter#ifdef LOGIN_CAP 65421640Speter if (setusercontext(lc, pwd, pwd->pw_uid, 65521640Speter LOGIN_SETALL) != 0) { 65621640Speter syslog(LOG_ERR, 65721640Speter "%s: can't setusercontext(..%s..): %m", 65821640Speter sep->se_service, sep->se_user); 65921640Speter _exit(EX_OSERR); 66021640Speter } 66121640Speter#else 6621553Srgrimes if (pwd->pw_uid) { 66312024Speter if (setlogin(sep->se_user) < 0) { 66412024Speter syslog(LOG_ERR, 66512024Speter "%s: can't setlogin(%s): %m", 66612024Speter sep->se_service, sep->se_user); 66719617Sjulian /* _exit(EX_OSERR); not yet */ 66812024Speter } 6691553Srgrimes if (setgid(pwd->pw_gid) < 0) { 6701553Srgrimes syslog(LOG_ERR, 6718857Srgrimes "%s: can't set gid %d: %m", 6721553Srgrimes sep->se_service, pwd->pw_gid); 67319617Sjulian _exit(EX_OSERR); 6741553Srgrimes } 6751553Srgrimes (void) initgroups(pwd->pw_name, 6761553Srgrimes pwd->pw_gid); 6771553Srgrimes if (setuid(pwd->pw_uid) < 0) { 6781553Srgrimes syslog(LOG_ERR, 6798857Srgrimes "%s: can't set uid %d: %m", 6801553Srgrimes sep->se_service, pwd->pw_uid); 68119617Sjulian _exit(EX_OSERR); 6821553Srgrimes } 6831553Srgrimes } 68421640Speter#endif 68535948Sbde sigaction(SIGPIPE, &sapipe, 68635948Sbde (struct sigaction *)0); 6871553Srgrimes execv(sep->se_server, sep->se_argv); 6881553Srgrimes if (sep->se_socktype != SOCK_STREAM) 6891553Srgrimes recv(0, buf, sizeof (buf), 0); 6901553Srgrimes syslog(LOG_ERR, 6911553Srgrimes "cannot execute %s: %m", sep->se_server); 69219617Sjulian _exit(EX_OSERR); 6931553Srgrimes } 6941553Srgrimes } 69519618Sjulian if (sep->se_accept && sep->se_socktype == SOCK_STREAM) 6961553Srgrimes close(ctrl); 6971553Srgrimes } 6981553Srgrimes } 6991553Srgrimes} 7001553Srgrimes 70119618Sjulian/* 70242122Sdes * Add a signal flag to the signal flag queue for later handling 70342122Sdes */ 70442122Sdes 70542122Sdesvoid flag_signal(c) 70642122Sdes char c; 70742122Sdes{ 70842122Sdes if (write(signalpipe[1], &c, 1) != 1) 70942122Sdes { 71042122Sdes syslog(LOG_ERR, "write: %m"); 71142122Sdes exit(EX_OSERR); 71242122Sdes } 71342122Sdes} 71442122Sdes 71542122Sdes/* 71619618Sjulian * Record a new child pid for this service. If we've reached the 71719618Sjulian * limit on children, then stop accepting incoming requests. 71819618Sjulian */ 71919618Sjulian 7201553Srgrimesvoid 72119618Sjulianaddchild(struct servtab *sep, pid_t pid) 72219618Sjulian{ 72319618Sjulian#ifdef SANITY_CHECK 72419618Sjulian if (sep->se_numchild >= sep->se_maxchild) { 72519618Sjulian syslog(LOG_ERR, "%s: %d >= %d", 72619618Sjulian __FUNCTION__, sep->se_numchild, sep->se_maxchild); 72719618Sjulian exit(EX_SOFTWARE); 72819618Sjulian } 72919618Sjulian#endif 73019618Sjulian if (sep->se_maxchild == 0) 73119618Sjulian return; 73219618Sjulian sep->se_pids[sep->se_numchild++] = pid; 73319618Sjulian if (sep->se_numchild == sep->se_maxchild) 73419618Sjulian disable(sep); 73519618Sjulian} 73619618Sjulian 73719618Sjulian/* 73819618Sjulian * Some child process has exited. See if it's on somebody's list. 73919618Sjulian */ 74019618Sjulian 74119618Sjulianvoid 74242122Sdesflag_reapchild(signo) 7431553Srgrimes int signo; 7441553Srgrimes{ 74542122Sdes flag_signal('C'); 74642122Sdes} 74742122Sdes 74842122Sdesvoid 74942122Sdesreapchild() 75042122Sdes{ 75119618Sjulian int k, status; 7521553Srgrimes pid_t pid; 7531553Srgrimes struct servtab *sep; 7541553Srgrimes 7551553Srgrimes for (;;) { 7561553Srgrimes pid = wait3(&status, WNOHANG, (struct rusage *)0); 7571553Srgrimes if (pid <= 0) 7581553Srgrimes break; 7591553Srgrimes if (debug) 76029602Scharnier warnx("%d reaped, status %#x", pid, status); 76119618Sjulian for (sep = servtab; sep; sep = sep->se_next) { 76219618Sjulian for (k = 0; k < sep->se_numchild; k++) 76319618Sjulian if (sep->se_pids[k] == pid) 76419618Sjulian break; 76519618Sjulian if (k == sep->se_numchild) 76619618Sjulian continue; 76719618Sjulian if (sep->se_numchild == sep->se_maxchild) 76819618Sjulian enable(sep); 76919618Sjulian sep->se_pids[k] = sep->se_pids[--sep->se_numchild]; 77019618Sjulian if (status) 77119618Sjulian syslog(LOG_WARNING, 77219618Sjulian "%s[%d]: exit status 0x%x", 77319618Sjulian sep->se_server, pid, status); 77419618Sjulian break; 77519618Sjulian } 7761553Srgrimes } 7771553Srgrimes} 7781553Srgrimes 7791553Srgrimesvoid 78042122Sdesflag_config(signo) 7811553Srgrimes int signo; 7821553Srgrimes{ 78342122Sdes flag_signal('H'); 78442122Sdes} 78542122Sdes 78642122Sdesvoid config() 78742122Sdes{ 78819618Sjulian struct servtab *sep, *new, **sepp; 78942122Sdes long omask; 7901553Srgrimes 7911553Srgrimes if (!setconfig()) { 7921553Srgrimes syslog(LOG_ERR, "%s: %m", CONFIG); 7931553Srgrimes return; 7941553Srgrimes } 7951553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 7961553Srgrimes sep->se_checked = 0; 79719618Sjulian while ((new = getconfigent())) { 79830807Sache if (getpwnam(new->se_user) == NULL) { 7991553Srgrimes syslog(LOG_ERR, 8001553Srgrimes "%s/%s: No such user '%s', service ignored", 80119618Sjulian new->se_service, new->se_proto, new->se_user); 8021553Srgrimes continue; 8031553Srgrimes } 80430807Sache if (new->se_group && getgrnam(new->se_group) == NULL) { 80530807Sache syslog(LOG_ERR, 80630807Sache "%s/%s: No such group '%s', service ignored", 80730807Sache new->se_service, new->se_proto, new->se_group); 80830807Sache continue; 80930807Sache } 81030792Sache#ifdef LOGIN_CAP 81130792Sache if (login_getclass(new->se_class) == NULL) { 81230792Sache /* error syslogged by getclass */ 81330792Sache syslog(LOG_ERR, 81437850Sache "%s/%s: %s: login class error, service ignored", 81537850Sache new->se_service, new->se_proto, new->se_class); 81630792Sache continue; 81730792Sache } 81830792Sache#endif 8191553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 82019618Sjulian if (strcmp(sep->se_service, new->se_service) == 0 && 82119618Sjulian strcmp(sep->se_proto, new->se_proto) == 0) 8221553Srgrimes break; 8231553Srgrimes if (sep != 0) { 8241553Srgrimes int i; 8251553Srgrimes 82619618Sjulian#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; } 82742122Sdes omask = sigblock(SIGBLOCK); 82819618Sjulian /* copy over outstanding child pids */ 82919618Sjulian if (sep->se_maxchild && new->se_maxchild) { 83019618Sjulian new->se_numchild = sep->se_numchild; 83119618Sjulian if (new->se_numchild > new->se_maxchild) 83219618Sjulian new->se_numchild = new->se_maxchild; 83319618Sjulian memcpy(new->se_pids, sep->se_pids, 83419618Sjulian new->se_numchild * sizeof(*new->se_pids)); 83519618Sjulian } 83619618Sjulian SWAP(sep->se_pids, new->se_pids); 83719618Sjulian sep->se_maxchild = new->se_maxchild; 83819618Sjulian sep->se_numchild = new->se_numchild; 83930847Sdima sep->se_maxcpm = new->se_maxcpm; 84019618Sjulian /* might need to turn on or off service now */ 84119618Sjulian if (sep->se_fd >= 0) { 84219618Sjulian if (sep->se_maxchild 84319618Sjulian && sep->se_numchild == sep->se_maxchild) { 84419618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 84519618Sjulian disable(sep); 84619618Sjulian } else { 84719618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) 84819618Sjulian enable(sep); 84919618Sjulian } 85019618Sjulian } 85119618Sjulian sep->se_accept = new->se_accept; 85230807Sache SWAP(sep->se_user, new->se_user); 85330807Sache SWAP(sep->se_group, new->se_group); 85430792Sache#ifdef LOGIN_CAP 85530807Sache SWAP(sep->se_class, new->se_class); 85630792Sache#endif 85730807Sache SWAP(sep->se_server, new->se_server); 8581553Srgrimes for (i = 0; i < MAXARGV; i++) 85919618Sjulian SWAP(sep->se_argv[i], new->se_argv[i]); 86042122Sdes sigsetmask(omask); 86119618Sjulian freeconfig(new); 8621553Srgrimes if (debug) 8631553Srgrimes print_service("REDO", sep); 8641553Srgrimes } else { 86519618Sjulian sep = enter(new); 8661553Srgrimes if (debug) 8671553Srgrimes print_service("ADD ", sep); 8681553Srgrimes } 8691553Srgrimes sep->se_checked = 1; 8701553Srgrimes if (ISMUX(sep)) { 8711553Srgrimes sep->se_fd = -1; 8721553Srgrimes continue; 8731553Srgrimes } 8742657Scsgr if (!sep->se_rpc) { 8752657Scsgr sp = getservbyname(sep->se_service, sep->se_proto); 8762657Scsgr if (sp == 0) { 8772657Scsgr syslog(LOG_ERR, "%s/%s: unknown service", 8782657Scsgr sep->se_service, sep->se_proto); 8792657Scsgr sep->se_checked = 0; 8802657Scsgr continue; 8812657Scsgr } 8822657Scsgr if (sp->s_port != sep->se_ctrladdr.sin_port) { 8832657Scsgr sep->se_ctrladdr.sin_family = AF_INET; 88422306Sjulian sep->se_ctrladdr.sin_addr = bind_address; 8852657Scsgr sep->se_ctrladdr.sin_port = sp->s_port; 8862657Scsgr if (sep->se_fd >= 0) 8872657Scsgr close_sep(sep); 8882657Scsgr } 8892657Scsgr } else { 8902657Scsgr rpc = getrpcbyname(sep->se_service); 8912657Scsgr if (rpc == 0) { 8922657Scsgr syslog(LOG_ERR, "%s/%s unknown RPC service.", 8932657Scsgr sep->se_service, sep->se_proto); 8942657Scsgr if (sep->se_fd != -1) 8952657Scsgr (void) close(sep->se_fd); 8962657Scsgr sep->se_fd = -1; 8972657Scsgr continue; 8982657Scsgr } 8992657Scsgr if (rpc->r_number != sep->se_rpc_prog) { 9002657Scsgr if (sep->se_rpc_prog) 9012657Scsgr unregisterrpc(sep); 9022657Scsgr sep->se_rpc_prog = rpc->r_number; 9032657Scsgr if (sep->se_fd != -1) 9042657Scsgr (void) close(sep->se_fd); 9052657Scsgr sep->se_fd = -1; 9062657Scsgr } 9071553Srgrimes } 9081553Srgrimes if (sep->se_fd == -1) 9091553Srgrimes setup(sep); 9101553Srgrimes } 9111553Srgrimes endconfig(); 9121553Srgrimes /* 9131553Srgrimes * Purge anything not looked at above. 9141553Srgrimes */ 91542122Sdes omask = sigblock(SIGBLOCK); 9161553Srgrimes sepp = &servtab; 91719617Sjulian while ((sep = *sepp)) { 9181553Srgrimes if (sep->se_checked) { 9191553Srgrimes sepp = &sep->se_next; 9201553Srgrimes continue; 9211553Srgrimes } 9221553Srgrimes *sepp = sep->se_next; 9231553Srgrimes if (sep->se_fd >= 0) 9241553Srgrimes close_sep(sep); 9251553Srgrimes if (debug) 9261553Srgrimes print_service("FREE", sep); 9272657Scsgr if (sep->se_rpc && sep->se_rpc_prog > 0) 9282657Scsgr unregisterrpc(sep); 9291553Srgrimes freeconfig(sep); 9301553Srgrimes free((char *)sep); 9311553Srgrimes } 93242122Sdes (void) sigsetmask(omask); 9331553Srgrimes} 9341553Srgrimes 9351553Srgrimesvoid 9362657Scsgrunregisterrpc(sep) 9372657Scsgr struct servtab *sep; 9382657Scsgr{ 9392657Scsgr int i; 9402657Scsgr struct servtab *sepp; 94142122Sdes long omask; 9422657Scsgr 94342122Sdes omask = sigblock(SIGBLOCK); 9442657Scsgr for (sepp = servtab; sepp; sepp = sepp->se_next) { 9452657Scsgr if (sepp == sep) 9462657Scsgr continue; 9472657Scsgr if (sep->se_checked == 0 || 9482657Scsgr !sepp->se_rpc || 9492657Scsgr sep->se_rpc_prog != sepp->se_rpc_prog) 9502657Scsgr continue; 9512657Scsgr return; 9522657Scsgr } 9532657Scsgr if (debug) 9542657Scsgr print_service("UNREG", sep); 9552657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) 9562657Scsgr pmap_unset(sep->se_rpc_prog, i); 9572657Scsgr if (sep->se_fd != -1) 9582657Scsgr (void) close(sep->se_fd); 9592657Scsgr sep->se_fd = -1; 96042122Sdes (void) sigsetmask(omask); 9612657Scsgr} 9622657Scsgr 9632657Scsgrvoid 96442122Sdesflag_retry(signo) 9651553Srgrimes int signo; 9661553Srgrimes{ 96742122Sdes flag_signal('A'); 96842122Sdes} 96942122Sdes 97042122Sdesvoid 97142122Sdesretry() 97242122Sdes{ 9731553Srgrimes struct servtab *sep; 9741553Srgrimes 9751553Srgrimes timingout = 0; 9761553Srgrimes for (sep = servtab; sep; sep = sep->se_next) 97719617Sjulian if (sep->se_fd == -1 && !ISMUX(sep)) 9781553Srgrimes setup(sep); 9791553Srgrimes} 9801553Srgrimes 9811553Srgrimesvoid 9821553Srgrimessetup(sep) 9831553Srgrimes struct servtab *sep; 9841553Srgrimes{ 9851553Srgrimes int on = 1; 9861553Srgrimes 9871553Srgrimes if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 9881553Srgrimes if (debug) 98929602Scharnier warn("socket failed on %s/%s", 99029602Scharnier sep->se_service, sep->se_proto); 9911553Srgrimes syslog(LOG_ERR, "%s/%s: socket: %m", 9921553Srgrimes sep->se_service, sep->se_proto); 9931553Srgrimes return; 9941553Srgrimes } 9951553Srgrimes#define turnon(fd, opt) \ 9961553Srgrimessetsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 9971553Srgrimes if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 9981553Srgrimes turnon(sep->se_fd, SO_DEBUG) < 0) 9991553Srgrimes syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 10001553Srgrimes if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 10011553Srgrimes syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 100225253Swollman#ifdef SO_PRIVSTATE 100313956Swollman if (turnon(sep->se_fd, SO_PRIVSTATE) < 0) 100413956Swollman syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m"); 100525253Swollman#endif 10061553Srgrimes#undef turnon 100736042Sguido if (sep->se_type == TTCP_TYPE) 100836042Sguido if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH, 100936042Sguido (char *)&on, sizeof (on)) < 0) 101036042Sguido syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m"); 10111553Srgrimes if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 10121553Srgrimes sizeof (sep->se_ctrladdr)) < 0) { 10131553Srgrimes if (debug) 101429602Scharnier warn("bind failed on %s/%s", 101529602Scharnier sep->se_service, sep->se_proto); 10161553Srgrimes syslog(LOG_ERR, "%s/%s: bind: %m", 10171553Srgrimes sep->se_service, sep->se_proto); 10181553Srgrimes (void) close(sep->se_fd); 10191553Srgrimes sep->se_fd = -1; 10201553Srgrimes if (!timingout) { 10211553Srgrimes timingout = 1; 10221553Srgrimes alarm(RETRYTIME); 10231553Srgrimes } 10241553Srgrimes return; 10251553Srgrimes } 10262657Scsgr if (sep->se_rpc) { 10272657Scsgr int i, len = sizeof(struct sockaddr); 10282657Scsgr 10298857Srgrimes if (getsockname(sep->se_fd, 10302657Scsgr (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){ 10312657Scsgr syslog(LOG_ERR, "%s/%s: getsockname: %m", 10322657Scsgr sep->se_service, sep->se_proto); 10332657Scsgr (void) close(sep->se_fd); 10342657Scsgr sep->se_fd = -1; 10358857Srgrimes return; 10362657Scsgr } 10372657Scsgr if (debug) 10382657Scsgr print_service("REG ", sep); 10392657Scsgr for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) { 10402657Scsgr pmap_unset(sep->se_rpc_prog, i); 10412657Scsgr pmap_set(sep->se_rpc_prog, i, 10422657Scsgr (sep->se_socktype == SOCK_DGRAM) 10432657Scsgr ? IPPROTO_UDP : IPPROTO_TCP, 10442657Scsgr ntohs(sep->se_ctrladdr.sin_port)); 10452657Scsgr } 10468857Srgrimes 10472657Scsgr } 10481553Srgrimes if (sep->se_socktype == SOCK_STREAM) 104917197Sdg listen(sep->se_fd, 64); 105019618Sjulian enable(sep); 10511553Srgrimes if (debug) { 105229602Scharnier warnx("registered %s on %d", 10531553Srgrimes sep->se_server, sep->se_fd); 10541553Srgrimes } 10551553Srgrimes} 10561553Srgrimes 10571553Srgrimes/* 10581553Srgrimes * Finish with a service and its socket. 10591553Srgrimes */ 10601553Srgrimesvoid 10611553Srgrimesclose_sep(sep) 10621553Srgrimes struct servtab *sep; 10631553Srgrimes{ 10641553Srgrimes if (sep->se_fd >= 0) { 106519618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) 106619618Sjulian disable(sep); 10671553Srgrimes (void) close(sep->se_fd); 10681553Srgrimes sep->se_fd = -1; 10691553Srgrimes } 10701553Srgrimes sep->se_count = 0; 107119618Sjulian sep->se_numchild = 0; /* forget about any existing children */ 10721553Srgrimes} 10731553Srgrimes 10741553Srgrimesstruct servtab * 10751553Srgrimesenter(cp) 10761553Srgrimes struct servtab *cp; 10771553Srgrimes{ 10781553Srgrimes struct servtab *sep; 107942122Sdes long omask; 10801553Srgrimes 10811553Srgrimes sep = (struct servtab *)malloc(sizeof (*sep)); 10821553Srgrimes if (sep == (struct servtab *)0) { 10831553Srgrimes syslog(LOG_ERR, "Out of memory."); 108419617Sjulian exit(EX_OSERR); 10851553Srgrimes } 10861553Srgrimes *sep = *cp; 10871553Srgrimes sep->se_fd = -1; 108842122Sdes omask = sigblock(SIGBLOCK); 10891553Srgrimes sep->se_next = servtab; 10901553Srgrimes servtab = sep; 109142122Sdes sigsetmask(omask); 10921553Srgrimes return (sep); 10931553Srgrimes} 10941553Srgrimes 109519618Sjulianvoid 109619618Sjulianenable(struct servtab *sep) 109719618Sjulian{ 109819618Sjulian if (debug) 109929602Scharnier warnx( 110019618Sjulian "enabling %s, fd %d", sep->se_service, sep->se_fd); 110119618Sjulian#ifdef SANITY_CHECK 110219618Sjulian if (sep->se_fd < 0) { 110319618Sjulian syslog(LOG_ERR, 110419618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 110519618Sjulian exit(EX_SOFTWARE); 110619618Sjulian } 110719618Sjulian if (ISMUX(sep)) { 110819618Sjulian syslog(LOG_ERR, 110919618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 111019618Sjulian exit(EX_SOFTWARE); 111119618Sjulian } 111219618Sjulian if (FD_ISSET(sep->se_fd, &allsock)) { 111319618Sjulian syslog(LOG_ERR, 111419618Sjulian "%s: %s: not off", __FUNCTION__, sep->se_service); 111519618Sjulian exit(EX_SOFTWARE); 111619618Sjulian } 111719618Sjulian#endif 111819618Sjulian FD_SET(sep->se_fd, &allsock); 111919618Sjulian nsock++; 112019618Sjulian if (sep->se_fd > maxsock) 112119618Sjulian maxsock = sep->se_fd; 112219618Sjulian} 112319618Sjulian 112419618Sjulianvoid 112519618Sjuliandisable(struct servtab *sep) 112619618Sjulian{ 112719618Sjulian if (debug) 112829602Scharnier warnx( 112919618Sjulian "disabling %s, fd %d", sep->se_service, sep->se_fd); 113019618Sjulian#ifdef SANITY_CHECK 113119618Sjulian if (sep->se_fd < 0) { 113219618Sjulian syslog(LOG_ERR, 113319618Sjulian "%s: %s: bad fd", __FUNCTION__, sep->se_service); 113419618Sjulian exit(EX_SOFTWARE); 113519618Sjulian } 113619618Sjulian if (ISMUX(sep)) { 113719618Sjulian syslog(LOG_ERR, 113819618Sjulian "%s: %s: is mux", __FUNCTION__, sep->se_service); 113919618Sjulian exit(EX_SOFTWARE); 114019618Sjulian } 114119618Sjulian if (!FD_ISSET(sep->se_fd, &allsock)) { 114219618Sjulian syslog(LOG_ERR, 114319618Sjulian "%s: %s: not on", __FUNCTION__, sep->se_service); 114419618Sjulian exit(EX_SOFTWARE); 114519618Sjulian } 114619618Sjulian if (nsock == 0) { 114719618Sjulian syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__); 114819618Sjulian exit(EX_SOFTWARE); 114919618Sjulian } 115019618Sjulian#endif 115119618Sjulian FD_CLR(sep->se_fd, &allsock); 115219618Sjulian nsock--; 115319618Sjulian if (sep->se_fd == maxsock) 115419618Sjulian maxsock--; 115519618Sjulian} 115619618Sjulian 11571553SrgrimesFILE *fconfig = NULL; 11581553Srgrimesstruct servtab serv; 11591553Srgrimeschar line[LINE_MAX]; 11601553Srgrimes 11611553Srgrimesint 11621553Srgrimessetconfig() 11631553Srgrimes{ 11641553Srgrimes 11651553Srgrimes if (fconfig != NULL) { 11661553Srgrimes fseek(fconfig, 0L, SEEK_SET); 11671553Srgrimes return (1); 11681553Srgrimes } 11691553Srgrimes fconfig = fopen(CONFIG, "r"); 11701553Srgrimes return (fconfig != NULL); 11711553Srgrimes} 11721553Srgrimes 11731553Srgrimesvoid 11741553Srgrimesendconfig() 11751553Srgrimes{ 11761553Srgrimes if (fconfig) { 11771553Srgrimes (void) fclose(fconfig); 11781553Srgrimes fconfig = NULL; 11791553Srgrimes } 11801553Srgrimes} 11811553Srgrimes 11821553Srgrimesstruct servtab * 11831553Srgrimesgetconfigent() 11841553Srgrimes{ 11851553Srgrimes struct servtab *sep = &serv; 11861553Srgrimes int argc; 118719618Sjulian char *cp, *arg, *s; 11882657Scsgr char *versp; 11891553Srgrimes static char TCPMUX_TOKEN[] = "tcpmux/"; 11901553Srgrimes#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 11911553Srgrimes 11921553Srgrimesmore: 11931553Srgrimes while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 11941553Srgrimes ; 11951553Srgrimes if (cp == NULL) 11961553Srgrimes return ((struct servtab *)0); 11971553Srgrimes /* 11981553Srgrimes * clear the static buffer, since some fields (se_ctrladdr, 11991553Srgrimes * for example) don't get initialized here. 12001553Srgrimes */ 12011553Srgrimes memset((caddr_t)sep, 0, sizeof *sep); 12021553Srgrimes arg = skip(&cp); 12031553Srgrimes if (cp == NULL) { 12041553Srgrimes /* got an empty line containing just blanks/tabs. */ 12051553Srgrimes goto more; 12061553Srgrimes } 12071553Srgrimes if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 12081553Srgrimes char *c = arg + MUX_LEN; 12091553Srgrimes if (*c == '+') { 12101553Srgrimes sep->se_type = MUXPLUS_TYPE; 12111553Srgrimes c++; 12121553Srgrimes } else 12131553Srgrimes sep->se_type = MUX_TYPE; 12141553Srgrimes sep->se_service = newstr(c); 12151553Srgrimes } else { 12161553Srgrimes sep->se_service = newstr(arg); 12171553Srgrimes sep->se_type = NORM_TYPE; 12181553Srgrimes } 12191553Srgrimes arg = sskip(&cp); 12201553Srgrimes if (strcmp(arg, "stream") == 0) 12211553Srgrimes sep->se_socktype = SOCK_STREAM; 12221553Srgrimes else if (strcmp(arg, "dgram") == 0) 12231553Srgrimes sep->se_socktype = SOCK_DGRAM; 12241553Srgrimes else if (strcmp(arg, "rdm") == 0) 12251553Srgrimes sep->se_socktype = SOCK_RDM; 12261553Srgrimes else if (strcmp(arg, "seqpacket") == 0) 12271553Srgrimes sep->se_socktype = SOCK_SEQPACKET; 12281553Srgrimes else if (strcmp(arg, "raw") == 0) 12291553Srgrimes sep->se_socktype = SOCK_RAW; 12301553Srgrimes else 12311553Srgrimes sep->se_socktype = -1; 123236042Sguido 123336042Sguido arg = sskip(&cp); 123436042Sguido if (strcmp(arg, "tcp/ttcp") == 0) { 123536042Sguido sep->se_type = TTCP_TYPE; 123636042Sguido sep->se_proto = newstr("tcp"); 123736042Sguido } else { 123836042Sguido sep->se_proto = newstr(arg); 123936042Sguido } 12402657Scsgr if (strncmp(sep->se_proto, "rpc/", 4) == 0) { 124119237Sjoerg memmove(sep->se_proto, sep->se_proto + 4, 124219237Sjoerg strlen(sep->se_proto) + 1 - 4); 12432657Scsgr sep->se_rpc = 1; 12442657Scsgr sep->se_rpc_prog = sep->se_rpc_lowvers = 12452657Scsgr sep->se_rpc_lowvers = 0; 12462657Scsgr sep->se_ctrladdr.sin_family = AF_INET; 12472657Scsgr sep->se_ctrladdr.sin_port = 0; 124817482Sjulian sep->se_ctrladdr.sin_addr = bind_address; 12492657Scsgr if ((versp = rindex(sep->se_service, '/'))) { 12502657Scsgr *versp++ = '\0'; 12512657Scsgr switch (sscanf(versp, "%d-%d", 12522657Scsgr &sep->se_rpc_lowvers, 12532657Scsgr &sep->se_rpc_highvers)) { 12542657Scsgr case 2: 12552657Scsgr break; 12562657Scsgr case 1: 12572657Scsgr sep->se_rpc_highvers = 12582657Scsgr sep->se_rpc_lowvers; 12592657Scsgr break; 12602657Scsgr default: 12618857Srgrimes syslog(LOG_ERR, 12628857Srgrimes "bad RPC version specifier; %s\n", 12632657Scsgr sep->se_service); 12642657Scsgr freeconfig(sep); 12652657Scsgr goto more; 12662657Scsgr } 12672657Scsgr } 12682657Scsgr else { 12692657Scsgr sep->se_rpc_lowvers = 12702657Scsgr sep->se_rpc_highvers = 1; 12712657Scsgr } 12722657Scsgr } 12731553Srgrimes arg = sskip(&cp); 127419618Sjulian if (!strncmp(arg, "wait", 4)) 127519618Sjulian sep->se_accept = 0; 127619618Sjulian else if (!strncmp(arg, "nowait", 6)) 127719618Sjulian sep->se_accept = 1; 127819618Sjulian else { 127919618Sjulian syslog(LOG_ERR, 128019618Sjulian "%s: bad wait/nowait for service %s", 128119618Sjulian CONFIG, sep->se_service); 128219618Sjulian goto more; 128319618Sjulian } 128433794Spst sep->se_maxchild = maxchild; 128533794Spst sep->se_maxcpm = maxcpm; 128619618Sjulian if ((s = strchr(arg, '/')) != NULL) { 128719618Sjulian char *eptr; 128819618Sjulian u_long val; 128919618Sjulian 129019618Sjulian val = strtoul(s + 1, &eptr, 10); 129130847Sdima if (eptr == s + 1 || val > MAX_MAXCHLD) { 129219618Sjulian syslog(LOG_ERR, 129319618Sjulian "%s: bad max-child for service %s", 129419618Sjulian CONFIG, sep->se_service); 129519618Sjulian goto more; 129619618Sjulian } 129719618Sjulian sep->se_maxchild = val; 129830847Sdima if (*eptr == '/') 129930847Sdima sep->se_maxcpm = strtol(eptr + 1, &eptr, 10); 130030847Sdima /* 130130847Sdima * explicitly do not check for \0 for future expansion / 130230847Sdima * backwards compatibility 130330847Sdima */ 130419618Sjulian } 13051553Srgrimes if (ISMUX(sep)) { 13061553Srgrimes /* 130719618Sjulian * Silently enforce "nowait" mode for TCPMUX services 130819618Sjulian * since they don't have an assigned port to listen on. 13091553Srgrimes */ 131019618Sjulian sep->se_accept = 1; 13111553Srgrimes if (strcmp(sep->se_proto, "tcp")) { 13128857Srgrimes syslog(LOG_ERR, 13131553Srgrimes "%s: bad protocol for tcpmux service %s", 13141553Srgrimes CONFIG, sep->se_service); 13151553Srgrimes goto more; 13161553Srgrimes } 13171553Srgrimes if (sep->se_socktype != SOCK_STREAM) { 13188857Srgrimes syslog(LOG_ERR, 13191553Srgrimes "%s: bad socket type for tcpmux service %s", 13201553Srgrimes CONFIG, sep->se_service); 13211553Srgrimes goto more; 13221553Srgrimes } 13231553Srgrimes } 13241553Srgrimes sep->se_user = newstr(sskip(&cp)); 132530792Sache#ifdef LOGIN_CAP 132630792Sache if ((s = strrchr(sep->se_user, '/')) != NULL) { 132730792Sache *s = '\0'; 132830792Sache sep->se_class = newstr(s + 1); 132930792Sache } else 133030792Sache sep->se_class = newstr(RESOURCE_RC); 133130792Sache#endif 133230807Sache if ((s = strrchr(sep->se_user, ':')) != NULL) { 133330807Sache *s = '\0'; 133430807Sache sep->se_group = newstr(s + 1); 133530807Sache } else 133630807Sache sep->se_group = NULL; 13371553Srgrimes sep->se_server = newstr(sskip(&cp)); 13381553Srgrimes if (strcmp(sep->se_server, "internal") == 0) { 13391553Srgrimes struct biltin *bi; 13401553Srgrimes 13411553Srgrimes for (bi = biltins; bi->bi_service; bi++) 13421553Srgrimes if (bi->bi_socktype == sep->se_socktype && 13431553Srgrimes strcmp(bi->bi_service, sep->se_service) == 0) 13441553Srgrimes break; 13451553Srgrimes if (bi->bi_service == 0) { 13461553Srgrimes syslog(LOG_ERR, "internal service %s unknown", 13471553Srgrimes sep->se_service); 13481553Srgrimes goto more; 13491553Srgrimes } 135019618Sjulian sep->se_accept = 1; /* force accept mode for built-ins */ 13511553Srgrimes sep->se_bi = bi; 13521553Srgrimes } else 13531553Srgrimes sep->se_bi = NULL; 135419618Sjulian if (sep->se_maxchild < 0) /* apply default max-children */ 135519618Sjulian if (sep->se_bi) 135619618Sjulian sep->se_maxchild = sep->se_bi->bi_maxchild; 135719618Sjulian else 135819618Sjulian sep->se_maxchild = sep->se_accept ? 0 : 1; 135919618Sjulian if (sep->se_maxchild) { 136019618Sjulian sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids)); 136119618Sjulian if (sep->se_pids == NULL) { 136219618Sjulian syslog(LOG_ERR, "Out of memory."); 136319618Sjulian exit(EX_OSERR); 136419618Sjulian } 136519618Sjulian } 13661553Srgrimes argc = 0; 13671553Srgrimes for (arg = skip(&cp); cp; arg = skip(&cp)) 136819618Sjulian if (argc < MAXARGV) { 13691553Srgrimes sep->se_argv[argc++] = newstr(arg); 137019618Sjulian } else { 137119618Sjulian syslog(LOG_ERR, 137219618Sjulian "%s: too many arguments for service %s", 137319618Sjulian CONFIG, sep->se_service); 137419618Sjulian goto more; 137519618Sjulian } 13761553Srgrimes while (argc <= MAXARGV) 13771553Srgrimes sep->se_argv[argc++] = NULL; 13781553Srgrimes return (sep); 13791553Srgrimes} 13801553Srgrimes 13811553Srgrimesvoid 13821553Srgrimesfreeconfig(cp) 13831553Srgrimes struct servtab *cp; 13841553Srgrimes{ 13851553Srgrimes int i; 13861553Srgrimes 13871553Srgrimes if (cp->se_service) 13881553Srgrimes free(cp->se_service); 13891553Srgrimes if (cp->se_proto) 13901553Srgrimes free(cp->se_proto); 13911553Srgrimes if (cp->se_user) 13921553Srgrimes free(cp->se_user); 139330807Sache if (cp->se_group) 139430807Sache free(cp->se_group); 139530792Sache#ifdef LOGIN_CAP 139630792Sache if (cp->se_class) 139730792Sache free(cp->se_class); 139830792Sache#endif 13991553Srgrimes if (cp->se_server) 14001553Srgrimes free(cp->se_server); 140119618Sjulian if (cp->se_pids) 140219618Sjulian free(cp->se_pids); 14031553Srgrimes for (i = 0; i < MAXARGV; i++) 14041553Srgrimes if (cp->se_argv[i]) 14051553Srgrimes free(cp->se_argv[i]); 14061553Srgrimes} 14071553Srgrimes 14081553Srgrimes 14091553Srgrimes/* 14101553Srgrimes * Safe skip - if skip returns null, log a syntax error in the 14111553Srgrimes * configuration file and exit. 14121553Srgrimes */ 14131553Srgrimeschar * 14141553Srgrimessskip(cpp) 14151553Srgrimes char **cpp; 14161553Srgrimes{ 14171553Srgrimes char *cp; 14181553Srgrimes 14191553Srgrimes cp = skip(cpp); 14201553Srgrimes if (cp == NULL) { 14211553Srgrimes syslog(LOG_ERR, "%s: syntax error", CONFIG); 142219617Sjulian exit(EX_DATAERR); 14231553Srgrimes } 14241553Srgrimes return (cp); 14251553Srgrimes} 14261553Srgrimes 14271553Srgrimeschar * 14281553Srgrimesskip(cpp) 14291553Srgrimes char **cpp; 14301553Srgrimes{ 14311553Srgrimes char *cp = *cpp; 14321553Srgrimes char *start; 143311933Sadam char quote = '\0'; 14341553Srgrimes 14351553Srgrimesagain: 14361553Srgrimes while (*cp == ' ' || *cp == '\t') 14371553Srgrimes cp++; 14381553Srgrimes if (*cp == '\0') { 14391553Srgrimes int c; 14401553Srgrimes 14411553Srgrimes c = getc(fconfig); 14421553Srgrimes (void) ungetc(c, fconfig); 14431553Srgrimes if (c == ' ' || c == '\t') 144419617Sjulian if ((cp = nextline(fconfig))) 14451553Srgrimes goto again; 14461553Srgrimes *cpp = (char *)0; 14471553Srgrimes return ((char *)0); 14481553Srgrimes } 144911933Sadam if (*cp == '"' || *cp == '\'') 145011933Sadam quote = *cp++; 14511553Srgrimes start = cp; 145211933Sadam if (quote) 145311933Sadam while (*cp && *cp != quote) 145411933Sadam cp++; 145511933Sadam else 145611933Sadam while (*cp && *cp != ' ' && *cp != '\t') 145711933Sadam cp++; 14581553Srgrimes if (*cp != '\0') 14591553Srgrimes *cp++ = '\0'; 14601553Srgrimes *cpp = cp; 14611553Srgrimes return (start); 14621553Srgrimes} 14631553Srgrimes 14641553Srgrimeschar * 14651553Srgrimesnextline(fd) 14661553Srgrimes FILE *fd; 14671553Srgrimes{ 14681553Srgrimes char *cp; 14691553Srgrimes 14701553Srgrimes if (fgets(line, sizeof (line), fd) == NULL) 14711553Srgrimes return ((char *)0); 14721553Srgrimes cp = strchr(line, '\n'); 14731553Srgrimes if (cp) 14741553Srgrimes *cp = '\0'; 14751553Srgrimes return (line); 14761553Srgrimes} 14771553Srgrimes 14781553Srgrimeschar * 14791553Srgrimesnewstr(cp) 14801553Srgrimes char *cp; 14811553Srgrimes{ 148219617Sjulian if ((cp = strdup(cp ? cp : ""))) 14831553Srgrimes return (cp); 14841553Srgrimes syslog(LOG_ERR, "strdup: %m"); 148519617Sjulian exit(EX_OSERR); 14861553Srgrimes} 14871553Srgrimes 148813142Speter#ifdef OLD_SETPROCTITLE 14891553Srgrimesvoid 149013142Speterinetd_setproctitle(a, s) 14911553Srgrimes char *a; 14921553Srgrimes int s; 14931553Srgrimes{ 14941553Srgrimes int size; 14951553Srgrimes char *cp; 14961553Srgrimes struct sockaddr_in sin; 14971553Srgrimes char buf[80]; 14981553Srgrimes 14991553Srgrimes cp = Argv[0]; 15001553Srgrimes size = sizeof(sin); 15011553Srgrimes if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 15028857Srgrimes (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 15031553Srgrimes else 15048857Srgrimes (void) sprintf(buf, "-%s", a); 15051553Srgrimes strncpy(cp, buf, LastArg - cp); 15061553Srgrimes cp += strlen(cp); 15071553Srgrimes while (cp < LastArg) 15081553Srgrimes *cp++ = ' '; 15091553Srgrimes} 151013142Speter#else 151113142Spetervoid 151213142Speterinetd_setproctitle(a, s) 151313142Speter char *a; 151413142Speter int s; 151513142Speter{ 151613142Speter int size; 151713142Speter struct sockaddr_in sin; 151813142Speter char buf[80]; 15191553Srgrimes 152013142Speter size = sizeof(sin); 152113142Speter if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 152213142Speter (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 152313142Speter else 152413142Speter (void) sprintf(buf, "%s", a); 152513142Speter setproctitle("%s", buf); 152613142Speter} 152713142Speter#endif 152813142Speter 152913142Speter 15301553Srgrimes/* 15311553Srgrimes * Internet services provided internally by inetd: 15321553Srgrimes */ 15331553Srgrimes#define BUFSIZE 8192 15341553Srgrimes 153540910Sphk#define IDENT_RESPONSE ":ERROR:HIDDEN-USER\r\n" 153640910Sphk 15371553Srgrimes/* ARGSUSED */ 15381553Srgrimesvoid 153940910Sphkident_stream(s, sep) /* Ident service */ 154040910Sphk int s; 154140910Sphk struct servtab *sep; 154240910Sphk{ 154340910Sphk char buffer[BUFSIZE]; 154440910Sphk int i, j; 154540910Sphk 154640910Sphk inetd_setproctitle(sep->se_service, s); 154740910Sphk j = 0; 154840910Sphk while ((i = read(s, buffer + j, sizeof(buffer) - j)) > 0) { 154940910Sphk j += i; 155040910Sphk buffer[j] = '\0'; 155140910Sphk if (strchr(buffer, '\n')) 155240910Sphk break; 155340910Sphk if (strchr(buffer, '\r')) 155440910Sphk break; 155540910Sphk } 155640910Sphk while (j > 0 && (buffer[j-1] == '\n' || buffer[j-1] == '\r')) 155740910Sphk j--; 155840910Sphk write(s, buffer, j); 155940910Sphk write(s, IDENT_RESPONSE, strlen(IDENT_RESPONSE)); 156040910Sphk exit(0); 156140910Sphk} 156240910Sphk/* ARGSUSED */ 156340910Sphkvoid 15641553Srgrimesecho_stream(s, sep) /* Echo service -- echo data back */ 15651553Srgrimes int s; 15661553Srgrimes struct servtab *sep; 15671553Srgrimes{ 15681553Srgrimes char buffer[BUFSIZE]; 15691553Srgrimes int i; 15701553Srgrimes 157113142Speter inetd_setproctitle(sep->se_service, s); 15721553Srgrimes while ((i = read(s, buffer, sizeof(buffer))) > 0 && 15731553Srgrimes write(s, buffer, i) > 0) 15741553Srgrimes ; 15751553Srgrimes exit(0); 15761553Srgrimes} 15771553Srgrimes 15785182Swollmanint check_loop(sin, sep) 15795182Swollman struct sockaddr_in *sin; 15805182Swollman struct servtab *sep; 15815182Swollman{ 15825182Swollman struct servtab *se2; 15835182Swollman 15845182Swollman for (se2 = servtab; se2; se2 = se2->se_next) { 15855182Swollman if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM) 15865182Swollman continue; 15875182Swollman 15885182Swollman if (sin->sin_port == se2->se_ctrladdr.sin_port) { 15895182Swollman syslog(LOG_WARNING, 15905182Swollman "%s/%s:%s/%s loop request REFUSED from %s", 15918857Srgrimes sep->se_service, sep->se_proto, 15925182Swollman se2->se_service, se2->se_proto, 15935182Swollman inet_ntoa(sin->sin_addr)); 15945182Swollman return 1; 15955182Swollman } 15965182Swollman } 15975182Swollman return 0; 15985182Swollman} 15995182Swollman 16001553Srgrimes/* ARGSUSED */ 16011553Srgrimesvoid 16021553Srgrimesecho_dg(s, sep) /* Echo service -- echo data back */ 16031553Srgrimes int s; 16041553Srgrimes struct servtab *sep; 16051553Srgrimes{ 16061553Srgrimes char buffer[BUFSIZE]; 16071553Srgrimes int i, size; 16085182Swollman struct sockaddr_in sin; 16091553Srgrimes 16105182Swollman size = sizeof(sin); 16118857Srgrimes if ((i = recvfrom(s, buffer, sizeof(buffer), 0, 16125182Swollman (struct sockaddr *)&sin, &size)) < 0) 16131553Srgrimes return; 16145182Swollman 16155182Swollman if (check_loop(&sin, sep)) 16165182Swollman return; 16175182Swollman 16185182Swollman (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin, 16195182Swollman sizeof(sin)); 16201553Srgrimes} 16211553Srgrimes 16221553Srgrimes/* ARGSUSED */ 16231553Srgrimesvoid 16241553Srgrimesdiscard_stream(s, sep) /* Discard service -- ignore data */ 16251553Srgrimes int s; 16261553Srgrimes struct servtab *sep; 16271553Srgrimes{ 16281553Srgrimes int ret; 16291553Srgrimes char buffer[BUFSIZE]; 16301553Srgrimes 163113142Speter inetd_setproctitle(sep->se_service, s); 16321553Srgrimes while (1) { 16331553Srgrimes while ((ret = read(s, buffer, sizeof(buffer))) > 0) 16341553Srgrimes ; 16351553Srgrimes if (ret == 0 || errno != EINTR) 16361553Srgrimes break; 16371553Srgrimes } 16381553Srgrimes exit(0); 16391553Srgrimes} 16401553Srgrimes 16411553Srgrimes/* ARGSUSED */ 16421553Srgrimesvoid 16431553Srgrimesdiscard_dg(s, sep) /* Discard service -- ignore data */ 16441553Srgrimes int s; 16451553Srgrimes struct servtab *sep; 16461553Srgrimes{ 16471553Srgrimes char buffer[BUFSIZE]; 16481553Srgrimes 16491553Srgrimes (void) read(s, buffer, sizeof(buffer)); 16501553Srgrimes} 16511553Srgrimes 16521553Srgrimes#include <ctype.h> 16531553Srgrimes#define LINESIZ 72 16541553Srgrimeschar ring[128]; 16551553Srgrimeschar *endring; 16561553Srgrimes 16571553Srgrimesvoid 16581553Srgrimesinitring() 16591553Srgrimes{ 16601553Srgrimes int i; 16611553Srgrimes 16621553Srgrimes endring = ring; 16631553Srgrimes 16641553Srgrimes for (i = 0; i <= 128; ++i) 16651553Srgrimes if (isprint(i)) 16661553Srgrimes *endring++ = i; 16671553Srgrimes} 16681553Srgrimes 16691553Srgrimes/* ARGSUSED */ 16701553Srgrimesvoid 16711553Srgrimeschargen_stream(s, sep) /* Character generator */ 16721553Srgrimes int s; 16731553Srgrimes struct servtab *sep; 16741553Srgrimes{ 16751553Srgrimes int len; 16761553Srgrimes char *rs, text[LINESIZ+2]; 16771553Srgrimes 167813142Speter inetd_setproctitle(sep->se_service, s); 16791553Srgrimes 16801553Srgrimes if (!endring) { 16811553Srgrimes initring(); 16821553Srgrimes rs = ring; 16831553Srgrimes } 16841553Srgrimes 16851553Srgrimes text[LINESIZ] = '\r'; 16861553Srgrimes text[LINESIZ + 1] = '\n'; 16871553Srgrimes for (rs = ring;;) { 16881553Srgrimes if ((len = endring - rs) >= LINESIZ) 16891553Srgrimes memmove(text, rs, LINESIZ); 16901553Srgrimes else { 16911553Srgrimes memmove(text, rs, len); 16921553Srgrimes memmove(text + len, ring, LINESIZ - len); 16931553Srgrimes } 16941553Srgrimes if (++rs == endring) 16951553Srgrimes rs = ring; 16961553Srgrimes if (write(s, text, sizeof(text)) != sizeof(text)) 16971553Srgrimes break; 16981553Srgrimes } 16991553Srgrimes exit(0); 17001553Srgrimes} 17011553Srgrimes 17021553Srgrimes/* ARGSUSED */ 17031553Srgrimesvoid 17041553Srgrimeschargen_dg(s, sep) /* Character generator */ 17051553Srgrimes int s; 17061553Srgrimes struct servtab *sep; 17071553Srgrimes{ 17085182Swollman struct sockaddr_in sin; 17091553Srgrimes static char *rs; 17101553Srgrimes int len, size; 17111553Srgrimes char text[LINESIZ+2]; 17121553Srgrimes 17131553Srgrimes if (endring == 0) { 17141553Srgrimes initring(); 17151553Srgrimes rs = ring; 17161553Srgrimes } 17171553Srgrimes 17185182Swollman size = sizeof(sin); 17198857Srgrimes if (recvfrom(s, text, sizeof(text), 0, 17205182Swollman (struct sockaddr *)&sin, &size) < 0) 17211553Srgrimes return; 17221553Srgrimes 17235182Swollman if (check_loop(&sin, sep)) 17245182Swollman return; 17255182Swollman 17261553Srgrimes if ((len = endring - rs) >= LINESIZ) 17271553Srgrimes memmove(text, rs, LINESIZ); 17281553Srgrimes else { 17291553Srgrimes memmove(text, rs, len); 17301553Srgrimes memmove(text + len, ring, LINESIZ - len); 17311553Srgrimes } 17321553Srgrimes if (++rs == endring) 17331553Srgrimes rs = ring; 17341553Srgrimes text[LINESIZ] = '\r'; 17351553Srgrimes text[LINESIZ + 1] = '\n'; 17368857Srgrimes (void) sendto(s, text, sizeof(text), 0, 17375182Swollman (struct sockaddr *)&sin, sizeof(sin)); 17381553Srgrimes} 17391553Srgrimes 17401553Srgrimes/* 17411553Srgrimes * Return a machine readable date and time, in the form of the 17421553Srgrimes * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 17431553Srgrimes * returns the number of seconds since midnight, Jan 1, 1970, 17441553Srgrimes * we must add 2208988800 seconds to this figure to make up for 17451553Srgrimes * some seventy years Bell Labs was asleep. 17461553Srgrimes */ 17471553Srgrimes 17481553Srgrimeslong 17491553Srgrimesmachtime() 17501553Srgrimes{ 17511553Srgrimes struct timeval tv; 17521553Srgrimes 175337856Sache if (gettimeofday(&tv, (struct timezone *)NULL) < 0) { 17541553Srgrimes if (debug) 175529602Scharnier warnx("unable to get time of day"); 17561553Srgrimes return (0L); 17571553Srgrimes } 17581553Srgrimes#define OFFSET ((u_long)25567 * 24*60*60) 17591553Srgrimes return (htonl((long)(tv.tv_sec + OFFSET))); 17601553Srgrimes#undef OFFSET 17611553Srgrimes} 17621553Srgrimes 17631553Srgrimes/* ARGSUSED */ 17641553Srgrimesvoid 17651553Srgrimesmachtime_stream(s, sep) 17661553Srgrimes int s; 17671553Srgrimes struct servtab *sep; 17681553Srgrimes{ 17691553Srgrimes long result; 17701553Srgrimes 17711553Srgrimes result = machtime(); 17721553Srgrimes (void) write(s, (char *) &result, sizeof(result)); 17731553Srgrimes} 17741553Srgrimes 17751553Srgrimes/* ARGSUSED */ 17761553Srgrimesvoid 17771553Srgrimesmachtime_dg(s, sep) 17781553Srgrimes int s; 17791553Srgrimes struct servtab *sep; 17801553Srgrimes{ 17811553Srgrimes long result; 17825182Swollman struct sockaddr_in sin; 17831553Srgrimes int size; 17841553Srgrimes 17855182Swollman size = sizeof(sin); 17868857Srgrimes if (recvfrom(s, (char *)&result, sizeof(result), 0, 17875182Swollman (struct sockaddr *)&sin, &size) < 0) 17881553Srgrimes return; 17895182Swollman 17905182Swollman if (check_loop(&sin, sep)) 17915182Swollman return; 17925182Swollman 17931553Srgrimes result = machtime(); 17948857Srgrimes (void) sendto(s, (char *) &result, sizeof(result), 0, 17955182Swollman (struct sockaddr *)&sin, sizeof(sin)); 17961553Srgrimes} 17971553Srgrimes 17981553Srgrimes/* ARGSUSED */ 17991553Srgrimesvoid 18001553Srgrimesdaytime_stream(s, sep) /* Return human-readable time of day */ 18011553Srgrimes int s; 18021553Srgrimes struct servtab *sep; 18031553Srgrimes{ 18041553Srgrimes char buffer[256]; 18051553Srgrimes time_t clock; 18061553Srgrimes 18071553Srgrimes clock = time((time_t *) 0); 18081553Srgrimes 18091553Srgrimes (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 18101553Srgrimes (void) write(s, buffer, strlen(buffer)); 18111553Srgrimes} 18121553Srgrimes 18131553Srgrimes/* ARGSUSED */ 18141553Srgrimesvoid 18151553Srgrimesdaytime_dg(s, sep) /* Return human-readable time of day */ 18161553Srgrimes int s; 18171553Srgrimes struct servtab *sep; 18181553Srgrimes{ 18191553Srgrimes char buffer[256]; 18201553Srgrimes time_t clock; 18215182Swollman struct sockaddr_in sin; 18221553Srgrimes int size; 18231553Srgrimes 18241553Srgrimes clock = time((time_t *) 0); 18251553Srgrimes 18265182Swollman size = sizeof(sin); 18278857Srgrimes if (recvfrom(s, buffer, sizeof(buffer), 0, 18285182Swollman (struct sockaddr *)&sin, &size) < 0) 18291553Srgrimes return; 18305182Swollman 18315182Swollman if (check_loop(&sin, sep)) 18325182Swollman return; 18335182Swollman 18341553Srgrimes (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 18358857Srgrimes (void) sendto(s, buffer, strlen(buffer), 0, 18365182Swollman (struct sockaddr *)&sin, sizeof(sin)); 18371553Srgrimes} 18381553Srgrimes 18391553Srgrimes/* 18401553Srgrimes * print_service: 18411553Srgrimes * Dump relevant information to stderr 18421553Srgrimes */ 18431553Srgrimesvoid 18441553Srgrimesprint_service(action, sep) 18451553Srgrimes char *action; 18461553Srgrimes struct servtab *sep; 18471553Srgrimes{ 184819617Sjulian fprintf(stderr, 184930792Sache#ifdef LOGIN_CAP 185038380Sjb "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n", 185130792Sache#else 185238380Sjb "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n", 185330792Sache#endif 185419617Sjulian action, sep->se_service, sep->se_proto, 185530807Sache sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group, 185630792Sache#ifdef LOGIN_CAP 185730792Sache sep->se_class, 185830792Sache#endif 185938417Sjb (void *) sep->se_bi, sep->se_server); 18601553Srgrimes} 18611553Srgrimes 18621553Srgrimes/* 18631553Srgrimes * Based on TCPMUX.C by Mark K. Lottor November 1988 18641553Srgrimes * sri-nic::ps:<mkl>tcpmux.c 18651553Srgrimes */ 18661553Srgrimes 18671553Srgrimes 18681553Srgrimesstatic int /* # of characters upto \r,\n or \0 */ 18691553Srgrimesgetline(fd, buf, len) 18701553Srgrimes int fd; 18711553Srgrimes char *buf; 18721553Srgrimes int len; 18731553Srgrimes{ 18741553Srgrimes int count = 0, n; 187535848Sguido struct sigaction sa; 18761553Srgrimes 187735948Sbde sa.sa_flags = 0; 187835948Sbde sigemptyset(&sa.sa_mask); 187935848Sguido sa.sa_handler = SIG_DFL; 188035848Sguido sigaction(SIGALRM, &sa, (struct sigaction *)0); 18811553Srgrimes do { 188235829Sguido alarm(10); 18831553Srgrimes n = read(fd, buf, len-count); 188435829Sguido alarm(0); 18851553Srgrimes if (n == 0) 188642122Sdes return (count); 188742122Sdes if (n < 0) 188842122Sdes return (-1); 18891553Srgrimes while (--n >= 0) { 189042122Sdes if (*buf == '\r' || *buf == '\n' || *buf == '\0') 189142122Sdes return (count); 18921553Srgrimes count++; 18931553Srgrimes buf++; 18941553Srgrimes } 189542122Sdes } while (count < len); 18961553Srgrimes return (count); 18971553Srgrimes} 18981553Srgrimes 18991553Srgrimes#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 19001553Srgrimes 19011553Srgrimes#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 19021553Srgrimes 19031553Srgrimesstruct servtab * 19041553Srgrimestcpmux(s) 19051553Srgrimes int s; 19061553Srgrimes{ 19071553Srgrimes struct servtab *sep; 19081553Srgrimes char service[MAX_SERV_LEN+1]; 19091553Srgrimes int len; 19101553Srgrimes 19111553Srgrimes /* Get requested service name */ 19121553Srgrimes if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 19131553Srgrimes strwrite(s, "-Error reading service name\r\n"); 19141553Srgrimes return (NULL); 19151553Srgrimes } 19161553Srgrimes service[len] = '\0'; 19171553Srgrimes 19181553Srgrimes if (debug) 191929602Scharnier warnx("tcpmux: someone wants %s", service); 19201553Srgrimes 19211553Srgrimes /* 19221553Srgrimes * Help is a required command, and lists available services, 19231553Srgrimes * one per line. 19241553Srgrimes */ 19251553Srgrimes if (!strcasecmp(service, "help")) { 19261553Srgrimes for (sep = servtab; sep; sep = sep->se_next) { 19271553Srgrimes if (!ISMUX(sep)) 19281553Srgrimes continue; 19291553Srgrimes (void)write(s,sep->se_service,strlen(sep->se_service)); 19301553Srgrimes strwrite(s, "\r\n"); 19311553Srgrimes } 19321553Srgrimes return (NULL); 19331553Srgrimes } 19341553Srgrimes 19351553Srgrimes /* Try matching a service in inetd.conf with the request */ 19361553Srgrimes for (sep = servtab; sep; sep = sep->se_next) { 19371553Srgrimes if (!ISMUX(sep)) 19381553Srgrimes continue; 19391553Srgrimes if (!strcasecmp(service, sep->se_service)) { 19401553Srgrimes if (ISMUXPLUS(sep)) { 19411553Srgrimes strwrite(s, "+Go\r\n"); 19421553Srgrimes } 19431553Srgrimes return (sep); 19441553Srgrimes } 19451553Srgrimes } 19461553Srgrimes strwrite(s, "-Service not available\r\n"); 19471553Srgrimes return (NULL); 19481553Srgrimes} 194930847Sdima 195030847Sdima#define CPMHSIZE 256 195130847Sdima#define CPMHMASK (CPMHSIZE-1) 195230847Sdima#define CHTGRAN 10 195330847Sdima#define CHTSIZE 6 195430847Sdima 195530847Sdimatypedef struct CTime { 195630847Sdima unsigned long ct_Ticks; 195730847Sdima int ct_Count; 195830847Sdima} CTime; 195930847Sdima 196030847Sdimatypedef struct CHash { 196130847Sdima struct in_addr ch_Addr; 196230847Sdima time_t ch_LTime; 196330847Sdima char *ch_Service; 196430847Sdima CTime ch_Times[CHTSIZE]; 196530847Sdima} CHash; 196630847Sdima 196730847SdimaCHash CHashAry[CPMHSIZE]; 196830847Sdima 196930847Sdimaint 197030847Sdimacpmip(sep, ctrl) 197130847Sdima struct servtab *sep; 197230847Sdima int ctrl; 197330847Sdima{ 197430847Sdima struct sockaddr_in rsin; 197530847Sdima int rsinLen = sizeof(rsin); 197630847Sdima int r = 0; 197730847Sdima 197830847Sdima /* 197930847Sdima * If getpeername() fails, just let it through (if logging is 198030847Sdima * enabled the condition is caught elsewhere) 198130847Sdima */ 198230847Sdima 198330847Sdima if (sep->se_maxcpm > 0 && 198430847Sdima getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) { 198530847Sdima time_t t = time(NULL); 198630847Sdima int hv = 0xABC3D20F; 198730847Sdima int i; 198830847Sdima int cnt = 0; 198930847Sdima CHash *chBest = NULL; 199030847Sdima unsigned int ticks = t / CHTGRAN; 199130847Sdima 199230847Sdima { 199330847Sdima char *p; 199430847Sdima int i; 199530847Sdima 199630847Sdima for (i = 0, p = (char *)&rsin.sin_addr; 199730847Sdima i < sizeof(rsin.sin_addr); 199830847Sdima ++i, ++p) { 199930847Sdima hv = (hv << 5) ^ (hv >> 23) ^ *p; 200030847Sdima } 200130847Sdima hv = (hv ^ (hv >> 16)); 200230847Sdima } 200330847Sdima for (i = 0; i < 5; ++i) { 200430847Sdima CHash *ch = &CHashAry[(hv + i) & CPMHMASK]; 200530847Sdima 200630847Sdima if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr && 200730847Sdima ch->ch_Service && strcmp(sep->se_service, 200830847Sdima ch->ch_Service) == 0) { 200930847Sdima chBest = ch; 201030847Sdima break; 201130847Sdima } 201230847Sdima if (chBest == NULL || ch->ch_LTime == 0 || 201330847Sdima ch->ch_LTime < chBest->ch_LTime) { 201430847Sdima chBest = ch; 201530847Sdima } 201630847Sdima } 201730847Sdima if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr || 201830847Sdima chBest->ch_Service == NULL || 201930847Sdima strcmp(sep->se_service, chBest->ch_Service) != 0) { 202030847Sdima chBest->ch_Addr = rsin.sin_addr; 202130847Sdima if (chBest->ch_Service) 202230847Sdima free(chBest->ch_Service); 202330847Sdima chBest->ch_Service = strdup(sep->se_service); 202430847Sdima bzero(chBest->ch_Times, sizeof(chBest->ch_Times)); 202530847Sdima } 202630847Sdima chBest->ch_LTime = t; 202730847Sdima { 202830847Sdima CTime *ct = &chBest->ch_Times[ticks % CHTSIZE]; 202930847Sdima if (ct->ct_Ticks != ticks) { 203030847Sdima ct->ct_Ticks = ticks; 203130847Sdima ct->ct_Count = 0; 203230847Sdima } 203330847Sdima ++ct->ct_Count; 203430847Sdima } 203530847Sdima for (i = 0; i < CHTSIZE; ++i) { 203630847Sdima CTime *ct = &chBest->ch_Times[i]; 203730847Sdima if (ct->ct_Ticks <= ticks && 203830847Sdima ct->ct_Ticks >= ticks - CHTSIZE) { 203930847Sdima cnt += ct->ct_Count; 204030847Sdima } 204130847Sdima } 204230847Sdima if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) { 204330847Sdima r = -1; 204430847Sdima syslog(LOG_ERR, 204533794Spst "%s from %s exceeded counts/min (limit %d/min)", 204633794Spst sep->se_service, inet_ntoa(rsin.sin_addr), 204733794Spst sep->se_maxcpm); 204830847Sdima } 204930847Sdima } 205030847Sdima return(r); 205130847Sdima} 2052