inetd.c revision 1.22 1 /* $NetBSD: inetd.c,v 1.22 1997/03/13 14:57:34 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1983,1991 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 char copyright[] =
38 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
39 All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 /*static char sccsid[] = "from: @(#)inetd.c 5.30 (Berkeley) 6/3/91";*/
44 static char rcsid[] = "$NetBSD: inetd.c,v 1.22 1997/03/13 14:57:34 mycroft Exp $";
45 #endif /* not lint */
46
47 /*
48 * Inetd - Internet super-server
49 *
50 * This program invokes all internet services as needed.
51 * connection-oriented services are invoked each time a
52 * connection is made, by creating a process. This process
53 * is passed the connection as file descriptor 0 and is
54 * expected to do a getpeername to find out the source host
55 * and port.
56 *
57 * Datagram oriented services are invoked when a datagram
58 * arrives; a process is created and passed a pending message
59 * on file descriptor 0. Datagram servers may either connect
60 * to their peer, freeing up the original socket for inetd
61 * to receive further messages on, or ``take over the socket'',
62 * processing all arriving datagrams and, eventually, timing
63 * out. The first type of server is said to be ``multi-threaded'';
64 * the second type of server ``single-threaded''.
65 *
66 * Inetd uses a configuration file which is read at startup
67 * and, possibly, at some later time in response to a hangup signal.
68 * The configuration file is ``free format'' with fields given in the
69 * order shown below. Continuation lines for an entry must being with
70 * a space or tab. All fields must be present in each entry.
71 *
72 * service name must be in /etc/services
73 * socket type stream/dgram/raw/rdm/seqpacket
74 * protocol must be in /etc/protocols
75 * wait/nowait[.max] single-threaded/multi-threaded, max #
76 * user[.group] user/group to run daemon as
77 * server program full path name
78 * server program arguments maximum of MAXARGS (20)
79 *
80 * For RPC services
81 * service name/version must be in /etc/rpc
82 * socket type stream/dgram/raw/rdm/seqpacket
83 * protocol must be in /etc/protocols
84 * wait/nowait[.max] single-threaded/multi-threaded
85 * user[.group] user to run daemon as
86 * server program full path name
87 * server program arguments maximum of MAXARGS (20)
88 *
89 * For non-RPC services, the "service name" can be of the form
90 * hostaddress:servicename, in which case the hostaddress is used
91 * as the host portion of the address to listen on. If hostaddress
92 * consists of a single `*' character, INADDR_ANY is used.
93 *
94 * A line can also consist of just
95 * hostaddress:
96 * where hostaddress is as in the preceding paragraph. Such a line must
97 * have no further fields; the specified hostaddress is remembered and
98 * used for all further lines that have no hostaddress specified,
99 * until the next such line (or EOF). (This is why * is provided to
100 * allow explicit specification of INADDR_ANY.) A line
101 * *:
102 * is implicitly in effect at the beginning of the file.
103 *
104 * The hostaddress specifier may (and often will) contain dots;
105 * the service name must not.
106 *
107 * For RPC services, host-address specifiers are accepted and will
108 * work to some extent; however, because of limitations in the
109 * portmapper interface, it will not work to try to give more than
110 * one line for any given RPC service, even if the host-address
111 * specifiers are different.
112 *
113 * Comment lines are indicated by a `#' in column 1.
114 */
115
116 /*
117 * Here's the scoop concerning the user.group feature:
118 *
119 * 1) set-group-option off.
120 *
121 * a) user = root: NO setuid() or setgid() is done
122 *
123 * b) other: setuid()
124 * setgid(primary group as found in passwd)
125 * initgroups(name, primary group)
126 *
127 * 2) set-group-option on.
128 *
129 * a) user = root: NO setuid()
130 * setgid(specified group)
131 * NO initgroups()
132 *
133 * b) other: setuid()
134 * setgid(specified group)
135 * initgroups(name, specified group)
136 *
137 */
138
139 #include <sys/param.h>
140 #include <sys/stat.h>
141 #include <sys/ioctl.h>
142 #include <sys/socket.h>
143 #include <sys/un.h>
144 #include <sys/file.h>
145 #include <sys/wait.h>
146 #include <sys/time.h>
147 #include <sys/resource.h>
148
149 #ifndef RLIMIT_NOFILE
150 #define RLIMIT_NOFILE RLIMIT_OFILE
151 #endif
152
153 #define RPC
154
155 #include <netinet/in.h>
156 #include <arpa/inet.h>
157
158 #include <errno.h>
159 #include <signal.h>
160 #include <netdb.h>
161 #include <syslog.h>
162 #include <pwd.h>
163 #include <grp.h>
164 #include <stdio.h>
165 #include <stdlib.h>
166 #include <string.h>
167 #ifdef RPC
168 #include <rpc/rpc.h>
169 #endif
170 #include "pathnames.h"
171
172 #ifdef LIBWRAP
173 # include <tcpd.h>
174 #ifndef LIBWRAP_ALLOW_FACILITY
175 # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
176 #endif
177 #ifndef LIBWRAP_ALLOW_SEVERITY
178 # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
179 #endif
180 #ifndef LIBWRAP_DENY_FACILITY
181 # define LIBWRAP_DENY_FACILITY LOG_AUTH
182 #endif
183 #ifndef LIBWRAP_DENY_SEVERITY
184 # define LIBWRAP_DENY_SEVERITY LOG_WARNING
185 #endif
186 int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
187 int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
188 #endif
189
190 #define TOOMANY 40 /* don't start more than TOOMANY */
191 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
192 #define RETRYTIME (60*10) /* retry after bind or server fail */
193
194 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
195
196 extern int errno;
197
198 /* Why aren't these static? */
199 void config(), reapchild(), retry(), goaway();
200 char *newstr();
201
202 /* Why isn't this done with <strings.h>? */
203 char *index();
204
205 int debug;
206 #ifdef LIBWRAP
207 int lflag;
208 #endif
209 int nsock, maxsock;
210 fd_set allsock;
211 int options;
212 int timingout;
213 struct servent *sp;
214 char *curdom;
215
216 #ifndef OPEN_MAX
217 #define OPEN_MAX 64
218 #endif
219
220 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
221 #define FD_MARGIN (8)
222 typeof(((struct rlimit *)0)->rlim_cur) rlim_ofile_cur = OPEN_MAX;
223
224 #ifdef RLIMIT_NOFILE
225 struct rlimit rlim_ofile;
226 #endif
227
228 struct servtab {
229 char *se_hostaddr; /* host address to listen on */
230 char *se_service; /* name of service */
231 int se_socktype; /* type of socket to use */
232 int se_family; /* address family */
233 char *se_proto; /* protocol used */
234 int se_rpcprog; /* rpc program number */
235 int se_rpcversl; /* rpc program lowest version */
236 int se_rpcversh; /* rpc program highest version */
237 #define isrpcservice(sep) ((sep)->se_rpcversl != 0)
238 short se_wait; /* single threaded server */
239 short se_checked; /* looked at during merge */
240 char *se_user; /* user name to run as */
241 char *se_group; /* group name to run as */
242 struct biltin *se_bi; /* if built-in, description */
243 char *se_server; /* server program */
244 #define MAXARGV 20
245 char *se_argv[MAXARGV+1]; /* program arguments */
246 int se_fd; /* open descriptor */
247 union {
248 struct sockaddr se_un_ctrladdr;
249 struct sockaddr_in se_un_ctrladdr_in;
250 struct sockaddr_un se_un_ctrladdr_un;
251 } se_un; /* bound address */
252 #define se_ctrladdr se_un.se_un_ctrladdr
253 #define se_ctrladdr_in se_un.se_un_ctrladdr_in
254 #define se_ctrladdr_un se_un.se_un_ctrladdr_un
255 int se_ctrladdr_size;
256 int se_max; /* max # of instances of this service */
257 int se_count; /* number started since se_time */
258 struct timeval se_time; /* start of se_count */
259 #ifdef MULOG
260 int se_log;
261 #define MULOG_RFC931 0x40000000
262 #endif
263 struct servtab *se_next;
264 } *servtab;
265
266 int echo_stream(), discard_stream(), machtime_stream();
267 int daytime_stream(), chargen_stream();
268 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
269
270 struct biltin {
271 char *bi_service; /* internally provided service name */
272 int bi_socktype; /* type of socket supported */
273 short bi_fork; /* 1 if should fork before call */
274 short bi_wait; /* 1 if should wait for child */
275 int (*bi_fn)(); /* function which performs it */
276 } biltins[] = {
277 /* Echo received data */
278 "echo", SOCK_STREAM, 1, 0, echo_stream,
279 "echo", SOCK_DGRAM, 0, 0, echo_dg,
280
281 /* Internet /dev/null */
282 "discard", SOCK_STREAM, 1, 0, discard_stream,
283 "discard", SOCK_DGRAM, 0, 0, discard_dg,
284
285 /* Return 32 bit time since 1900 */
286 "time", SOCK_STREAM, 0, 0, machtime_stream,
287 "time", SOCK_DGRAM, 0, 0, machtime_dg,
288
289 /* Return human-readable time */
290 "daytime", SOCK_STREAM, 0, 0, daytime_stream,
291 "daytime", SOCK_DGRAM, 0, 0, daytime_dg,
292
293 /* Familiar character generator */
294 "chargen", SOCK_STREAM, 1, 0, chargen_stream,
295 "chargen", SOCK_DGRAM, 0, 0, chargen_dg,
296 0
297 };
298
299 #define NUMINT (sizeof(intab) / sizeof(struct inent))
300 char *CONFIG = _PATH_INETDCONF;
301 char **Argv;
302 char *LastArg;
303 char *progname;
304
305 #ifdef sun
306 /*
307 * Sun's RPC library caches the result of `dtablesize()'
308 * This is incompatible with our "bumping" of file descriptors "on demand"
309 */
310 int
311 _rpc_dtablesize()
312 {
313 return rlim_ofile_cur;
314 }
315 #endif
316
317 main(argc, argv, envp)
318 int argc;
319 char *argv[], *envp[];
320 {
321 extern char *optarg;
322 extern int optind;
323 register struct servtab *sep;
324 register struct passwd *pwd;
325 register struct group *grp;
326 register int tmpint;
327 struct sigvec sv;
328 int ch, pid, dofork;
329 char buf[50];
330 #ifdef LIBWRAP
331 struct request_info req;
332 int denied;
333 char *service;
334 #endif
335
336 Argv = argv;
337 if (envp == 0 || *envp == 0)
338 envp = argv;
339 while (*envp)
340 envp++;
341 LastArg = envp[-1] + strlen(envp[-1]);
342
343 progname = strrchr(argv[0], '/');
344 progname = progname ? progname + 1 : argv[0];
345
346 while ((ch = getopt(argc, argv,
347 #ifdef LIBWRAP
348 "dl"
349 #else
350 "d"
351 #endif
352 )) != EOF)
353 switch(ch) {
354 case 'd':
355 debug = 1;
356 options |= SO_DEBUG;
357 break;
358 #ifdef LIBWRAP
359 case 'l':
360 lflag = 1;
361 break;
362 #endif
363 case '?':
364 default:
365 #ifdef LIBWRAP
366 fprintf(stderr, "usage: %s [-dl] [conf]\n", progname);
367 #else
368 fprintf(stderr, "usage: %s [-d] [conf]\n", progname);
369 #endif
370 exit(1);
371 }
372 argc -= optind;
373 argv += optind;
374
375 if (argc > 0)
376 CONFIG = argv[0];
377
378 if (debug == 0)
379 daemon(0, 0);
380 openlog(progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
381 logpid();
382
383 #ifdef RLIMIT_NOFILE
384 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
385 syslog(LOG_ERR, "getrlimit: %m");
386 } else {
387 rlim_ofile_cur = rlim_ofile.rlim_cur;
388 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
389 rlim_ofile_cur = OPEN_MAX;
390 }
391 #endif
392
393 bzero((char *)&sv, sizeof(sv));
394 sv.sv_mask = SIGBLOCK;
395 sv.sv_handler = retry;
396 sigvec(SIGALRM, &sv, (struct sigvec *)0);
397 config();
398 sv.sv_handler = config;
399 sigvec(SIGHUP, &sv, (struct sigvec *)0);
400 sv.sv_handler = reapchild;
401 sigvec(SIGCHLD, &sv, (struct sigvec *)0);
402 sv.sv_handler = goaway;
403 sigvec(SIGTERM, &sv, (struct sigvec *)0);
404 sv.sv_handler = goaway;
405 sigvec(SIGINT, &sv, (struct sigvec *)0);
406
407 {
408 /* space for daemons to overwrite environment for ps */
409 #define DUMMYSIZE 100
410 char dummy[DUMMYSIZE];
411
412 (void)memset(dummy, 'x', DUMMYSIZE - 1);
413 dummy[DUMMYSIZE - 1] = '\0';
414
415 (void)setenv("inetd_dummy", dummy, 1);
416 }
417
418 for (;;) {
419 int n, ctrl;
420 fd_set readable;
421
422 if (nsock == 0) {
423 (void) sigblock(SIGBLOCK);
424 while (nsock == 0)
425 sigpause(0L);
426 (void) sigsetmask(0L);
427 }
428 readable = allsock;
429 if ((n = select(maxsock + 1, &readable, (fd_set *)0,
430 (fd_set *)0, (struct timeval *)0)) <= 0) {
431 if (n < 0 && errno != EINTR)
432 syslog(LOG_WARNING, "select: %m\n");
433 sleep(1);
434 continue;
435 }
436 for (sep = servtab; n && sep; sep = sep->se_next)
437 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
438 n--;
439 if (debug)
440 fprintf(stderr, "someone wants %s\n", sep->se_service);
441 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
442 /* XXX here do the libwrap check-before-accept */
443 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
444 (int *)0);
445 if (debug)
446 fprintf(stderr, "accept, ctrl %d\n", ctrl);
447 if (ctrl < 0) {
448 if (errno == EINTR)
449 continue;
450 syslog(LOG_WARNING, "accept (for %s): %m",
451 sep->se_service);
452 continue;
453 }
454 } else
455 ctrl = sep->se_fd;
456 (void) sigblock(SIGBLOCK);
457 pid = 0;
458 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
459 if (dofork) {
460 if (sep->se_count++ == 0)
461 (void)gettimeofday(&sep->se_time,
462 (struct timezone *)0);
463 else if (sep->se_count >= sep->se_max) {
464 struct timeval now;
465
466 (void)gettimeofday(&now, (struct timezone *)0);
467 if (now.tv_sec - sep->se_time.tv_sec >
468 CNT_INTVL) {
469 sep->se_time = now;
470 sep->se_count = 1;
471 } else {
472 syslog(LOG_ERR,
473 "%s/%s server failing (looping), service terminated\n",
474 sep->se_service, sep->se_proto);
475 FD_CLR(sep->se_fd, &allsock);
476 (void) close(sep->se_fd);
477 sep->se_fd = -1;
478 sep->se_count = 0;
479 nsock--;
480 sigsetmask(0L);
481 if (!timingout) {
482 timingout = 1;
483 alarm(RETRYTIME);
484 }
485 continue;
486 }
487 }
488 pid = fork();
489 }
490 if (pid < 0) {
491 syslog(LOG_ERR, "fork: %m");
492 if (sep->se_socktype == SOCK_STREAM)
493 close(ctrl);
494 sigsetmask(0L);
495 sleep(1);
496 continue;
497 }
498 if (pid && sep->se_wait) {
499 sep->se_wait = pid;
500 FD_CLR(sep->se_fd, &allsock);
501 nsock--;
502 }
503 sigsetmask(0L);
504 if (pid == 0) {
505 if (debug && dofork)
506 setsid();
507 #ifdef LIBWRAP
508 request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
509 sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl,
510 NULL);
511 fromhost(&req);
512 denied = !hosts_access(&req);
513 if (denied || lflag) {
514 sp = getservbyport(sep->se_ctrladdr_in.sin_port,
515 sep->se_proto);
516 if (sp == NULL) {
517 (void)snprintf(buf, sizeof buf, "%d",
518 ntohs(sep->se_ctrladdr_in.sin_port));
519 service = buf;
520 } else
521 service = sp->s_name;
522 }
523 if (denied) {
524 syslog(deny_severity, "refused "
525 "connection from %.500s, service %s (%s)",
526 eval_client(&req), service, sep->se_proto);
527 goto reject;
528 }
529 if (lflag) {
530 syslog(allow_severity,
531 "connection from %.500s, service %s (%s)",
532 eval_client(&req), service, sep->se_proto);
533 }
534 #endif /* LIBWRAP */
535 if (sep->se_bi)
536 (*sep->se_bi->bi_fn)(ctrl, sep);
537 else {
538 if ((pwd = getpwnam(sep->se_user)) == NULL) {
539 syslog(LOG_ERR,
540 "getpwnam: %s: No such user",
541 sep->se_user);
542 goto reject;
543 }
544 if (sep->se_group &&
545 (grp = getgrnam(sep->se_group)) == NULL) {
546 syslog(LOG_ERR,
547 "getgrnam: %s: No such group",
548 sep->se_group);
549 goto reject;
550 }
551 if (pwd->pw_uid) {
552 if (sep->se_group)
553 pwd->pw_gid = grp->gr_gid;
554 (void) setgid((gid_t)pwd->pw_gid);
555 initgroups(pwd->pw_name, pwd->pw_gid);
556 (void) setuid((uid_t)pwd->pw_uid);
557 } else if (sep->se_group) {
558 (void) setgid((gid_t)grp->gr_gid);
559 }
560 if (debug)
561 fprintf(stderr, "%d execl %s\n",
562 getpid(), sep->se_server);
563 #ifdef MULOG
564 if (sep->se_log)
565 dolog(sep, ctrl);
566 #endif
567 if (ctrl != 0) {
568 dup2(ctrl, 0);
569 close(ctrl);
570 ctrl = 0;
571 }
572 dup2(0, 1);
573 dup2(0, 2);
574 #ifdef RLIMIT_NOFILE
575 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
576 if (setrlimit(RLIMIT_NOFILE,
577 &rlim_ofile) < 0)
578 syslog(LOG_ERR,"setrlimit: %m");
579 }
580 #endif
581 for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
582 (void)close(tmpint);
583 execv(sep->se_server, sep->se_argv);
584 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
585 reject:
586 if (sep->se_socktype != SOCK_STREAM)
587 recv(ctrl, buf, sizeof (buf), 0);
588 _exit(1);
589 }
590 }
591 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
592 close(ctrl);
593 }
594 }
595 }
596
597 void
598 reapchild()
599 {
600 int status;
601 int pid;
602 register struct servtab *sep;
603
604 for (;;) {
605 pid = wait3(&status, WNOHANG, (struct rusage *)0);
606 if (pid <= 0)
607 break;
608 if (debug)
609 fprintf(stderr, "%d reaped\n", pid);
610 for (sep = servtab; sep; sep = sep->se_next)
611 if (sep->se_wait == pid) {
612 if (WIFEXITED(status) && WEXITSTATUS(status))
613 syslog(LOG_WARNING,
614 "%s: exit status 0x%x",
615 sep->se_server, WEXITSTATUS(status));
616 else if (WIFSIGNALED(status))
617 syslog(LOG_WARNING,
618 "%s: exit signal 0x%x",
619 sep->se_server, WTERMSIG(status));
620 sep->se_wait = 1;
621 FD_SET(sep->se_fd, &allsock);
622 nsock++;
623 if (debug)
624 fprintf(stderr, "restored %s, fd %d\n",
625 sep->se_service, sep->se_fd);
626 }
627 }
628 }
629
630 void
631 config()
632 {
633 register struct servtab *sep, *cp, **sepp;
634 struct servtab *getconfigent(), *enter();
635 long omask;
636 int n;
637
638 if (!setconfig()) {
639 syslog(LOG_ERR, "%s: %m", CONFIG);
640 return;
641 }
642 for (sep = servtab; sep; sep = sep->se_next)
643 sep->se_checked = 0;
644 while (cp = getconfigent()) {
645 for (sep = servtab; sep; sep = sep->se_next)
646 if (strcmp(sep->se_service, cp->se_service) == 0 &&
647 strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
648 strcmp(sep->se_proto, cp->se_proto) == 0)
649 break;
650 if (sep != 0) {
651 int i;
652
653 #define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
654
655 omask = sigblock(SIGBLOCK);
656 /*
657 * sep->se_wait may be holding the pid of a daemon
658 * that we're waiting for. If so, don't overwrite
659 * it unless the config file explicitly says don't
660 * wait.
661 */
662 if (cp->se_bi == 0 &&
663 (sep->se_wait == 1 || cp->se_wait == 0))
664 sep->se_wait = cp->se_wait;
665 SWAP(int, cp->se_max, sep->se_max);
666 SWAP(char *, sep->se_user, cp->se_user);
667 SWAP(char *, sep->se_group, cp->se_group);
668 SWAP(char *, sep->se_server, cp->se_server);
669 for (i = 0; i < MAXARGV; i++)
670 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
671 #undef SWAP
672 if (isrpcservice(sep))
673 unregister_rpc(sep);
674 sep->se_rpcversl = cp->se_rpcversl;
675 sep->se_rpcversh = cp->se_rpcversh;
676 sigsetmask(omask);
677 freeconfig(cp);
678 if (debug)
679 print_service("REDO", sep);
680 } else {
681 sep = enter(cp);
682 if (debug)
683 print_service("ADD ", sep);
684 }
685 sep->se_checked = 1;
686
687 switch (sep->se_family) {
688 case AF_UNIX:
689 if (sep->se_fd != -1)
690 break;
691 (void)unlink(sep->se_service);
692 n = strlen(sep->se_service);
693 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
694 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
695 strncpy(sep->se_ctrladdr_un.sun_path,
696 sep->se_service, n);
697 sep->se_ctrladdr_un.sun_family = AF_UNIX;
698 sep->se_ctrladdr_size = n +
699 sizeof sep->se_ctrladdr_un -
700 sizeof sep->se_ctrladdr_un.sun_path;
701 setup(sep);
702 break;
703 case AF_INET:
704 sep->se_ctrladdr_in.sin_family = AF_INET;
705 if (!strcmp(sep->se_hostaddr,"*"))
706 sep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
707 else if (!inet_aton(sep->se_hostaddr,&sep->se_ctrladdr_in.sin_addr)) {
708 /* Do we really want to support hostname lookups here? */
709 struct hostent *hp;
710 hp = gethostbyname(sep->se_hostaddr);
711 if (hp == 0) {
712 syslog(LOG_ERR,"%s: unknown host",sep->se_hostaddr);
713 continue;
714 } else if (hp->h_addrtype != AF_INET) {
715 syslog(LOG_ERR,"%s: address isn't an Internet address",sep->se_hostaddr);
716 continue;
717 } else if (hp->h_length != sizeof(struct in_addr)) {
718 syslog(LOG_ERR,"%s: address size wrong (under DNS corruption attack?)",sep->se_hostaddr);
719 continue;
720 } else {
721 bcopy(hp->h_addr_list[0],&sep->se_ctrladdr_in.sin_addr,sizeof(struct in_addr));
722 }
723 }
724 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
725 if (isrpcservice(sep)) {
726 struct rpcent *rp;
727
728 sep->se_rpcprog = atoi(sep->se_service);
729 if (sep->se_rpcprog == 0) {
730 rp = getrpcbyname(sep->se_service);
731 if (rp == 0) {
732 syslog(LOG_ERR,
733 "%s: unknown service",
734 sep->se_service);
735 continue;
736 }
737 sep->se_rpcprog = rp->r_number;
738 }
739 if (sep->se_fd == -1)
740 setup(sep);
741 if (sep->se_fd != -1)
742 register_rpc(sep);
743 } else {
744 u_short port = htons(atoi(sep->se_service));
745
746 if (!port) {
747 sp = getservbyname(sep->se_service,
748 sep->se_proto);
749 if (sp == 0) {
750 syslog(LOG_ERR,
751 "%s/%s: unknown service",
752 sep->se_service, sep->se_proto);
753 continue;
754 }
755 port = sp->s_port;
756 }
757 if (port != sep->se_ctrladdr_in.sin_port) {
758 sep->se_ctrladdr_in.sin_port = port;
759 if (sep->se_fd != -1) {
760 FD_CLR(sep->se_fd, &allsock);
761 nsock--;
762 (void) close(sep->se_fd);
763 }
764 sep->se_fd = -1;
765 }
766 if (sep->se_fd == -1)
767 setup(sep);
768 }
769 }
770 }
771 endconfig();
772 /*
773 * Purge anything not looked at above.
774 */
775 omask = sigblock(SIGBLOCK);
776 sepp = &servtab;
777 while (sep = *sepp) {
778 if (sep->se_checked) {
779 sepp = &sep->se_next;
780 continue;
781 }
782 *sepp = sep->se_next;
783 if (sep->se_fd != -1) {
784 FD_CLR(sep->se_fd, &allsock);
785 nsock--;
786 (void) close(sep->se_fd);
787 }
788 if (isrpcservice(sep))
789 unregister_rpc(sep);
790 if (sep->se_family == AF_UNIX)
791 (void)unlink(sep->se_service);
792 if (debug)
793 print_service("FREE", sep);
794 freeconfig(sep);
795 free((char *)sep);
796 }
797 (void) sigsetmask(omask);
798 }
799
800 void
801 retry()
802 {
803 register struct servtab *sep;
804
805 timingout = 0;
806 for (sep = servtab; sep; sep = sep->se_next) {
807 if (sep->se_fd == -1) {
808 switch (sep->se_family) {
809 case AF_UNIX:
810 case AF_INET:
811 setup(sep);
812 if (sep->se_fd != -1 && isrpcservice(sep))
813 register_rpc(sep);
814 break;
815 }
816 }
817 }
818 }
819
820 void
821 goaway()
822 {
823 register struct servtab *sep;
824
825 for (sep = servtab; sep; sep = sep->se_next) {
826 if (sep->se_fd == -1)
827 continue;
828
829 switch (sep->se_family) {
830 case AF_UNIX:
831 (void)unlink(sep->se_service);
832 break;
833 case AF_INET:
834 if (sep->se_wait == 1 && isrpcservice(sep))
835 unregister_rpc(sep);
836 break;
837 }
838 (void)close(sep->se_fd);
839 }
840 (void)unlink(_PATH_INETDPID);
841 exit(0);
842 }
843
844
845 setup(sep)
846 register struct servtab *sep;
847 {
848 int on = 1;
849
850 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
851 syslog(LOG_ERR, "%s/%s: socket: %m",
852 sep->se_service, sep->se_proto);
853 return;
854 }
855 #define turnon(fd, opt) \
856 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
857 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
858 turnon(sep->se_fd, SO_DEBUG) < 0)
859 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
860 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
861 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
862 #undef turnon
863 if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
864 syslog(LOG_ERR, "%s/%s: bind: %m",
865 sep->se_service, sep->se_proto);
866 (void) close(sep->se_fd);
867 sep->se_fd = -1;
868 if (!timingout) {
869 timingout = 1;
870 alarm(RETRYTIME);
871 }
872 return;
873 }
874 if (sep->se_socktype == SOCK_STREAM)
875 listen(sep->se_fd, 10);
876
877 FD_SET(sep->se_fd, &allsock);
878 nsock++;
879 if (sep->se_fd > maxsock) {
880 maxsock = sep->se_fd;
881 if (maxsock > rlim_ofile_cur - FD_MARGIN)
882 bump_nofile();
883 }
884 }
885
886 register_rpc(sep)
887 register struct servtab *sep;
888 {
889 #ifdef RPC
890 int n;
891 struct sockaddr_in sin;
892 struct protoent *pp;
893
894 if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
895 syslog(LOG_ERR, "%s: getproto: %m",
896 sep->se_proto);
897 return;
898 }
899 n = sizeof sin;
900 if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
901 syslog(LOG_ERR, "%s/%s: getsockname: %m",
902 sep->se_service, sep->se_proto);
903 return;
904 }
905
906 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
907 if (debug)
908 fprintf(stderr, "pmap_set: %u %u %u %u\n",
909 sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
910 (void)pmap_unset(sep->se_rpcprog, n);
911 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
912 syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
913 sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
914 }
915 #endif /* RPC */
916 }
917
918 unregister_rpc(sep)
919 register struct servtab *sep;
920 {
921 #ifdef RPC
922 int n;
923
924 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
925 if (debug)
926 fprintf(stderr, "pmap_unset(%u, %u)\n",
927 sep->se_rpcprog, n);
928 if (!pmap_unset(sep->se_rpcprog, n))
929 syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
930 sep->se_rpcprog, n);
931 }
932 #endif /* RPC */
933 }
934
935
936 struct servtab *
937 enter(cp)
938 struct servtab *cp;
939 {
940 register struct servtab *sep;
941 long omask;
942
943 sep = (struct servtab *)malloc(sizeof (*sep));
944 if (sep == (struct servtab *)0) {
945 syslog(LOG_ERR, "Out of memory.");
946 exit(-1);
947 }
948 *sep = *cp;
949 sep->se_fd = -1;
950 sep->se_rpcprog = -1;
951 omask = sigblock(SIGBLOCK);
952 sep->se_next = servtab;
953 servtab = sep;
954 sigsetmask(omask);
955 return (sep);
956 }
957
958 FILE *fconfig = NULL;
959 struct servtab serv;
960 char line[256];
961 char *skip(), *nextline();
962 char *defhost;
963
964 setconfig()
965 {
966 if (defhost) free(defhost);
967 defhost = newstr("*");
968 if (fconfig != NULL) {
969 fseek(fconfig, 0L, SEEK_SET);
970 return (1);
971 }
972 fconfig = fopen(CONFIG, "r");
973 return (fconfig != NULL);
974 }
975
976 endconfig()
977 {
978 if (fconfig) {
979 (void) fclose(fconfig);
980 fconfig = NULL;
981 }
982 if (defhost) {
983 free(defhost);
984 defhost = 0;
985 }
986 }
987
988 struct servtab *
989 getconfigent()
990 {
991 register struct servtab *sep = &serv;
992 int argc;
993 char *cp, *arg;
994 char *hostdelim;
995
996 more:
997 #ifdef MULOG
998 while ((cp = nextline(fconfig)) && *cp == '#') {
999 /* Avoid use of `skip' if there is a danger of it looking
1000 * at continuation lines.
1001 */
1002 do {
1003 cp++;
1004 } while (*cp == ' ' || *cp == '\t');
1005 if (*cp == '\0')
1006 continue;
1007 if ((arg = skip(&cp)) == NULL)
1008 continue;
1009 if (strcmp(arg, "DOMAIN"))
1010 continue;
1011 if (curdom)
1012 free(curdom);
1013 curdom = NULL;
1014 while (*cp == ' ' || *cp == '\t')
1015 cp++;
1016 if (*cp == '\0')
1017 continue;
1018 arg = cp;
1019 while (*cp && *cp != ' ' && *cp != '\t')
1020 cp++;
1021 if (*cp != '\0')
1022 *cp++ = '\0';
1023 curdom = newstr(arg);
1024 }
1025 #else
1026 while ((cp = nextline(fconfig)) && *cp == '#')
1027 ;
1028 #endif
1029 if (cp == NULL)
1030 return ((struct servtab *)0);
1031 bzero((char *)sep, sizeof *sep);
1032 sep->se_service = newstr(skip(&cp));
1033 hostdelim = rindex(sep->se_service,':');
1034 if (hostdelim) {
1035 *hostdelim = '\0';
1036 sep->se_hostaddr = sep->se_service;
1037 sep->se_service = newstr(hostdelim+1);
1038 } else {
1039 sep->se_hostaddr = newstr(defhost);
1040 }
1041 arg = skip(&cp);
1042 if (arg == NULL) {
1043 if (!strcmp(sep->se_service,"")) {
1044 /* if we didn't have a colon, still OK */
1045 free(defhost);
1046 defhost = sep->se_hostaddr;
1047 } else
1048 free(sep->se_hostaddr);
1049 free(sep->se_service);
1050 goto more;
1051 }
1052
1053 if (strcmp(arg, "stream") == 0)
1054 sep->se_socktype = SOCK_STREAM;
1055 else if (strcmp(arg, "dgram") == 0)
1056 sep->se_socktype = SOCK_DGRAM;
1057 else if (strcmp(arg, "rdm") == 0)
1058 sep->se_socktype = SOCK_RDM;
1059 else if (strcmp(arg, "seqpacket") == 0)
1060 sep->se_socktype = SOCK_SEQPACKET;
1061 else if (strcmp(arg, "raw") == 0)
1062 sep->se_socktype = SOCK_RAW;
1063 else
1064 sep->se_socktype = -1;
1065
1066 sep->se_proto = newstr(skip(&cp));
1067 if (strcmp(sep->se_proto, "unix") == 0) {
1068 sep->se_family = AF_UNIX;
1069 } else {
1070 sep->se_family = AF_INET;
1071 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1072 #ifdef RPC
1073 char *cp, *ccp;
1074 cp = index(sep->se_service, '/');
1075 if (cp == 0) {
1076 syslog(LOG_ERR, "%s: no rpc version",
1077 sep->se_service);
1078 goto more;
1079 }
1080 *cp++ = '\0';
1081 sep->se_rpcversl =
1082 sep->se_rpcversh = strtol(cp, &ccp, 0);
1083 if (ccp == cp) {
1084 badafterall:
1085 syslog(LOG_ERR, "%s/%s: bad rpc version",
1086 sep->se_service, cp);
1087 goto more;
1088 }
1089 if (*ccp == '-') {
1090 cp = ccp + 1;
1091 sep->se_rpcversh = strtol(cp, &ccp, 0);
1092 if (ccp == cp)
1093 goto badafterall;
1094 }
1095 #else
1096 syslog(LOG_ERR, "%s: rpc services not suported",
1097 sep->se_service);
1098 goto more;
1099 #endif /* RPC */
1100 }
1101 }
1102 arg = skip(&cp);
1103 if (arg == NULL)
1104 goto more;
1105 {
1106 char *s = index(arg, '.');
1107 if (s) {
1108 *s++ = '\0';
1109 sep->se_max = atoi(s);
1110 } else
1111 sep->se_max = TOOMANY;
1112 }
1113 sep->se_wait = strcmp(arg, "wait") == 0;
1114 sep->se_user = newstr(skip(&cp));
1115 if (sep->se_group = index(sep->se_user, '.')) {
1116 *sep->se_group++ = '\0';
1117 }
1118 sep->se_server = newstr(skip(&cp));
1119 if (strcmp(sep->se_server, "internal") == 0) {
1120 register struct biltin *bi;
1121
1122 for (bi = biltins; bi->bi_service; bi++)
1123 if (bi->bi_socktype == sep->se_socktype &&
1124 strcmp(bi->bi_service, sep->se_service) == 0)
1125 break;
1126 if (bi->bi_service == 0) {
1127 syslog(LOG_ERR, "internal service %s unknown\n",
1128 sep->se_service);
1129 goto more;
1130 }
1131 sep->se_bi = bi;
1132 sep->se_wait = bi->bi_wait;
1133 } else
1134 sep->se_bi = NULL;
1135 argc = 0;
1136 for (arg = skip(&cp); cp; arg = skip(&cp)) {
1137 #if MULOG
1138 char *colon, *rindex();
1139
1140 if (argc == 0 && (colon = rindex(arg, ':'))) {
1141 while (arg < colon) {
1142 int x;
1143 char *ccp;
1144
1145 switch (*arg++) {
1146 case 'l':
1147 x = 1;
1148 if (isdigit(*arg)) {
1149 x = strtol(arg, &ccp, 0);
1150 if (ccp == arg)
1151 break;
1152 arg = ccp;
1153 }
1154 sep->se_log &= ~MULOG_RFC931;
1155 sep->se_log |= x;
1156 break;
1157 case 'a':
1158 sep->se_log |= MULOG_RFC931;
1159 break;
1160 default:
1161 break;
1162 }
1163 }
1164 arg = colon + 1;
1165 }
1166 #endif
1167 if (argc < MAXARGV)
1168 sep->se_argv[argc++] = newstr(arg);
1169 }
1170 while (argc <= MAXARGV)
1171 sep->se_argv[argc++] = NULL;
1172 return (sep);
1173 }
1174
1175 freeconfig(cp)
1176 register struct servtab *cp;
1177 {
1178 int i;
1179
1180 if (cp->se_hostaddr)
1181 free(cp->se_hostaddr);
1182 if (cp->se_service)
1183 free(cp->se_service);
1184 if (cp->se_proto)
1185 free(cp->se_proto);
1186 if (cp->se_user)
1187 free(cp->se_user);
1188 /* Note: se_group is part of the newstr'ed se_user */
1189 if (cp->se_server)
1190 free(cp->se_server);
1191 for (i = 0; i < MAXARGV; i++)
1192 if (cp->se_argv[i])
1193 free(cp->se_argv[i]);
1194 }
1195
1196 char *
1197 skip(cpp)
1198 char **cpp;
1199 {
1200 register char *cp = *cpp;
1201 char *start;
1202
1203 if (*cpp == NULL)
1204 return ((char *)0);
1205
1206 again:
1207 while (*cp == ' ' || *cp == '\t')
1208 cp++;
1209 if (*cp == '\0') {
1210 int c;
1211
1212 c = getc(fconfig);
1213 (void) ungetc(c, fconfig);
1214 if (c == ' ' || c == '\t')
1215 if (cp = nextline(fconfig))
1216 goto again;
1217 *cpp = (char *)0;
1218 return ((char *)0);
1219 }
1220 start = cp;
1221 while (*cp && *cp != ' ' && *cp != '\t')
1222 cp++;
1223 if (*cp != '\0')
1224 *cp++ = '\0';
1225 *cpp = cp;
1226 return (start);
1227 }
1228
1229 char *
1230 nextline(fd)
1231 FILE *fd;
1232 {
1233 char *cp;
1234
1235 if (fgets(line, sizeof (line), fd) == NULL)
1236 return ((char *)0);
1237 cp = index(line, '\n');
1238 if (cp)
1239 *cp = '\0';
1240 return (line);
1241 }
1242
1243 char *
1244 newstr(cp)
1245 char *cp;
1246 {
1247 if (cp = strdup(cp ? cp : ""))
1248 return(cp);
1249 syslog(LOG_ERR, "strdup: %m");
1250 exit(-1);
1251 }
1252
1253 inetd_setproctitle(a, s)
1254 char *a;
1255 int s;
1256 {
1257 int size;
1258 register char *cp;
1259 struct sockaddr_in sin;
1260 char buf[80];
1261
1262 cp = Argv[0];
1263 size = sizeof(sin);
1264 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1265 (void)snprintf(buf, sizeof buf, "-%s [%s]", a,
1266 inet_ntoa(sin.sin_addr));
1267 else
1268 (void)snprintf(buf, sizeof buf, "-%s", a);
1269 strncpy(cp, buf, LastArg - cp);
1270 cp += strlen(cp);
1271 while (cp < LastArg)
1272 *cp++ = ' ';
1273 }
1274
1275 logpid()
1276 {
1277 FILE *fp;
1278
1279 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1280 fprintf(fp, "%u\n", getpid());
1281 (void)fclose(fp);
1282 }
1283 }
1284
1285 bump_nofile()
1286 {
1287 #ifdef RLIMIT_NOFILE
1288
1289 #define FD_CHUNK 32
1290
1291 struct rlimit rl;
1292
1293 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1294 syslog(LOG_ERR, "getrlimit: %m");
1295 return -1;
1296 }
1297 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1298 if (rl.rlim_cur <= rlim_ofile_cur) {
1299 syslog(LOG_ERR,
1300 "bump_nofile: cannot extend file limit, max = %d",
1301 rl.rlim_cur);
1302 return -1;
1303 }
1304
1305 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1306 syslog(LOG_ERR, "setrlimit: %m");
1307 return -1;
1308 }
1309
1310 rlim_ofile_cur = rl.rlim_cur;
1311 return 0;
1312
1313 #else
1314 syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
1315 return -1;
1316 #endif
1317 }
1318
1319 /*
1320 * Internet services provided internally by inetd:
1321 */
1322 #define BUFSIZE 4096
1323
1324 /* ARGSUSED */
1325 echo_stream(s, sep) /* Echo service -- echo data back */
1326 int s;
1327 struct servtab *sep;
1328 {
1329 char buffer[BUFSIZE];
1330 int i;
1331
1332 inetd_setproctitle(sep->se_service, s);
1333 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1334 write(s, buffer, i) > 0)
1335 ;
1336 exit(0);
1337 }
1338
1339 /* ARGSUSED */
1340 echo_dg(s, sep) /* Echo service -- echo data back */
1341 int s;
1342 struct servtab *sep;
1343 {
1344 char buffer[BUFSIZE];
1345 int i, size;
1346 struct sockaddr sa;
1347
1348 size = sizeof(sa);
1349 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1350 return;
1351 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1352 }
1353
1354 /* ARGSUSED */
1355 discard_stream(s, sep) /* Discard service -- ignore data */
1356 int s;
1357 struct servtab *sep;
1358 {
1359 char buffer[BUFSIZE];
1360
1361 inetd_setproctitle(sep->se_service, s);
1362 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1363 errno == EINTR)
1364 ;
1365 exit(0);
1366 }
1367
1368 /* ARGSUSED */
1369 discard_dg(s, sep) /* Discard service -- ignore data */
1370 int s;
1371 struct servtab *sep;
1372 {
1373 char buffer[BUFSIZE];
1374
1375 (void) read(s, buffer, sizeof(buffer));
1376 }
1377
1378 #include <ctype.h>
1379 #define LINESIZ 72
1380 char ring[128];
1381 char *endring;
1382
1383 initring()
1384 {
1385 register int i;
1386
1387 endring = ring;
1388
1389 for (i = 0; i <= 128; ++i)
1390 if (isprint(i))
1391 *endring++ = i;
1392 }
1393
1394 /* ARGSUSED */
1395 chargen_stream(s, sep) /* Character generator */
1396 int s;
1397 struct servtab *sep;
1398 {
1399 register char *rs;
1400 int len;
1401 char text[LINESIZ+2];
1402
1403 inetd_setproctitle(sep->se_service, s);
1404
1405 if (!endring) {
1406 initring();
1407 rs = ring;
1408 }
1409
1410 text[LINESIZ] = '\r';
1411 text[LINESIZ + 1] = '\n';
1412 for (rs = ring;;) {
1413 if ((len = endring - rs) >= LINESIZ)
1414 bcopy(rs, text, LINESIZ);
1415 else {
1416 bcopy(rs, text, len);
1417 bcopy(ring, text + len, LINESIZ - len);
1418 }
1419 if (++rs == endring)
1420 rs = ring;
1421 if (write(s, text, sizeof(text)) != sizeof(text))
1422 break;
1423 }
1424 exit(0);
1425 }
1426
1427 /* ARGSUSED */
1428 chargen_dg(s, sep) /* Character generator */
1429 int s;
1430 struct servtab *sep;
1431 {
1432 struct sockaddr sa;
1433 static char *rs;
1434 int len, size;
1435 char text[LINESIZ+2];
1436
1437 if (endring == 0) {
1438 initring();
1439 rs = ring;
1440 }
1441
1442 size = sizeof(sa);
1443 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1444 return;
1445
1446 if ((len = endring - rs) >= LINESIZ)
1447 bcopy(rs, text, LINESIZ);
1448 else {
1449 bcopy(rs, text, len);
1450 bcopy(ring, text + len, LINESIZ - len);
1451 }
1452 if (++rs == endring)
1453 rs = ring;
1454 text[LINESIZ] = '\r';
1455 text[LINESIZ + 1] = '\n';
1456 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1457 }
1458
1459 /*
1460 * Return a machine readable date and time, in the form of the
1461 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1462 * returns the number of seconds since midnight, Jan 1, 1970,
1463 * we must add 2208988800 seconds to this figure to make up for
1464 * some seventy years Bell Labs was asleep.
1465 */
1466
1467 long
1468 machtime()
1469 {
1470 struct timeval tv;
1471
1472 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1473 fprintf(stderr, "Unable to get time of day\n");
1474 return (0L);
1475 }
1476 return (htonl((long)tv.tv_sec + 2208988800UL));
1477 }
1478
1479 /* ARGSUSED */
1480 machtime_stream(s, sep)
1481 int s;
1482 struct servtab *sep;
1483 {
1484 long result;
1485
1486 result = machtime();
1487 (void) write(s, (char *) &result, sizeof(result));
1488 }
1489
1490 /* ARGSUSED */
1491 machtime_dg(s, sep)
1492 int s;
1493 struct servtab *sep;
1494 {
1495 long result;
1496 struct sockaddr sa;
1497 int size;
1498
1499 size = sizeof(sa);
1500 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1501 return;
1502 result = machtime();
1503 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1504 }
1505
1506 /* ARGSUSED */
1507 daytime_stream(s, sep) /* Return human-readable time of day */
1508 int s;
1509 struct servtab *sep;
1510 {
1511 char buffer[256];
1512 time_t time(), clock;
1513 int len;
1514
1515 clock = time((time_t *) 0);
1516
1517 len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1518 (void) write(s, buffer, len);
1519 }
1520
1521 /* ARGSUSED */
1522 daytime_dg(s, sep) /* Return human-readable time of day */
1523 int s;
1524 struct servtab *sep;
1525 {
1526 char buffer[256];
1527 time_t time(), clock;
1528 struct sockaddr sa;
1529 int size;
1530
1531 clock = time((time_t *) 0);
1532
1533 size = sizeof(sa);
1534 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1535 return;
1536 size = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1537 (void) sendto(s, buffer, size, 0, &sa, sizeof(sa));
1538 }
1539
1540 /*
1541 * print_service:
1542 * Dump relevant information to stderr
1543 */
1544 print_service(action, sep)
1545 char *action;
1546 struct servtab *sep;
1547 {
1548 if (isrpcservice(sep))
1549 fprintf(stderr,
1550 "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1551 action, sep->se_service,
1552 sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
1553 sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1554 (long)sep->se_bi, sep->se_server);
1555 else
1556 fprintf(stderr,
1557 "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1558 action, sep->se_service, sep->se_proto,
1559 sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1560 (long)sep->se_bi, sep->se_server);
1561 }
1562
1563 #ifdef MULOG
1564 dolog(sep, ctrl)
1565 struct servtab *sep;
1566 int ctrl;
1567 {
1568 struct sockaddr sa;
1569 struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
1570 int len = sizeof(sa);
1571 struct hostent *hp;
1572 char *host, *dp, buf[BUFSIZ], *rfc931_name();
1573 int connected = 1;
1574
1575 if (sep->se_family != AF_INET)
1576 return;
1577
1578 if (getpeername(ctrl, &sa, &len) < 0) {
1579 if (errno != ENOTCONN) {
1580 syslog(LOG_ERR, "getpeername: %m");
1581 return;
1582 }
1583 if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1584 syslog(LOG_ERR, "recvfrom: %m");
1585 return;
1586 }
1587 connected = 0;
1588 }
1589 if (sa.sa_family != AF_INET) {
1590 syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1591 return;
1592 }
1593
1594 hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1595 sizeof (sin->sin_addr.s_addr), AF_INET);
1596
1597 host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1598
1599 switch (sep->se_log & ~MULOG_RFC931) {
1600 case 0:
1601 return;
1602 case 1:
1603 if (curdom == NULL || *curdom == '\0')
1604 break;
1605 dp = host + strlen(host) - strlen(curdom);
1606 if (dp < host)
1607 break;
1608 if (debug)
1609 fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1610 host, curdom);
1611 if (strcasecmp(dp, curdom) == 0)
1612 return;
1613 break;
1614 case 2:
1615 default:
1616 break;
1617 }
1618
1619 openlog("", LOG_NOWAIT, MULOG);
1620
1621 if (connected && (sep->se_log & MULOG_RFC931))
1622 syslog(LOG_INFO, "%s@%s wants %s",
1623 rfc931_name(sin, ctrl), host, sep->se_service);
1624 else
1625 syslog(LOG_INFO, "%s wants %s",
1626 host, sep->se_service);
1627 }
1628 /*
1629 * From tcp_log by
1630 * Wietse Venema, Eindhoven University of Technology, The Netherlands.
1631 */
1632 #if 0
1633 static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1634 #endif
1635
1636 #include <setjmp.h>
1637
1638 #define RFC931_PORT 113 /* Semi-well-known port */
1639 #define TIMEOUT 4
1640 #define TIMEOUT2 10
1641
1642 static jmp_buf timebuf;
1643
1644 /* timeout - handle timeouts */
1645
1646 static void timeout(sig)
1647 int sig;
1648 {
1649 longjmp(timebuf, sig);
1650 }
1651
1652 /* rfc931_name - return remote user name */
1653
1654 char *
1655 rfc931_name(there, ctrl)
1656 struct sockaddr_in *there; /* remote link information */
1657 int ctrl;
1658 {
1659 struct sockaddr_in here; /* local link information */
1660 struct sockaddr_in sin; /* for talking to RFC931 daemon */
1661 int length;
1662 int s;
1663 unsigned remote;
1664 unsigned local;
1665 static char user[256]; /* XXX */
1666 char buf[256];
1667 char *cp;
1668 char *result = "USER_UNKNOWN";
1669 int len;
1670
1671 /* Find out local port number of our stdin. */
1672
1673 length = sizeof(here);
1674 if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1675 syslog(LOG_ERR, "getsockname: %m");
1676 return (result);
1677 }
1678 /* Set up timer so we won't get stuck. */
1679
1680 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1681 syslog(LOG_ERR, "socket: %m");
1682 return (result);
1683 }
1684
1685 sin = here;
1686 sin.sin_port = htons(0);
1687 if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1688 syslog(LOG_ERR, "bind: %m");
1689 return (result);
1690 }
1691
1692 signal(SIGALRM, timeout);
1693 if (setjmp(timebuf)) {
1694 close(s); /* not: fclose(fp) */
1695 return (result);
1696 }
1697 alarm(TIMEOUT);
1698
1699 /* Connect to the RFC931 daemon. */
1700
1701 sin = *there;
1702 sin.sin_port = htons(RFC931_PORT);
1703 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1704 close(s);
1705 alarm(0);
1706 return (result);
1707 }
1708
1709 /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
1710 (void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
1711 ntohs(here.sin_port));
1712
1713
1714 for (len = 0, cp = buf; len < strlen(buf); ) {
1715 int n;
1716
1717 if ((n = write(s, cp, strlen(buf) - len)) == -1) {
1718 close(s);
1719 alarm(0);
1720 return (result);
1721 }
1722 cp += n;
1723 len += n;
1724 }
1725
1726 /* Read response */
1727 for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
1728 char c;
1729 if (read(s, &c, 1) != 1) {
1730 close(s);
1731 alarm(0);
1732 return (result);
1733 }
1734 if (c == '\n')
1735 break;
1736 *cp++ = c;
1737 }
1738 *cp = '\0';
1739
1740 if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
1741 && ntohs(there->sin_port) == remote
1742 && ntohs(here.sin_port) == local) {
1743
1744 /* Strip trailing carriage return. */
1745 if (cp = strchr(user, '\r'))
1746 *cp = 0;
1747 result = user;
1748 }
1749
1750 alarm(0);
1751 close(s);
1752 return (result);
1753 }
1754 #endif
1755