]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/inetd/inetd.c
This commit was generated by cvs2svn to compensate for changes in r98008,
[FreeBSD/FreeBSD.git] / usr.sbin / inetd / inetd.c
1 /*
2  * Copyright (c) 1983, 1991, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)from: inetd.c       8.4 (Berkeley) 4/13/94";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47
48 /*
49  * Inetd - Internet super-server
50  *
51  * This program invokes all internet services as needed.  Connection-oriented
52  * services are invoked each time a connection is made, by creating a process.
53  * This process is passed the connection as file descriptor 0 and is expected
54  * to do a getpeername to find out the source host and port.
55  *
56  * Datagram oriented services are invoked when a datagram
57  * arrives; a process is created and passed a pending message
58  * on file descriptor 0.  Datagram servers may either connect
59  * to their peer, freeing up the original socket for inetd
60  * to receive further messages on, or ``take over the socket'',
61  * processing all arriving datagrams and, eventually, timing
62  * out.  The first type of server is said to be ``multi-threaded'';
63  * the second type of server ``single-threaded''.
64  *
65  * Inetd uses a configuration file which is read at startup
66  * and, possibly, at some later time in response to a hangup signal.
67  * The configuration file is ``free format'' with fields given in the
68  * order shown below.  Continuation lines for an entry must begin with
69  * a space or tab.  All fields must be present in each entry.
70  *
71  *      service name                    must be in /etc/services
72  *                                      or name a tcpmux service 
73  *                                      or specify a unix domain socket
74  *      socket type                     stream/dgram/raw/rdm/seqpacket
75  *      protocol                        tcp[4][6][/faith,ttcp], udp[4][6], unix
76  *      wait/nowait                     single-threaded/multi-threaded
77  *      user                            user to run daemon as
78  *      server program                  full path name
79  *      server program arguments        maximum of MAXARGS (20)
80  *
81  * TCP services without official port numbers are handled with the
82  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
83  * requests. When a connection is made from a foreign host, the service
84  * requested is passed to tcpmux, which looks it up in the servtab list
85  * and returns the proper entry for the service. Tcpmux returns a
86  * negative reply if the service doesn't exist, otherwise the invoked
87  * server is expected to return the positive reply if the service type in
88  * inetd.conf file has the prefix "tcpmux/". If the service type has the
89  * prefix "tcpmux/+", tcpmux will return the positive reply for the
90  * process; this is for compatibility with older server code, and also
91  * allows you to invoke programs that use stdin/stdout without putting any
92  * special server code in them. Services that use tcpmux are "nowait"
93  * because they do not have a well-known port and hence cannot listen
94  * for new requests.
95  *
96  * For RPC services
97  *      service name/version            must be in /etc/rpc
98  *      socket type                     stream/dgram/raw/rdm/seqpacket
99  *      protocol                        rpc/tcp, rpc/udp
100  *      wait/nowait                     single-threaded/multi-threaded
101  *      user                            user to run daemon as
102  *      server program                  full path name
103  *      server program arguments        maximum of MAXARGS
104  *
105  * Comment lines are indicated by a `#' in column 1.
106  *
107  * #ifdef IPSEC
108  * Comment lines that start with "#@" denote IPsec policy string, as described
109  * in ipsec_set_policy(3).  This will affect all the following items in
110  * inetd.conf(8).  To reset the policy, just use "#@" line.  By default,
111  * there's no IPsec policy.
112  * #endif
113  */
114 #include <sys/param.h>
115 #include <sys/ioctl.h>
116 #include <sys/wait.h>
117 #include <sys/time.h>
118 #include <sys/resource.h>
119 #include <sys/stat.h>
120 #include <sys/un.h>
121
122 #include <netinet/in.h>
123 #include <netinet/tcp.h>
124 #include <arpa/inet.h>
125 #include <rpc/rpc.h>
126 #include <rpc/pmap_clnt.h>
127
128 #include <errno.h>
129 #include <err.h>
130 #include <fcntl.h>
131 #include <grp.h>
132 #include <netdb.h>
133 #include <pwd.h>
134 #include <signal.h>
135 #include <stdio.h>
136 #include <stdlib.h>
137 #include <string.h>
138 #include <syslog.h>
139 #include <tcpd.h>
140 #include <unistd.h>
141 #include <libutil.h>
142 #include <sysexits.h>
143 #include <ctype.h>
144
145 #include "inetd.h"
146 #include "pathnames.h"
147
148 #ifdef IPSEC
149 #include <netinet6/ipsec.h>
150 #ifndef IPSEC_POLICY_IPSEC      /* no ipsec support on old ipsec */
151 #undef IPSEC
152 #endif
153 #endif
154
155 /* wrapper for KAME-special getnameinfo() */
156 #ifndef NI_WITHSCOPEID
157 #define NI_WITHSCOPEID  0
158 #endif
159
160 #ifndef LIBWRAP_ALLOW_FACILITY
161 # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
162 #endif
163 #ifndef LIBWRAP_ALLOW_SEVERITY
164 # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
165 #endif
166 #ifndef LIBWRAP_DENY_FACILITY
167 # define LIBWRAP_DENY_FACILITY LOG_AUTH
168 #endif
169 #ifndef LIBWRAP_DENY_SEVERITY
170 # define LIBWRAP_DENY_SEVERITY LOG_WARNING
171 #endif
172
173 #define ISWRAP(sep)     \
174            ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \
175         && (sep->se_family == AF_INET || sep->se_family == AF_INET6) \
176         && ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \
177             || (sep)->se_socktype == SOCK_DGRAM))
178
179 #ifdef LOGIN_CAP
180 #include <login_cap.h>
181
182 /* see init.c */
183 #define RESOURCE_RC "daemon"
184
185 #endif
186
187 #ifndef MAXCHILD
188 #define MAXCHILD        -1              /* maximum number of this service
189                                            < 0 = no limit */
190 #endif
191
192 #ifndef MAXCPM
193 #define MAXCPM          -1              /* rate limit invocations from a
194                                            single remote address,
195                                            < 0 = no limit */
196 #endif
197
198 #ifndef TOOMANY
199 #define TOOMANY         256             /* don't start more than TOOMANY */
200 #endif
201 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
202 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
203 #define MAX_MAXCHLD     32767           /* max allowable max children */
204
205 #define SIGBLOCK        (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
206
207 void            close_sep __P((struct servtab *));
208 void            flag_signal __P((int));
209 void            flag_config __P((int));
210 void            config __P((void));
211 int             cpmip __P((const struct servtab *, int));
212 void            endconfig __P((void));
213 struct servtab *enter __P((struct servtab *));
214 void            freeconfig __P((struct servtab *));
215 struct servtab *getconfigent __P((void));
216 int             matchservent __P((const char *, const char *, const char *));
217 char           *nextline __P((FILE *));
218 void            addchild __P((struct servtab *, int));
219 void            flag_reapchild __P((int));
220 void            reapchild __P((void));
221 void            enable __P((struct servtab *));
222 void            disable __P((struct servtab *));
223 void            flag_retry __P((int));
224 void            retry __P((void));
225 int             setconfig __P((void));
226 void            setup __P((struct servtab *));
227 #ifdef IPSEC
228 void            ipsecsetup __P((struct servtab *));
229 #endif
230 void            unregisterrpc __P((register struct servtab *sep));
231
232 int     allow_severity;
233 int     deny_severity;
234 int     wrap_ex = 0;
235 int     wrap_bi = 0;
236 int     debug = 0;
237 int     log = 0;
238 int     maxsock;                        /* highest-numbered descriptor */
239 fd_set  allsock;
240 int     options;
241 int     timingout;
242 int     toomany = TOOMANY;
243 int     maxchild = MAXCHILD;
244 int     maxcpm = MAXCPM;
245 struct  servent *sp;
246 struct  rpcent *rpc;
247 char    *hostname = NULL;
248 struct  sockaddr_in *bind_sa4;
249 int     no_v4bind = 1;
250 #ifdef INET6
251 struct  sockaddr_in6 *bind_sa6;
252 int     no_v6bind = 1;
253 #endif
254 int     signalpipe[2];
255 #ifdef SANITY_CHECK
256 int     nsock;
257 #endif
258 uid_t   euid;
259 gid_t   egid;
260 mode_t  mask;
261
262 struct  servtab *servtab;
263
264 extern struct biltin biltins[];
265
266 #define NUMINT  (sizeof(intab) / sizeof(struct inent))
267 const char      *CONFIG = _PATH_INETDCONF;
268 const char      *pid_file = _PATH_INETDPID;
269
270 int
271 getvalue(arg, value, whine)
272         const char *arg, *whine;
273         int  *value;
274 {
275         int  tmp;
276         char *p;
277
278         tmp = strtol(arg, &p, 0);
279         if (tmp < 0 || *p) {
280                 syslog(LOG_ERR, whine, arg);
281                 return 1;                       /* failure */
282         }
283         *value = tmp;
284         return 0;                               /* success */
285 }
286
287 int
288 main(argc, argv)
289         int argc;
290         char *argv[];
291 {
292         struct servtab *sep;
293         struct passwd *pwd;
294         struct group *grp;
295         struct sigaction sa, saalrm, sachld, sahup, sapipe;
296         int tmpint, ch, dofork;
297         pid_t pid;
298         char buf[50];
299 #ifdef LOGIN_CAP
300         login_cap_t *lc = NULL;
301 #endif
302         struct request_info req;
303         int denied;
304         char *service = NULL;
305         union {
306                 struct sockaddr peer_un;
307                 struct sockaddr_in peer_un4;
308                 struct sockaddr_in6 peer_un6;
309                 struct sockaddr_storage peer_max;
310         } p_un;
311 #define peer    p_un.peer_un
312 #define peer4   p_un.peer_un4
313 #define peer6   p_un.peer_un6
314 #define peermax p_un.peer_max
315         int i;
316         struct addrinfo hints, *res;
317         const char *servname;
318         int error;
319
320         openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON);
321
322         while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1)
323                 switch(ch) {
324                 case 'd':
325                         debug = 1;
326                         options |= SO_DEBUG;
327                         break;
328                 case 'l':
329                         log = 1;
330                         break;
331                 case 'R':
332                         getvalue(optarg, &toomany,
333                                 "-R %s: bad value for service invocation rate");
334                         break;
335                 case 'c':
336                         getvalue(optarg, &maxchild,
337                                 "-c %s: bad value for maximum children");
338                         break;
339                 case 'C':
340                         getvalue(optarg, &maxcpm,
341                                 "-C %s: bad value for maximum children/minute");
342                         break;
343                 case 'a':
344                         hostname = optarg;
345                         break;
346                 case 'p':
347                         pid_file = optarg;
348                         break;
349                 case 'w':
350                         wrap_ex++;
351                         break;
352                 case 'W':
353                         wrap_bi++;
354                         break;
355                 case '?':
356                 default:
357                         syslog(LOG_ERR,
358                                 "usage: inetd [-dlwW] [-a address] [-R rate]"
359                                 " [-c maximum] [-C rate]"
360                                 " [-p pidfile] [conf-file]");
361                         exit(EX_USAGE);
362                 }
363         /*
364          * Initialize Bind Addrs.
365          *   When hostname is NULL, wild card bind addrs are obtained from
366          *   getaddrinfo(). But getaddrinfo() requires at least one of
367          *   hostname or servname is non NULL.
368          *   So when hostname is NULL, set dummy value to servname.
369          */
370         servname = (hostname == NULL) ? "discard" /* dummy */ : NULL;
371
372         bzero(&hints, sizeof(struct addrinfo));
373         hints.ai_flags = AI_PASSIVE;
374         hints.ai_family = AF_UNSPEC;
375         error = getaddrinfo(hostname, servname, &hints, &res);
376         if (error != 0) {
377                 syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error));
378                 if (error == EAI_SYSTEM)
379                         syslog(LOG_ERR, "%s", strerror(errno));
380                 exit(EX_USAGE);
381         }
382         do {
383                 if (res->ai_addr == NULL) {
384                         syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
385                         exit(EX_USAGE);
386                 }
387                 switch (res->ai_addr->sa_family) {
388                 case AF_INET:
389                         if (no_v4bind == 0)
390                                 continue;
391                         bind_sa4 = (struct sockaddr_in *)res->ai_addr;
392                         /* init port num in case servname is dummy */
393                         bind_sa4->sin_port = 0;
394                         no_v4bind = 0;
395                         continue;
396 #ifdef INET6
397                 case AF_INET6:
398                         if (no_v6bind == 0)
399                                 continue;
400                         bind_sa6 = (struct sockaddr_in6 *)res->ai_addr;
401                         /* init port num in case servname is dummy */
402                         bind_sa6->sin6_port = 0;
403                         no_v6bind = 0;
404                         continue;
405 #endif
406                 }
407                 if (no_v4bind == 0
408 #ifdef INET6
409                     && no_v6bind == 0
410 #endif
411                     )
412                         break;
413         } while ((res = res->ai_next) != NULL);
414         if (no_v4bind != 0
415 #ifdef INET6
416             && no_v6bind != 0
417 #endif
418             ) {
419                 syslog(LOG_ERR, "-a %s: unknown address family", hostname);
420                 exit(EX_USAGE);
421         }
422
423         euid = geteuid();
424         egid = getegid();
425         umask(mask = umask(0777));
426
427         argc -= optind;
428         argv += optind;
429
430         if (argc > 0)
431                 CONFIG = argv[0];
432         if (debug == 0) {
433                 FILE *fp;
434                 if (daemon(0, 0) < 0) {
435                         syslog(LOG_WARNING, "daemon(0,0) failed: %m");
436                 }
437                 /* From now on we don't want syslog messages going to stderr. */
438                 closelog();
439                 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
440                 /*
441                  * In case somebody has started inetd manually, we need to
442                  * clear the logname, so that old servers run as root do not
443                  * get the user's logname..
444                  */
445                 if (setlogin("") < 0) {
446                         syslog(LOG_WARNING, "cannot clear logname: %m");
447                         /* no big deal if it fails.. */
448                 }
449                 pid = getpid();
450                 fp = fopen(pid_file, "w");
451                 if (fp) {
452                         fprintf(fp, "%ld\n", (long)pid);
453                         fclose(fp);
454                 } else {
455                         syslog(LOG_WARNING, "%s: %m", pid_file);
456                 }
457         }
458         sa.sa_flags = 0;
459         sigemptyset(&sa.sa_mask);
460         sigaddset(&sa.sa_mask, SIGALRM);
461         sigaddset(&sa.sa_mask, SIGCHLD);
462         sigaddset(&sa.sa_mask, SIGHUP);
463         sa.sa_handler = flag_retry;
464         sigaction(SIGALRM, &sa, &saalrm);
465         config();
466         sa.sa_handler = flag_config;
467         sigaction(SIGHUP, &sa, &sahup);
468         sa.sa_handler = flag_reapchild;
469         sigaction(SIGCHLD, &sa, &sachld);
470         sa.sa_handler = SIG_IGN;
471         sigaction(SIGPIPE, &sa, &sapipe);
472
473         {
474                 /* space for daemons to overwrite environment for ps */
475 #define DUMMYSIZE       100
476                 char dummy[DUMMYSIZE];
477
478                 (void)memset(dummy, 'x', DUMMYSIZE - 1);
479                 dummy[DUMMYSIZE - 1] = '\0';
480                 (void)setenv("inetd_dummy", dummy, 1);
481         }
482
483         if (pipe(signalpipe) != 0) {
484                 syslog(LOG_ERR, "pipe: %m");
485                 exit(EX_OSERR);
486         }
487         FD_SET(signalpipe[0], &allsock);
488 #ifdef SANITY_CHECK
489         nsock++;
490 #endif
491         if (signalpipe[0] > maxsock)
492             maxsock = signalpipe[0];
493         if (signalpipe[1] > maxsock)
494             maxsock = signalpipe[1];
495
496         for (;;) {
497             int n, ctrl;
498             fd_set readable;
499
500 #ifdef SANITY_CHECK
501             if (nsock == 0) {
502                 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
503                 exit(EX_SOFTWARE);
504             }
505 #endif
506             readable = allsock;
507             if ((n = select(maxsock + 1, &readable, (fd_set *)0,
508                 (fd_set *)0, (struct timeval *)0)) <= 0) {
509                     if (n < 0 && errno != EINTR) {
510                         syslog(LOG_WARNING, "select: %m");
511                         sleep(1);
512                     }
513                     continue;
514             }
515             /* handle any queued signal flags */
516             if (FD_ISSET(signalpipe[0], &readable)) {
517                 int nsig;
518                 if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) {
519                     syslog(LOG_ERR, "ioctl: %m");
520                     exit(EX_OSERR);
521                 }
522                 while (--nsig >= 0) {
523                     char c;
524                     if (read(signalpipe[0], &c, 1) != 1) {
525                         syslog(LOG_ERR, "read: %m");
526                         exit(EX_OSERR);
527                     }
528                     if (debug)
529                         warnx("handling signal flag %c", c);
530                     switch(c) {
531                     case 'A': /* sigalrm */
532                         retry();
533                         break;
534                     case 'C': /* sigchld */
535                         reapchild();
536                         break;
537                     case 'H': /* sighup */
538                         config();
539                         break;
540                     }
541                 }
542             }
543             for (sep = servtab; n && sep; sep = sep->se_next)
544                 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
545                     n--;
546                     if (debug)
547                             warnx("someone wants %s", sep->se_service);
548                     if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
549                             i = 1;
550                             if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
551                                     syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m");
552                             ctrl = accept(sep->se_fd, (struct sockaddr *)0,
553                                 (socklen_t *)0);
554                             if (debug)
555                                     warnx("accept, ctrl %d", ctrl);
556                             if (ctrl < 0) {
557                                     if (errno != EINTR)
558                                             syslog(LOG_WARNING,
559                                                 "accept (for %s): %m",
560                                                 sep->se_service);
561                                       if (sep->se_accept &&
562                                           sep->se_socktype == SOCK_STREAM)
563                                               close(ctrl);
564                                     continue;
565                             }
566                             i = 0;
567                             if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
568                                     syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m");
569                             if (ioctl(ctrl, FIONBIO, &i) < 0)
570                                     syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m");
571                             if (cpmip(sep, ctrl) < 0) {
572                                 close(ctrl);
573                                 continue;
574                             }
575                     } else
576                             ctrl = sep->se_fd;
577                     if (log && !ISWRAP(sep)) {
578                             char pname[INET6_ADDRSTRLEN] = "unknown";
579                             socklen_t sl;
580                             sl = sizeof peermax;
581                             if (getpeername(ctrl, (struct sockaddr *)
582                                             &peermax, &sl)) {
583                                     sl = sizeof peermax;
584                                     if (recvfrom(ctrl, buf, sizeof(buf),
585                                         MSG_PEEK,
586                                         (struct sockaddr *)&peermax,
587                                         &sl) >= 0) {
588                                       getnameinfo((struct sockaddr *)&peermax,
589                                                   peer.sa_len,
590                                                   pname, sizeof(pname),
591                                                   NULL, 0, 
592                                                   NI_NUMERICHOST|
593                                                   NI_WITHSCOPEID);
594                                     }
595                             } else {
596                                     getnameinfo((struct sockaddr *)&peermax,
597                                                 peer.sa_len,
598                                                 pname, sizeof(pname),
599                                                 NULL, 0, 
600                                                 NI_NUMERICHOST|
601                                                 NI_WITHSCOPEID);
602                             }
603                             syslog(LOG_INFO,"%s from %s", sep->se_service, pname);
604                     }
605                     (void) sigblock(SIGBLOCK);
606                     pid = 0;
607                     /*
608                      * Fork for all external services, builtins which need to
609                      * fork and anything we're wrapping (as wrapping might
610                      * block or use hosts_options(5) twist).
611                      */
612                     dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep);
613                     if (dofork) {
614                             if (sep->se_count++ == 0)
615                                 (void)gettimeofday(&sep->se_time, (struct timezone *)NULL);
616                             else if (toomany > 0 && sep->se_count >= toomany) {
617                                 struct timeval now;
618
619                                 (void)gettimeofday(&now, (struct timezone *)NULL);
620                                 if (now.tv_sec - sep->se_time.tv_sec >
621                                     CNT_INTVL) {
622                                         sep->se_time = now;
623                                         sep->se_count = 1;
624                                 } else {
625                                         syslog(LOG_ERR,
626                         "%s/%s server failing (looping), service terminated",
627                                             sep->se_service, sep->se_proto);
628                                         if (sep->se_accept &&
629                                             sep->se_socktype == SOCK_STREAM)
630                                                 close(ctrl);
631                                         close_sep(sep);
632                                         sigsetmask(0L);
633                                         if (!timingout) {
634                                                 timingout = 1;
635                                                 alarm(RETRYTIME);
636                                         }
637                                         continue;
638                                 }
639                             }
640                             pid = fork();
641                     }
642                     if (pid < 0) {
643                             syslog(LOG_ERR, "fork: %m");
644                             if (sep->se_accept &&
645                                 sep->se_socktype == SOCK_STREAM)
646                                     close(ctrl);
647                             sigsetmask(0L);
648                             sleep(1);
649                             continue;
650                     }
651                     if (pid)
652                         addchild(sep, pid);
653                     sigsetmask(0L);
654                     if (pid == 0) {
655                             if (dofork) {
656                                 if (debug)
657                                         warnx("+ closing from %d", maxsock);
658                                 for (tmpint = maxsock; tmpint > 2; tmpint--)
659                                         if (tmpint != ctrl)
660                                                 (void) close(tmpint);
661                                 sigaction(SIGALRM, &saalrm, (struct sigaction *)0);
662                                 sigaction(SIGCHLD, &sachld, (struct sigaction *)0);
663                                 sigaction(SIGHUP, &sahup, (struct sigaction *)0);
664                                 /* SIGPIPE reset before exec */
665                             }
666                             /*
667                              * Call tcpmux to find the real service to exec.
668                              */
669                             if (sep->se_bi &&
670                                 sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) {
671                                     sep = tcpmux(ctrl);
672                                     if (sep == NULL) {
673                                             close(ctrl);
674                                             _exit(0);
675                                     }
676                             }
677                             if (ISWRAP(sep)) {
678                                 inetd_setproctitle("wrapping", ctrl);
679                                 service = sep->se_server_name ?
680                                     sep->se_server_name : sep->se_service;
681                                 request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL);
682                                 fromhost(&req);
683                                 deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
684                                 allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
685                                 denied = !hosts_access(&req);
686                                 if (denied) {
687                                     syslog(deny_severity,
688                                         "refused connection from %.500s, service %s (%s%s)",
689                                         eval_client(&req), service, sep->se_proto,
690                                         (((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : "");
691                                     if (sep->se_socktype != SOCK_STREAM)
692                                         recv(ctrl, buf, sizeof (buf), 0);
693                                     if (dofork) {
694                                         sleep(1);
695                                         _exit(0);
696                                     }
697                                 }
698                                 if (log) {
699                                     syslog(allow_severity,
700                                         "connection from %.500s, service %s (%s%s)",
701                                         eval_client(&req), service, sep->se_proto,
702                                         (((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : "");
703                                 }
704                             }
705                             if (sep->se_bi) {
706                                 (*sep->se_bi->bi_fn)(ctrl, sep);
707                             } else {
708                                 if (debug)
709                                         warnx("%d execl %s",
710                                                 getpid(), sep->se_server);
711                                 dup2(ctrl, 0);
712                                 close(ctrl);
713                                 dup2(0, 1);
714                                 dup2(0, 2);
715                                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
716                                         syslog(LOG_ERR,
717                                             "%s/%s: %s: no such user",
718                                                 sep->se_service, sep->se_proto,
719                                                 sep->se_user);
720                                         if (sep->se_socktype != SOCK_STREAM)
721                                                 recv(0, buf, sizeof (buf), 0);
722                                         _exit(EX_NOUSER);
723                                 }
724                                 grp = NULL;
725                                 if (   sep->se_group != NULL
726                                     && (grp = getgrnam(sep->se_group)) == NULL
727                                    ) {
728                                         syslog(LOG_ERR,
729                                             "%s/%s: %s: no such group",
730                                                 sep->se_service, sep->se_proto,
731                                                 sep->se_group);
732                                         if (sep->se_socktype != SOCK_STREAM)
733                                                 recv(0, buf, sizeof (buf), 0);
734                                         _exit(EX_NOUSER);
735                                 }
736                                 if (grp != NULL)
737                                         pwd->pw_gid = grp->gr_gid;
738 #ifdef LOGIN_CAP
739                                 if ((lc = login_getclass(sep->se_class)) == NULL) {
740                                         /* error syslogged by getclass */
741                                         syslog(LOG_ERR,
742                                             "%s/%s: %s: login class error",
743                                                 sep->se_service, sep->se_proto,
744                                                 sep->se_class);
745                                         if (sep->se_socktype != SOCK_STREAM)
746                                                 recv(0, buf, sizeof (buf), 0);
747                                         _exit(EX_NOUSER);
748                                 }
749 #endif
750                                 if (setsid() < 0) {
751                                         syslog(LOG_ERR,
752                                                 "%s: can't setsid(): %m",
753                                                  sep->se_service);
754                                         /* _exit(EX_OSERR); not fatal yet */
755                                 }
756 #ifdef LOGIN_CAP
757                                 if (setusercontext(lc, pwd, pwd->pw_uid,
758                                     LOGIN_SETALL) != 0) {
759                                         syslog(LOG_ERR,
760                                          "%s: can't setusercontext(..%s..): %m",
761                                          sep->se_service, sep->se_user);
762                                         _exit(EX_OSERR);
763                                 }
764 #else
765                                 if (pwd->pw_uid) {
766                                         if (setlogin(sep->se_user) < 0) {
767                                                 syslog(LOG_ERR,
768                                                  "%s: can't setlogin(%s): %m",
769                                                  sep->se_service, sep->se_user);
770                                                 /* _exit(EX_OSERR); not yet */
771                                         }
772                                         if (setgid(pwd->pw_gid) < 0) {
773                                                 syslog(LOG_ERR,
774                                                   "%s: can't set gid %d: %m",
775                                                   sep->se_service, pwd->pw_gid);
776                                                 _exit(EX_OSERR);
777                                         }
778                                         (void) initgroups(pwd->pw_name,
779                                                         pwd->pw_gid);
780                                         if (setuid(pwd->pw_uid) < 0) {
781                                                 syslog(LOG_ERR,
782                                                   "%s: can't set uid %d: %m",
783                                                   sep->se_service, pwd->pw_uid);
784                                                 _exit(EX_OSERR);
785                                         }
786                                 }
787 #endif
788                                 sigaction(SIGPIPE, &sapipe,
789                                     (struct sigaction *)0);
790                                 execv(sep->se_server, sep->se_argv);
791                                 syslog(LOG_ERR,
792                                     "cannot execute %s: %m", sep->se_server);
793                                 if (sep->se_socktype != SOCK_STREAM)
794                                         recv(0, buf, sizeof (buf), 0);
795                             }
796                             if (dofork)
797                                 _exit(0);
798                     }
799                     if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
800                             close(ctrl);
801                 }
802         }
803 }
804
805 /*
806  * Add a signal flag to the signal flag queue for later handling
807  */
808
809 void
810 flag_signal(c)
811         int c;
812 {
813         char ch = c;
814
815         if (write(signalpipe[1], &ch, 1) != 1) {
816                 syslog(LOG_ERR, "write: %m");
817                 _exit(EX_OSERR);
818         }
819 }
820
821 /*
822  * Record a new child pid for this service. If we've reached the
823  * limit on children, then stop accepting incoming requests.
824  */
825
826 void
827 addchild(struct servtab *sep, pid_t pid)
828 {
829         if (sep->se_maxchild <= 0)
830                 return;
831 #ifdef SANITY_CHECK
832         if (sep->se_numchild >= sep->se_maxchild) {
833                 syslog(LOG_ERR, "%s: %d >= %d",
834                     __FUNCTION__, sep->se_numchild, sep->se_maxchild);
835                 exit(EX_SOFTWARE);
836         }
837 #endif
838         sep->se_pids[sep->se_numchild++] = pid;
839         if (sep->se_numchild == sep->se_maxchild)
840                 disable(sep);
841 }
842
843 /*
844  * Some child process has exited. See if it's on somebody's list.
845  */
846
847 void
848 flag_reapchild(signo)
849         int signo __unused;
850 {
851         flag_signal('C');
852 }
853
854 void
855 reapchild()
856 {
857         int k, status;
858         pid_t pid;
859         struct servtab *sep;
860
861         for (;;) {
862                 pid = wait3(&status, WNOHANG, (struct rusage *)0);
863                 if (pid <= 0)
864                         break;
865                 if (debug)
866                         warnx("%d reaped, status %#x", pid, status);
867                 for (sep = servtab; sep; sep = sep->se_next) {
868                         for (k = 0; k < sep->se_numchild; k++)
869                                 if (sep->se_pids[k] == pid)
870                                         break;
871                         if (k == sep->se_numchild)
872                                 continue;
873                         if (sep->se_numchild == sep->se_maxchild)
874                                 enable(sep);
875                         sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
876                         if (status)
877                                 syslog(LOG_WARNING,
878                                     "%s[%d]: exit status 0x%x",
879                                     sep->se_server, pid, status);
880                         break;
881                 }
882         }
883 }
884
885 void
886 flag_config(signo)
887         int signo __unused;
888 {
889         flag_signal('H');
890 }
891
892 void
893 config()
894 {
895         struct servtab *sep, *new, **sepp;
896         long omask;
897
898         if (!setconfig()) {
899                 syslog(LOG_ERR, "%s: %m", CONFIG);
900                 return;
901         }
902         for (sep = servtab; sep; sep = sep->se_next)
903                 sep->se_checked = 0;
904         while ((new = getconfigent())) {
905                 if (getpwnam(new->se_user) == NULL) {
906                         syslog(LOG_ERR,
907                                 "%s/%s: no such user '%s', service ignored",
908                                 new->se_service, new->se_proto, new->se_user);
909                         continue;
910                 }
911                 if (new->se_group && getgrnam(new->se_group) == NULL) {
912                         syslog(LOG_ERR,
913                                 "%s/%s: no such group '%s', service ignored",
914                                 new->se_service, new->se_proto, new->se_group);
915                         continue;
916                 }
917 #ifdef LOGIN_CAP
918                 if (login_getclass(new->se_class) == NULL) {
919                         /* error syslogged by getclass */
920                         syslog(LOG_ERR,
921                                 "%s/%s: %s: login class error, service ignored",
922                                 new->se_service, new->se_proto, new->se_class);
923                         continue;
924                 }
925 #endif
926                 for (sep = servtab; sep; sep = sep->se_next)
927                         if (strcmp(sep->se_service, new->se_service) == 0 &&
928                             strcmp(sep->se_proto, new->se_proto) == 0 &&
929                             sep->se_socktype == new->se_socktype &&
930                             sep->se_family == new->se_family)
931                                 break;
932                 if (sep != 0) {
933                         int i;
934
935 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
936                         omask = sigblock(SIGBLOCK);
937                         if (sep->se_nomapped != new->se_nomapped) {
938                                 sep->se_nomapped = new->se_nomapped;
939                                 sep->se_reset = 1;
940                         }
941                         /* copy over outstanding child pids */
942                         if (sep->se_maxchild > 0 && new->se_maxchild > 0) {
943                                 new->se_numchild = sep->se_numchild;
944                                 if (new->se_numchild > new->se_maxchild)
945                                         new->se_numchild = new->se_maxchild;
946                                 memcpy(new->se_pids, sep->se_pids,
947                                     new->se_numchild * sizeof(*new->se_pids));
948                         }
949                         SWAP(sep->se_pids, new->se_pids);
950                         sep->se_maxchild = new->se_maxchild;
951                         sep->se_numchild = new->se_numchild;
952                         sep->se_maxcpm = new->se_maxcpm;
953                         sep->se_bi = new->se_bi;
954                         /* might need to turn on or off service now */
955                         if (sep->se_fd >= 0) {
956                               if (sep->se_maxchild > 0
957                                   && sep->se_numchild == sep->se_maxchild) {
958                                       if (FD_ISSET(sep->se_fd, &allsock))
959                                           disable(sep);
960                               } else {
961                                       if (!FD_ISSET(sep->se_fd, &allsock))
962                                           enable(sep);
963                               }
964                         }
965                         sep->se_accept = new->se_accept;
966                         SWAP(sep->se_user, new->se_user);
967                         SWAP(sep->se_group, new->se_group);
968 #ifdef LOGIN_CAP
969                         SWAP(sep->se_class, new->se_class);
970 #endif
971                         SWAP(sep->se_server, new->se_server);
972                         SWAP(sep->se_server_name, new->se_server_name);
973                         for (i = 0; i < MAXARGV; i++)
974                                 SWAP(sep->se_argv[i], new->se_argv[i]);
975 #ifdef IPSEC
976                         SWAP(sep->se_policy, new->se_policy);
977                         ipsecsetup(sep);
978 #endif
979                         sigsetmask(omask);
980                         freeconfig(new);
981                         if (debug)
982                                 print_service("REDO", sep);
983                 } else {
984                         sep = enter(new);
985                         if (debug)
986                                 print_service("ADD ", sep);
987                 }
988                 sep->se_checked = 1;
989                 if (ISMUX(sep)) {
990                         sep->se_fd = -1;
991                         continue;
992                 }
993                 switch (sep->se_family) {
994                 case AF_INET:
995                         if (no_v4bind != 0) {
996                                 sep->se_fd = -1;
997                                 continue;
998                         }
999                         break;
1000 #ifdef INET6
1001                 case AF_INET6:
1002                         if (no_v6bind != 0) {
1003                                 sep->se_fd = -1;
1004                                 continue;
1005                         }
1006                         break;
1007 #endif
1008                 }
1009                 if (!sep->se_rpc) {
1010                         if (sep->se_family != AF_UNIX) {
1011                                 sp = getservbyname(sep->se_service, sep->se_proto);
1012                                 if (sp == 0) {
1013                                         syslog(LOG_ERR, "%s/%s: unknown service",
1014                                         sep->se_service, sep->se_proto);
1015                                         sep->se_checked = 0;
1016                                         continue;
1017                                 }
1018                         }
1019                         switch (sep->se_family) {
1020                         case AF_INET:
1021                                 if (sp->s_port != sep->se_ctrladdr4.sin_port) {
1022                                         sep->se_ctrladdr4.sin_port =
1023                                                 sp->s_port;
1024                                         sep->se_reset = 1;
1025                                 }
1026                                 break;
1027 #ifdef INET6
1028                         case AF_INET6:
1029                                 if (sp->s_port !=
1030                                     sep->se_ctrladdr6.sin6_port) {
1031                                         sep->se_ctrladdr6.sin6_port =
1032                                                 sp->s_port;
1033                                         sep->se_reset = 1;
1034                                 }
1035                                 break;
1036 #endif
1037                         }
1038                         if (sep->se_reset != 0 && sep->se_fd >= 0)
1039                                 close_sep(sep);
1040                 } else {
1041                         rpc = getrpcbyname(sep->se_service);
1042                         if (rpc == 0) {
1043                                 syslog(LOG_ERR, "%s/%s unknown RPC service",
1044                                         sep->se_service, sep->se_proto);
1045                                 if (sep->se_fd != -1)
1046                                         (void) close(sep->se_fd);
1047                                 sep->se_fd = -1;
1048                                         continue;
1049                         }
1050                         if (rpc->r_number != sep->se_rpc_prog) {
1051                                 if (sep->se_rpc_prog)
1052                                         unregisterrpc(sep);
1053                                 sep->se_rpc_prog = rpc->r_number;
1054                                 if (sep->se_fd != -1)
1055                                         (void) close(sep->se_fd);
1056                                 sep->se_fd = -1;
1057                         }
1058                 }
1059                 if (sep->se_fd == -1)
1060                         setup(sep);
1061         }
1062         endconfig();
1063         /*
1064          * Purge anything not looked at above.
1065          */
1066         omask = sigblock(SIGBLOCK);
1067         sepp = &servtab;
1068         while ((sep = *sepp)) {
1069                 if (sep->se_checked) {
1070                         sepp = &sep->se_next;
1071                         continue;
1072                 }
1073                 *sepp = sep->se_next;
1074                 if (sep->se_fd >= 0)
1075                         close_sep(sep);
1076                 if (debug)
1077                         print_service("FREE", sep);
1078                 if (sep->se_rpc && sep->se_rpc_prog > 0)
1079                         unregisterrpc(sep);
1080                 freeconfig(sep);
1081                 free(sep);
1082         }
1083         (void) sigsetmask(omask);
1084 }
1085
1086 void
1087 unregisterrpc(sep)
1088         struct servtab *sep;
1089 {
1090         u_int i;
1091         struct servtab *sepp;
1092         long omask;
1093
1094         omask = sigblock(SIGBLOCK);
1095         for (sepp = servtab; sepp; sepp = sepp->se_next) {
1096                 if (sepp == sep)
1097                         continue;
1098                 if (sep->se_checked == 0 ||
1099                     !sepp->se_rpc ||
1100                     sep->se_rpc_prog != sepp->se_rpc_prog)
1101                         continue;
1102                 return;
1103         }
1104         if (debug)
1105                 print_service("UNREG", sep);
1106         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
1107                 pmap_unset(sep->se_rpc_prog, i);
1108         if (sep->se_fd != -1)
1109                 (void) close(sep->se_fd);
1110         sep->se_fd = -1;
1111         (void) sigsetmask(omask);
1112 }
1113
1114 void
1115 flag_retry(signo)
1116         int signo __unused;
1117 {
1118         flag_signal('A');
1119 }
1120
1121 void
1122 retry()
1123 {
1124         struct servtab *sep;
1125
1126         timingout = 0;
1127         for (sep = servtab; sep; sep = sep->se_next)
1128                 if (sep->se_fd == -1 && !ISMUX(sep))
1129                         setup(sep);
1130 }
1131
1132 void
1133 setup(sep)
1134         struct servtab *sep;
1135 {
1136         int on = 1;
1137
1138         if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
1139                 if (debug)
1140                         warn("socket failed on %s/%s",
1141                                 sep->se_service, sep->se_proto);
1142                 syslog(LOG_ERR, "%s/%s: socket: %m",
1143                     sep->se_service, sep->se_proto);
1144                 return;
1145         }
1146 #define turnon(fd, opt) \
1147 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
1148         if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
1149             turnon(sep->se_fd, SO_DEBUG) < 0)
1150                 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
1151         if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
1152                 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
1153 #ifdef SO_PRIVSTATE
1154         if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
1155                 syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
1156 #endif
1157         /* tftpd opens a new connection then needs more infos */
1158         if ((sep->se_family == AF_INET6) &&
1159             (strcmp(sep->se_proto, "udp") == 0) &&
1160             (sep->se_accept == 0) &&
1161             (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO,
1162                         (char *)&on, sizeof (on)) < 0))
1163                 syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m");
1164 #ifdef IPV6_BINDV6ONLY
1165         if (sep->se_family == AF_INET6) {
1166                 int flag = sep->se_nomapped ? 1 : 0;
1167                 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
1168                                (char *)&flag, sizeof (flag)) < 0)
1169                         syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m");
1170         }
1171 #endif /* IPV6_BINDV6ONLY */
1172 #undef turnon
1173         if (sep->se_type == TTCP_TYPE)
1174                 if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
1175                     (char *)&on, sizeof (on)) < 0)
1176                         syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
1177 #ifdef IPV6_FAITH
1178         if (sep->se_type == FAITH_TYPE) {
1179                 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on,
1180                                 sizeof(on)) < 0) {
1181                         syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
1182                 }
1183         }
1184 #endif
1185 #ifdef IPSEC
1186         ipsecsetup(sep);
1187 #endif
1188         if (sep->se_family == AF_UNIX) {
1189                 (void) unlink(sep->se_ctrladdr_un.sun_path);
1190                 umask(0777); /* Make socket with conservative permissions */
1191         }
1192         if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
1193             sep->se_ctrladdr_size) < 0) {
1194                 if (debug)
1195                         warn("bind failed on %s/%s",
1196                                 sep->se_service, sep->se_proto);
1197                 syslog(LOG_ERR, "%s/%s: bind: %m",
1198                     sep->se_service, sep->se_proto);
1199                 (void) close(sep->se_fd);
1200                 sep->se_fd = -1;
1201                 if (!timingout) {
1202                         timingout = 1;
1203                         alarm(RETRYTIME);
1204                 }
1205                 if (sep->se_family == AF_UNIX)
1206                         umask(mask);
1207                 return;
1208         }
1209         if (sep->se_family == AF_UNIX) {
1210                 /* Ick - fch{own,mod} don't work on Unix domain sockets */
1211                 if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0)
1212                         syslog(LOG_ERR, "chown socket: %m");
1213                 if (chmod(sep->se_service, sep->se_sockmode) < 0)
1214                         syslog(LOG_ERR, "chmod socket: %m");
1215                 umask(mask);
1216         }
1217         if (sep->se_rpc) {
1218                 u_int i;
1219                 socklen_t len = sep->se_ctrladdr_size;
1220
1221                 if (sep->se_family != AF_INET) {
1222                         syslog(LOG_ERR,
1223                                "%s/%s: unsupported address family for rpc",
1224                                sep->se_service, sep->se_proto);
1225                         (void) close(sep->se_fd);
1226                         sep->se_fd = -1;
1227                         return;
1228                 }
1229                 if (getsockname(sep->se_fd,
1230                                 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
1231                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
1232                                sep->se_service, sep->se_proto);
1233                         (void) close(sep->se_fd);
1234                         sep->se_fd = -1;
1235                         return;
1236                 }
1237                 if (debug)
1238                         print_service("REG ", sep);
1239                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
1240                         pmap_unset(sep->se_rpc_prog, i);
1241                         pmap_set(sep->se_rpc_prog, i,
1242                                  (sep->se_socktype == SOCK_DGRAM)
1243                                  ? IPPROTO_UDP : IPPROTO_TCP,
1244                                  ntohs(sep->se_ctrladdr4.sin_port));
1245                 }
1246         }
1247         if (sep->se_socktype == SOCK_STREAM)
1248                 listen(sep->se_fd, 64);
1249         enable(sep);
1250         if (debug) {
1251                 warnx("registered %s on %d",
1252                         sep->se_server, sep->se_fd);
1253         }
1254 }
1255
1256 #ifdef IPSEC
1257 void
1258 ipsecsetup(sep)
1259         struct servtab *sep;
1260 {
1261         char *buf;
1262         char *policy_in = NULL;
1263         char *policy_out = NULL;
1264         int level;
1265         int opt;
1266
1267         switch (sep->se_family) {
1268         case AF_INET:
1269                 level = IPPROTO_IP;
1270                 opt = IP_IPSEC_POLICY;
1271                 break;
1272 #ifdef INET6
1273         case AF_INET6:
1274                 level = IPPROTO_IPV6;
1275                 opt = IPV6_IPSEC_POLICY;
1276                 break;
1277 #endif
1278         default:
1279                 return;
1280         }
1281
1282         if (!sep->se_policy || sep->se_policy[0] == '\0') {
1283                 static char def_in[] = "in entrust", def_out[] = "out entrust";
1284                 policy_in = def_in;
1285                 policy_out = def_out;
1286         } else {
1287                 if (!strncmp("in", sep->se_policy, 2))
1288                         policy_in = sep->se_policy;
1289                 else if (!strncmp("out", sep->se_policy, 3))
1290                         policy_out = sep->se_policy;
1291                 else {
1292                         syslog(LOG_ERR, "invalid security policy \"%s\"",
1293                                 sep->se_policy);
1294                         return;
1295                 }
1296         }
1297
1298         if (policy_in != NULL) {
1299                 buf = ipsec_set_policy(policy_in, strlen(policy_in));
1300                 if (buf != NULL) {
1301                         if (setsockopt(sep->se_fd, level, opt,
1302                                         buf, ipsec_get_policylen(buf)) < 0 &&
1303                             debug != 0)
1304                                 warnx("%s/%s: ipsec initialization failed; %s",
1305                                       sep->se_service, sep->se_proto,
1306                                       policy_in);
1307                         free(buf);
1308                 } else
1309                         syslog(LOG_ERR, "invalid security policy \"%s\"",
1310                                 policy_in);
1311         }
1312         if (policy_out != NULL) {
1313                 buf = ipsec_set_policy(policy_out, strlen(policy_out));
1314                 if (buf != NULL) {
1315                         if (setsockopt(sep->se_fd, level, opt,
1316                                         buf, ipsec_get_policylen(buf)) < 0 &&
1317                             debug != 0)
1318                                 warnx("%s/%s: ipsec initialization failed; %s",
1319                                       sep->se_service, sep->se_proto,
1320                                       policy_out);
1321                         free(buf);
1322                 } else
1323                         syslog(LOG_ERR, "invalid security policy \"%s\"",
1324                                 policy_out);
1325         }
1326 }
1327 #endif
1328
1329 /*
1330  * Finish with a service and its socket.
1331  */
1332 void
1333 close_sep(sep)
1334         struct servtab *sep;
1335 {
1336         if (sep->se_fd >= 0) {
1337                 if (FD_ISSET(sep->se_fd, &allsock))
1338                         disable(sep);
1339                 (void) close(sep->se_fd);
1340                 sep->se_fd = -1;
1341         }
1342         sep->se_count = 0;
1343         sep->se_numchild = 0;   /* forget about any existing children */
1344 }
1345
1346 int
1347 matchservent(name1, name2, proto)
1348         const char *name1, *name2, *proto;
1349 {
1350         char **alias, *p;
1351         struct servent *se;
1352
1353         if (strcmp(proto, "unix") == 0) {
1354                 if ((p = strrchr(name1, '/')) != NULL)
1355                         name1 = p + 1;
1356                 if ((p = strrchr(name2, '/')) != NULL)
1357                         name2 = p + 1;
1358         }
1359         if (strcmp(name1, name2) == 0)
1360                 return(1);
1361         if ((se = getservbyname(name1, proto)) != NULL) {
1362                 if (strcmp(name2, se->s_name) == 0)
1363                         return(1);
1364                 for (alias = se->s_aliases; *alias; alias++)
1365                         if (strcmp(name2, *alias) == 0)
1366                                 return(1);
1367         }
1368         return(0);
1369 }
1370
1371 struct servtab *
1372 enter(cp)
1373         struct servtab *cp;
1374 {
1375         struct servtab *sep;
1376         long omask;
1377
1378         sep = (struct servtab *)malloc(sizeof (*sep));
1379         if (sep == (struct servtab *)0) {
1380                 syslog(LOG_ERR, "malloc: %m");
1381                 exit(EX_OSERR);
1382         }
1383         *sep = *cp;
1384         sep->se_fd = -1;
1385         omask = sigblock(SIGBLOCK);
1386         sep->se_next = servtab;
1387         servtab = sep;
1388         sigsetmask(omask);
1389         return (sep);
1390 }
1391
1392 void
1393 enable(sep)
1394         struct servtab *sep;
1395 {
1396         if (debug)
1397                 warnx(
1398                     "enabling %s, fd %d", sep->se_service, sep->se_fd);
1399 #ifdef SANITY_CHECK
1400         if (sep->se_fd < 0) {
1401                 syslog(LOG_ERR,
1402                     "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1403                 exit(EX_SOFTWARE);
1404         }
1405         if (ISMUX(sep)) {
1406                 syslog(LOG_ERR,
1407                     "%s: %s: is mux", __FUNCTION__, sep->se_service);
1408                 exit(EX_SOFTWARE);
1409         }
1410         if (FD_ISSET(sep->se_fd, &allsock)) {
1411                 syslog(LOG_ERR,
1412                     "%s: %s: not off", __FUNCTION__, sep->se_service);
1413                 exit(EX_SOFTWARE);
1414         }
1415         nsock++;
1416 #endif
1417         FD_SET(sep->se_fd, &allsock);
1418         if (sep->se_fd > maxsock)
1419                 maxsock = sep->se_fd;
1420 }
1421
1422 void
1423 disable(sep)
1424         struct servtab *sep;
1425 {
1426         if (debug)
1427                 warnx(
1428                     "disabling %s, fd %d", sep->se_service, sep->se_fd);
1429 #ifdef SANITY_CHECK
1430         if (sep->se_fd < 0) {
1431                 syslog(LOG_ERR,
1432                     "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1433                 exit(EX_SOFTWARE);
1434         }
1435         if (ISMUX(sep)) {
1436                 syslog(LOG_ERR,
1437                     "%s: %s: is mux", __FUNCTION__, sep->se_service);
1438                 exit(EX_SOFTWARE);
1439         }
1440         if (!FD_ISSET(sep->se_fd, &allsock)) {
1441                 syslog(LOG_ERR,
1442                     "%s: %s: not on", __FUNCTION__, sep->se_service);
1443                 exit(EX_SOFTWARE);
1444         }
1445         if (nsock == 0) {
1446                 syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
1447                 exit(EX_SOFTWARE);
1448         }
1449         nsock--;
1450 #endif
1451         FD_CLR(sep->se_fd, &allsock);
1452         if (sep->se_fd == maxsock)
1453                 maxsock--;
1454 }
1455
1456 FILE    *fconfig = NULL;
1457 struct  servtab serv;
1458 char    line[LINE_MAX];
1459
1460 int
1461 setconfig()
1462 {
1463
1464         if (fconfig != NULL) {
1465                 fseek(fconfig, 0L, SEEK_SET);
1466                 return (1);
1467         }
1468         fconfig = fopen(CONFIG, "r");
1469         return (fconfig != NULL);
1470 }
1471
1472 void
1473 endconfig()
1474 {
1475         if (fconfig) {
1476                 (void) fclose(fconfig);
1477                 fconfig = NULL;
1478         }
1479 }
1480
1481 struct servtab *
1482 getconfigent()
1483 {
1484         struct servtab *sep = &serv;
1485         int argc;
1486         char *cp, *arg, *s;
1487         char *versp;
1488         static char TCPMUX_TOKEN[] = "tcpmux/";
1489 #define MUX_LEN         (sizeof(TCPMUX_TOKEN)-1)
1490 #ifdef IPSEC
1491         char *policy = NULL;
1492 #endif
1493         int v4bind = 0;
1494 #ifdef INET6
1495         int v6bind = 0;
1496 #endif
1497
1498 more:
1499         while ((cp = nextline(fconfig)) != NULL) {
1500 #ifdef IPSEC
1501                 /* lines starting with #@ is not a comment, but the policy */
1502                 if (cp[0] == '#' && cp[1] == '@') {
1503                         char *p;
1504                         for (p = cp + 2; p && *p && isspace(*p); p++)
1505                                 ;
1506                         if (*p == '\0') {
1507                                 if (policy)
1508                                         free(policy);
1509                                 policy = NULL;
1510                         } else if (ipsec_get_policylen(p) >= 0) {
1511                                 if (policy)
1512                                         free(policy);
1513                                 policy = newstr(p);
1514                         } else {
1515                                 syslog(LOG_ERR,
1516                                         "%s: invalid ipsec policy \"%s\"",
1517                                         CONFIG, p);
1518                                 exit(EX_CONFIG);
1519                         }
1520                 }
1521 #endif
1522                 if (*cp == '#' || *cp == '\0')
1523                         continue;
1524                 break;
1525         }
1526         if (cp == NULL)
1527                 return ((struct servtab *)0);
1528         /*
1529          * clear the static buffer, since some fields (se_ctrladdr,
1530          * for example) don't get initialized here.
1531          */
1532         memset(sep, 0, sizeof *sep);
1533         arg = skip(&cp);
1534         if (cp == NULL) {
1535                 /* got an empty line containing just blanks/tabs. */
1536                 goto more;
1537         }
1538         if (arg[0] == ':') { /* :user:group:perm: */
1539                 char *user, *group, *perm;
1540                 struct passwd *pw;
1541                 struct group *gr;
1542                 user = arg+1;
1543                 if ((group = strchr(user, ':')) == NULL) {
1544                         syslog(LOG_ERR, "no group after user '%s'", user);
1545                         goto more;
1546                 }
1547                 *group++ = '\0';
1548                 if ((perm = strchr(group, ':')) == NULL) {
1549                         syslog(LOG_ERR, "no mode after group '%s'", group);
1550                         goto more;
1551                 }
1552                 *perm++ = '\0';
1553                 if ((pw = getpwnam(user)) == NULL) {
1554                         syslog(LOG_ERR, "no such user '%s'", user);
1555                         goto more;
1556                 }
1557                 sep->se_sockuid = pw->pw_uid;
1558                 if ((gr = getgrnam(group)) == NULL) {
1559                         syslog(LOG_ERR, "no such user '%s'", group);
1560                         goto more;
1561                 }
1562                 sep->se_sockgid = gr->gr_gid;
1563                 sep->se_sockmode = strtol(perm, &arg, 8);
1564                 if (*arg != ':') {
1565                         syslog(LOG_ERR, "bad mode '%s'", perm);
1566                         goto more;
1567                 }
1568                 *arg++ = '\0';
1569         } else {
1570                 sep->se_sockuid = euid;
1571                 sep->se_sockgid = egid;
1572                 sep->se_sockmode = 0200;
1573         }
1574         if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1575                 char *c = arg + MUX_LEN;
1576                 if (*c == '+') {
1577                         sep->se_type = MUXPLUS_TYPE;
1578                         c++;
1579                 } else
1580                         sep->se_type = MUX_TYPE;
1581                 sep->se_service = newstr(c);
1582         } else {
1583                 sep->se_service = newstr(arg);
1584                 sep->se_type = NORM_TYPE;
1585         }
1586         arg = sskip(&cp);
1587         if (strcmp(arg, "stream") == 0)
1588                 sep->se_socktype = SOCK_STREAM;
1589         else if (strcmp(arg, "dgram") == 0)
1590                 sep->se_socktype = SOCK_DGRAM;
1591         else if (strcmp(arg, "rdm") == 0)
1592                 sep->se_socktype = SOCK_RDM;
1593         else if (strcmp(arg, "seqpacket") == 0)
1594                 sep->se_socktype = SOCK_SEQPACKET;
1595         else if (strcmp(arg, "raw") == 0)
1596                 sep->se_socktype = SOCK_RAW;
1597         else
1598                 sep->se_socktype = -1;
1599
1600         arg = sskip(&cp);
1601         if (strncmp(arg, "tcp", 3) == 0) {
1602                 sep->se_proto = newstr(strsep(&arg, "/"));
1603                 if (arg != NULL) {
1604                         if (strcmp(arg, "ttcp") == 0)
1605                                 sep->se_type = TTCP_TYPE;
1606                         else if (strcmp(arg, "faith") == 0)
1607                                 sep->se_type = FAITH_TYPE;
1608                 }
1609         } else {
1610                 if (sep->se_type == NORM_TYPE &&
1611                     strncmp(arg, "faith/", 6) == 0) {
1612                         arg += 6;
1613                         sep->se_type = FAITH_TYPE;
1614                 }
1615                 sep->se_proto = newstr(arg);
1616         }
1617         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1618                 if (no_v4bind != 0) {
1619                         syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
1620                                sep->se_service);
1621                         freeconfig(sep);
1622                         goto more;
1623                 }
1624                 memmove(sep->se_proto, sep->se_proto + 4,
1625                     strlen(sep->se_proto) + 1 - 4);
1626                 sep->se_rpc = 1;
1627                 sep->se_rpc_prog = sep->se_rpc_lowvers =
1628                         sep->se_rpc_lowvers = 0;
1629                 memcpy(&sep->se_ctrladdr4, bind_sa4,
1630                        sizeof(sep->se_ctrladdr4));
1631                 if ((versp = rindex(sep->se_service, '/'))) {
1632                         *versp++ = '\0';
1633                         switch (sscanf(versp, "%d-%d",
1634                                        &sep->se_rpc_lowvers,
1635                                        &sep->se_rpc_highvers)) {
1636                         case 2:
1637                                 break;
1638                         case 1:
1639                                 sep->se_rpc_highvers =
1640                                         sep->se_rpc_lowvers;
1641                                 break;
1642                         default:
1643                                 syslog(LOG_ERR,
1644                                         "bad RPC version specifier; %s",
1645                                         sep->se_service);
1646                                 freeconfig(sep);
1647                                 goto more;
1648                         }
1649                 }
1650                 else {
1651                         sep->se_rpc_lowvers =
1652                                 sep->se_rpc_highvers = 1;
1653                 }
1654         }
1655         sep->se_nomapped = 0;
1656         while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) {
1657 #ifdef INET6
1658                 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') {
1659                         if (no_v6bind != 0) {
1660                                 syslog(LOG_NOTICE, "IPv6 bind is ignored for %s",
1661                                        sep->se_service);
1662                                 freeconfig(sep);
1663                                 goto more;
1664                         }
1665                         sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
1666                         v6bind = 1;
1667                         continue;
1668                 }
1669 #endif
1670                 if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
1671                         sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
1672                         v4bind = 1;
1673                         continue;
1674                 }
1675                 /* illegal version num */
1676                 syslog(LOG_ERR, "bad IP version for %s", sep->se_proto);
1677                 freeconfig(sep);
1678                 goto more;
1679         }
1680         if (strcmp(sep->se_proto, "unix") == 0) {
1681                 sep->se_family = AF_UNIX;
1682         } else
1683 #ifdef INET6
1684         if (v6bind != 0) {
1685                 sep->se_family = AF_INET6;
1686                 if (v4bind == 0 || no_v4bind != 0)
1687                         sep->se_nomapped = 1;
1688         } else
1689 #endif
1690         { /* default to v4 bind if not v6 bind */
1691                 if (no_v4bind != 0) {
1692                         syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
1693                                sep->se_service);
1694                         freeconfig(sep);
1695                         goto more;
1696                 }
1697                 sep->se_family = AF_INET;
1698         }
1699         /* init ctladdr */
1700         switch(sep->se_family) {
1701         case AF_INET:
1702                 memcpy(&sep->se_ctrladdr4, bind_sa4,
1703                        sizeof(sep->se_ctrladdr4));
1704                 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4);
1705                 break;
1706 #ifdef INET6
1707         case AF_INET6:
1708                 memcpy(&sep->se_ctrladdr6, bind_sa6,
1709                        sizeof(sep->se_ctrladdr6));
1710                 sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6);
1711                 break;
1712 #endif
1713         case AF_UNIX:
1714                 if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) {
1715                         syslog(LOG_ERR, 
1716                             "domain socket pathname too long for service %s",
1717                             sep->se_service);
1718                         goto more;
1719                 }
1720                 memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr));
1721                 sep->se_ctrladdr_un.sun_family = sep->se_family;
1722                 sep->se_ctrladdr_un.sun_len = strlen(sep->se_service);
1723                 strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service);
1724                 sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un);
1725         }
1726         arg = sskip(&cp);
1727         if (!strncmp(arg, "wait", 4))
1728                 sep->se_accept = 0;
1729         else if (!strncmp(arg, "nowait", 6))
1730                 sep->se_accept = 1;
1731         else {
1732                 syslog(LOG_ERR,
1733                         "%s: bad wait/nowait for service %s",
1734                         CONFIG, sep->se_service);
1735                 goto more;
1736         }
1737         sep->se_maxchild = -1;
1738         sep->se_maxcpm = -1;
1739         if ((s = strchr(arg, '/')) != NULL) {
1740                 char *eptr;
1741                 u_long val;
1742
1743                 val = strtoul(s + 1, &eptr, 10);
1744                 if (eptr == s + 1 || val > MAX_MAXCHLD) {
1745                         syslog(LOG_ERR,
1746                                 "%s: bad max-child for service %s",
1747                                 CONFIG, sep->se_service);
1748                         goto more;
1749                 }
1750                 if (debug)
1751                         if (!sep->se_accept && val != 1)
1752                                 warnx("maxchild=%lu for wait service %s"
1753                                     " not recommended", val, sep->se_service);
1754                 sep->se_maxchild = val;
1755                 if (*eptr == '/')
1756                         sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
1757                 /*
1758                  * explicitly do not check for \0 for future expansion /
1759                  * backwards compatibility
1760                  */
1761         }
1762         if (ISMUX(sep)) {
1763                 /*
1764                  * Silently enforce "nowait" mode for TCPMUX services
1765                  * since they don't have an assigned port to listen on.
1766                  */
1767                 sep->se_accept = 1;
1768                 if (strcmp(sep->se_proto, "tcp")) {
1769                         syslog(LOG_ERR,
1770                                 "%s: bad protocol for tcpmux service %s",
1771                                 CONFIG, sep->se_service);
1772                         goto more;
1773                 }
1774                 if (sep->se_socktype != SOCK_STREAM) {
1775                         syslog(LOG_ERR,
1776                                 "%s: bad socket type for tcpmux service %s",
1777                                 CONFIG, sep->se_service);
1778                         goto more;
1779                 }
1780         }
1781         sep->se_user = newstr(sskip(&cp));
1782 #ifdef LOGIN_CAP
1783         if ((s = strrchr(sep->se_user, '/')) != NULL) {
1784                 *s = '\0';
1785                 sep->se_class = newstr(s + 1);
1786         } else
1787                 sep->se_class = newstr(RESOURCE_RC);
1788 #endif
1789         if ((s = strrchr(sep->se_user, ':')) != NULL) {
1790                 *s = '\0';
1791                 sep->se_group = newstr(s + 1);
1792         } else
1793                 sep->se_group = NULL;
1794         sep->se_server = newstr(sskip(&cp));
1795         if ((sep->se_server_name = rindex(sep->se_server, '/')))
1796                 sep->se_server_name++;
1797         if (strcmp(sep->se_server, "internal") == 0) {
1798                 struct biltin *bi;
1799
1800                 for (bi = biltins; bi->bi_service; bi++)
1801                         if (bi->bi_socktype == sep->se_socktype &&
1802                             matchservent(bi->bi_service, sep->se_service,
1803                             sep->se_proto))
1804                                 break;
1805                 if (bi->bi_service == 0) {
1806                         syslog(LOG_ERR, "internal service %s unknown",
1807                                 sep->se_service);
1808                         goto more;
1809                 }
1810                 sep->se_accept = 1;     /* force accept mode for built-ins */
1811                 sep->se_bi = bi;
1812         } else
1813                 sep->se_bi = NULL;
1814         if (sep->se_maxcpm < 0)
1815                 sep->se_maxcpm = maxcpm;
1816         if (sep->se_maxchild < 0) {     /* apply default max-children */
1817                 if (sep->se_bi && sep->se_bi->bi_maxchild >= 0)
1818                         sep->se_maxchild = sep->se_bi->bi_maxchild;
1819                 else if (sep->se_accept) 
1820                         sep->se_maxchild = maxchild > 0 ? maxchild : 0;
1821                 else
1822                         sep->se_maxchild = 1;
1823         }
1824         if (sep->se_maxchild > 0) {
1825                 sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1826                 if (sep->se_pids == NULL) {
1827                         syslog(LOG_ERR, "malloc: %m");
1828                         exit(EX_OSERR);
1829                 }
1830         }
1831         argc = 0;
1832         for (arg = skip(&cp); cp; arg = skip(&cp))
1833                 if (argc < MAXARGV) {
1834                         sep->se_argv[argc++] = newstr(arg);
1835                 } else {
1836                         syslog(LOG_ERR,
1837                                 "%s: too many arguments for service %s",
1838                                 CONFIG, sep->se_service);
1839                         goto more;
1840                 }
1841         while (argc <= MAXARGV)
1842                 sep->se_argv[argc++] = NULL;
1843 #ifdef IPSEC
1844         sep->se_policy = policy ? newstr(policy) : NULL;
1845 #endif
1846         return (sep);
1847 }
1848
1849 void
1850 freeconfig(cp)
1851         struct servtab *cp;
1852 {
1853         int i;
1854
1855         if (cp->se_service)
1856                 free(cp->se_service);
1857         if (cp->se_proto)
1858                 free(cp->se_proto);
1859         if (cp->se_user)
1860                 free(cp->se_user);
1861         if (cp->se_group)
1862                 free(cp->se_group);
1863 #ifdef LOGIN_CAP
1864         if (cp->se_class)
1865                 free(cp->se_class);
1866 #endif
1867         if (cp->se_server)
1868                 free(cp->se_server);
1869         if (cp->se_pids)
1870                 free(cp->se_pids);
1871         for (i = 0; i < MAXARGV; i++)
1872                 if (cp->se_argv[i])
1873                         free(cp->se_argv[i]);
1874 #ifdef IPSEC
1875         if (cp->se_policy)
1876                 free(cp->se_policy);
1877 #endif
1878 }
1879
1880
1881 /*
1882  * Safe skip - if skip returns null, log a syntax error in the
1883  * configuration file and exit.
1884  */
1885 char *
1886 sskip(cpp)
1887         char **cpp;
1888 {
1889         char *cp;
1890
1891         cp = skip(cpp);
1892         if (cp == NULL) {
1893                 syslog(LOG_ERR, "%s: syntax error", CONFIG);
1894                 exit(EX_DATAERR);
1895         }
1896         return (cp);
1897 }
1898
1899 char *
1900 skip(cpp)
1901         char **cpp;
1902 {
1903         char *cp = *cpp;
1904         char *start;
1905         char quote = '\0';
1906
1907 again:
1908         while (*cp == ' ' || *cp == '\t')
1909                 cp++;
1910         if (*cp == '\0') {
1911                 int c;
1912
1913                 c = getc(fconfig);
1914                 (void) ungetc(c, fconfig);
1915                 if (c == ' ' || c == '\t')
1916                         if ((cp = nextline(fconfig)))
1917                                 goto again;
1918                 *cpp = (char *)0;
1919                 return ((char *)0);
1920         }
1921         if (*cp == '"' || *cp == '\'')
1922                 quote = *cp++;
1923         start = cp;
1924         if (quote)
1925                 while (*cp && *cp != quote)
1926                         cp++;
1927         else
1928                 while (*cp && *cp != ' ' && *cp != '\t')
1929                         cp++;
1930         if (*cp != '\0')
1931                 *cp++ = '\0';
1932         *cpp = cp;
1933         return (start);
1934 }
1935
1936 char *
1937 nextline(fd)
1938         FILE *fd;
1939 {
1940         char *cp;
1941
1942         if (fgets(line, sizeof (line), fd) == NULL)
1943                 return ((char *)0);
1944         cp = strchr(line, '\n');
1945         if (cp)
1946                 *cp = '\0';
1947         return (line);
1948 }
1949
1950 char *
1951 newstr(cp)
1952         const char *cp;
1953 {
1954         char *cr;
1955
1956         if ((cr = strdup(cp != NULL ? cp : "")))
1957                 return (cr);
1958         syslog(LOG_ERR, "strdup: %m");
1959         exit(EX_OSERR);
1960 }
1961
1962 void
1963 inetd_setproctitle(a, s)
1964         const char *a;
1965         int s;
1966 {
1967         socklen_t size;
1968         struct sockaddr_storage ss;
1969         char buf[80], pbuf[INET6_ADDRSTRLEN];
1970
1971         size = sizeof(ss);
1972         if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1973                 getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf),
1974                             NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID);
1975                 (void) sprintf(buf, "%s [%s]", a, pbuf);
1976         } else
1977                 (void) sprintf(buf, "%s", a);
1978         setproctitle("%s", buf);
1979 }
1980
1981 int
1982 check_loop(sa, sep)
1983         const struct sockaddr *sa;
1984         const struct servtab *sep;
1985 {
1986         struct servtab *se2;
1987         char pname[INET6_ADDRSTRLEN];
1988
1989         for (se2 = servtab; se2; se2 = se2->se_next) {
1990                 if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1991                         continue;
1992
1993                 switch (se2->se_family) {
1994                 case AF_INET:
1995                         if (((const struct sockaddr_in *)sa)->sin_port ==
1996                             se2->se_ctrladdr4.sin_port)
1997                                 goto isloop;
1998                         continue;
1999 #ifdef INET6
2000                 case AF_INET6:
2001                         if (((const struct sockaddr_in *)sa)->sin_port ==
2002                             se2->se_ctrladdr4.sin_port)
2003                                 goto isloop;
2004                         continue;
2005 #endif
2006                 default:
2007                         continue;
2008                 }
2009         isloop:
2010                 getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0,
2011                             NI_NUMERICHOST|NI_WITHSCOPEID);
2012                 syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s",
2013                        sep->se_service, sep->se_proto,
2014                        se2->se_service, se2->se_proto,
2015                        pname);
2016                 return 1;
2017         }
2018         return 0;
2019 }
2020
2021 /*
2022  * print_service:
2023  *      Dump relevant information to stderr
2024  */
2025 void
2026 print_service(action, sep)
2027         const char *action;
2028         const struct servtab *sep;
2029 {
2030         fprintf(stderr,
2031             "%s: %s proto=%s accept=%d max=%d user=%s group=%s"
2032 #ifdef LOGIN_CAP
2033             "class=%s"
2034 #endif
2035             " builtin=%p server=%s"
2036 #ifdef IPSEC
2037             " policy=\"%s\""
2038 #endif
2039             "\n",
2040             action, sep->se_service, sep->se_proto,
2041             sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
2042 #ifdef LOGIN_CAP
2043             sep->se_class,
2044 #endif
2045             (void *) sep->se_bi, sep->se_server
2046 #ifdef IPSEC
2047             , (sep->se_policy ? sep->se_policy : "")
2048 #endif
2049             );
2050 }
2051
2052 #define CPMHSIZE        256
2053 #define CPMHMASK        (CPMHSIZE-1)
2054 #define CHTGRAN         10
2055 #define CHTSIZE         6
2056
2057 typedef struct CTime {
2058         unsigned long   ct_Ticks;
2059         int             ct_Count;
2060 } CTime;
2061
2062 typedef struct CHash {
2063         union {
2064                 struct in_addr  c4_Addr;
2065                 struct in6_addr c6_Addr;
2066         } cu_Addr;
2067 #define ch_Addr4        cu_Addr.c4_Addr
2068 #define ch_Addr6        cu_Addr.c6_Addr
2069         int             ch_Family;
2070         time_t          ch_LTime;
2071         char            *ch_Service;
2072         CTime           ch_Times[CHTSIZE];
2073 } CHash;
2074
2075 CHash   CHashAry[CPMHSIZE];
2076
2077 int
2078 cpmip(sep, ctrl)
2079         const struct servtab *sep;
2080         int ctrl;
2081 {
2082         struct sockaddr_storage rss;
2083         socklen_t rssLen = sizeof(rss);
2084         int r = 0;
2085
2086         /*
2087          * If getpeername() fails, just let it through (if logging is
2088          * enabled the condition is caught elsewhere)
2089          */
2090
2091         if (sep->se_maxcpm > 0 && 
2092             getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) {
2093                 time_t t = time(NULL);
2094                 int hv = 0xABC3D20F;
2095                 int i;
2096                 int cnt = 0;
2097                 CHash *chBest = NULL;
2098                 unsigned int ticks = t / CHTGRAN;
2099                 struct sockaddr_in *sin4;
2100 #ifdef INET6
2101                 struct sockaddr_in6 *sin6;
2102 #endif
2103
2104                 sin4 = (struct sockaddr_in *)&rss;
2105 #ifdef INET6
2106                 sin6 = (struct sockaddr_in6 *)&rss;
2107 #endif
2108                 {
2109                         char *p;
2110                         int addrlen;
2111
2112                         switch (rss.ss_family) {
2113                         case AF_INET:
2114                                 p = (char *)&sin4->sin_addr;
2115                                 addrlen = sizeof(struct in_addr);
2116                                 break;
2117 #ifdef INET6
2118                         case AF_INET6:
2119                                 p = (char *)&sin6->sin6_addr;
2120                                 addrlen = sizeof(struct in6_addr);
2121                                 break;
2122 #endif
2123                         default:
2124                                 /* should not happen */
2125                                 return -1;
2126                         }
2127
2128                         for (i = 0; i < addrlen; ++i, ++p) {
2129                                 hv = (hv << 5) ^ (hv >> 23) ^ *p;
2130                         }
2131                         hv = (hv ^ (hv >> 16));
2132                 }
2133                 for (i = 0; i < 5; ++i) {
2134                         CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
2135
2136                         if (rss.ss_family == AF_INET &&
2137                             ch->ch_Family == AF_INET &&
2138                             sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr &&
2139                             ch->ch_Service && strcmp(sep->se_service,
2140                             ch->ch_Service) == 0) {
2141                                 chBest = ch;
2142                                 break;
2143                         }
2144 #ifdef INET6
2145                         if (rss.ss_family == AF_INET6 &&
2146                             ch->ch_Family == AF_INET6 &&
2147                             IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
2148                                                &ch->ch_Addr6) != 0 &&
2149                             ch->ch_Service && strcmp(sep->se_service,
2150                             ch->ch_Service) == 0) {
2151                                 chBest = ch;
2152                                 break;
2153                         }
2154 #endif
2155                         if (chBest == NULL || ch->ch_LTime == 0 || 
2156                             ch->ch_LTime < chBest->ch_LTime) {
2157                                 chBest = ch;
2158                         }
2159                 }
2160                 if ((rss.ss_family == AF_INET &&
2161                      (chBest->ch_Family != AF_INET ||
2162                       sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) ||
2163                     chBest->ch_Service == NULL ||
2164                     strcmp(sep->se_service, chBest->ch_Service) != 0) {
2165                         chBest->ch_Family = sin4->sin_family;
2166                         chBest->ch_Addr4 = sin4->sin_addr;
2167                         if (chBest->ch_Service)
2168                                 free(chBest->ch_Service);
2169                         chBest->ch_Service = strdup(sep->se_service);
2170                         bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
2171                 } 
2172 #ifdef INET6
2173                 if ((rss.ss_family == AF_INET6 &&
2174                      (chBest->ch_Family != AF_INET6 ||
2175                       IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
2176                                          &chBest->ch_Addr6) == 0)) ||
2177                     chBest->ch_Service == NULL ||
2178                     strcmp(sep->se_service, chBest->ch_Service) != 0) {
2179                         chBest->ch_Family = sin6->sin6_family;
2180                         chBest->ch_Addr6 = sin6->sin6_addr;
2181                         if (chBest->ch_Service)
2182                                 free(chBest->ch_Service);
2183                         chBest->ch_Service = strdup(sep->se_service);
2184                         bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
2185                 }
2186 #endif
2187                 chBest->ch_LTime = t;
2188                 {
2189                         CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
2190                         if (ct->ct_Ticks != ticks) {
2191                                 ct->ct_Ticks = ticks;
2192                                 ct->ct_Count = 0;
2193                         }
2194                         ++ct->ct_Count;
2195                 }
2196                 for (i = 0; i < CHTSIZE; ++i) {
2197                         CTime *ct = &chBest->ch_Times[i];
2198                         if (ct->ct_Ticks <= ticks &&
2199                             ct->ct_Ticks >= ticks - CHTSIZE) {
2200                                 cnt += ct->ct_Count;
2201                         }
2202                 }
2203                 if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
2204                         char pname[INET6_ADDRSTRLEN];
2205
2206                         getnameinfo((struct sockaddr *)&rss,
2207                                     ((struct sockaddr *)&rss)->sa_len,
2208                                     pname, sizeof(pname), NULL, 0,
2209                                     NI_NUMERICHOST|NI_WITHSCOPEID);
2210                         r = -1;
2211                         syslog(LOG_ERR,
2212                             "%s from %s exceeded counts/min (limit %d/min)",
2213                             sep->se_service, pname,
2214                             sep->se_maxcpm);
2215                 }
2216         }
2217         return(r);
2218 }