inetd.c revision 1.20 1 /* $NetBSD: inetd.c,v 1.20 1997/03/13 14:15:40 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.20 1997/03/13 14:15:40 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 shutdown(ctrl, 2);
528 close(ctrl);
529 continue;
530 }
531 if (lflag) {
532 syslog(allow_severity,
533 "connection from %.500s, service %s (%s)",
534 eval_client(&req), service, sep->se_proto);
535 }
536 #endif /* LIBWRAP */
537 if (sep->se_bi)
538 (*sep->se_bi->bi_fn)(ctrl, sep);
539 else {
540 if ((pwd = getpwnam(sep->se_user)) == NULL) {
541 syslog(LOG_ERR,
542 "getpwnam: %s: No such user",
543 sep->se_user);
544 if (sep->se_socktype != SOCK_STREAM)
545 recv(0, buf, sizeof (buf), 0);
546 _exit(1);
547 }
548 if (sep->se_group &&
549 (grp = getgrnam(sep->se_group)) == NULL) {
550 syslog(LOG_ERR,
551 "getgrnam: %s: No such group",
552 sep->se_group);
553 if (sep->se_socktype != SOCK_STREAM)
554 recv(0, buf, sizeof (buf), 0);
555 _exit(1);
556 }
557 if (pwd->pw_uid) {
558 if (sep->se_group)
559 pwd->pw_gid = grp->gr_gid;
560 (void) setgid((gid_t)pwd->pw_gid);
561 initgroups(pwd->pw_name, pwd->pw_gid);
562 (void) setuid((uid_t)pwd->pw_uid);
563 } else if (sep->se_group) {
564 (void) setgid((gid_t)grp->gr_gid);
565 }
566 if (debug)
567 fprintf(stderr, "%d execl %s\n",
568 getpid(), sep->se_server);
569 #ifdef MULOG
570 if (sep->se_log)
571 dolog(sep, ctrl);
572 #endif
573 dup2(ctrl, 0);
574 close(ctrl);
575 dup2(0, 1);
576 dup2(0, 2);
577 #ifdef RLIMIT_NOFILE
578 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
579 if (setrlimit(RLIMIT_NOFILE,
580 &rlim_ofile) < 0)
581 syslog(LOG_ERR,"setrlimit: %m");
582 }
583 #endif
584 for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
585 (void)close(tmpint);
586 execv(sep->se_server, sep->se_argv);
587 if (sep->se_socktype != SOCK_STREAM)
588 recv(0, buf, sizeof (buf), 0);
589 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
590 _exit(1);
591 }
592 }
593 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
594 close(ctrl);
595 }
596 }
597 }
598
599 void
600 reapchild()
601 {
602 int status;
603 int pid;
604 register struct servtab *sep;
605
606 for (;;) {
607 pid = wait3(&status, WNOHANG, (struct rusage *)0);
608 if (pid <= 0)
609 break;
610 if (debug)
611 fprintf(stderr, "%d reaped\n", pid);
612 for (sep = servtab; sep; sep = sep->se_next)
613 if (sep->se_wait == pid) {
614 if (WIFEXITED(status) && WEXITSTATUS(status))
615 syslog(LOG_WARNING,
616 "%s: exit status 0x%x",
617 sep->se_server, WEXITSTATUS(status));
618 else if (WIFSIGNALED(status))
619 syslog(LOG_WARNING,
620 "%s: exit signal 0x%x",
621 sep->se_server, WTERMSIG(status));
622 sep->se_wait = 1;
623 FD_SET(sep->se_fd, &allsock);
624 nsock++;
625 if (debug)
626 fprintf(stderr, "restored %s, fd %d\n",
627 sep->se_service, sep->se_fd);
628 }
629 }
630 }
631
632 void
633 config()
634 {
635 register struct servtab *sep, *cp, **sepp;
636 struct servtab *getconfigent(), *enter();
637 long omask;
638 int n;
639
640 if (!setconfig()) {
641 syslog(LOG_ERR, "%s: %m", CONFIG);
642 return;
643 }
644 for (sep = servtab; sep; sep = sep->se_next)
645 sep->se_checked = 0;
646 while (cp = getconfigent()) {
647 for (sep = servtab; sep; sep = sep->se_next)
648 if (strcmp(sep->se_service, cp->se_service) == 0 &&
649 strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
650 strcmp(sep->se_proto, cp->se_proto) == 0)
651 break;
652 if (sep != 0) {
653 int i;
654
655 #define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
656
657 omask = sigblock(SIGBLOCK);
658 /*
659 * sep->se_wait may be holding the pid of a daemon
660 * that we're waiting for. If so, don't overwrite
661 * it unless the config file explicitly says don't
662 * wait.
663 */
664 if (cp->se_bi == 0 &&
665 (sep->se_wait == 1 || cp->se_wait == 0))
666 sep->se_wait = cp->se_wait;
667 SWAP(int, cp->se_max, sep->se_max);
668 SWAP(char *, sep->se_user, cp->se_user);
669 SWAP(char *, sep->se_group, cp->se_group);
670 SWAP(char *, sep->se_server, cp->se_server);
671 for (i = 0; i < MAXARGV; i++)
672 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
673 #undef SWAP
674 if (isrpcservice(sep))
675 unregister_rpc(sep);
676 sep->se_rpcversl = cp->se_rpcversl;
677 sep->se_rpcversh = cp->se_rpcversh;
678 sigsetmask(omask);
679 freeconfig(cp);
680 if (debug)
681 print_service("REDO", sep);
682 } else {
683 sep = enter(cp);
684 if (debug)
685 print_service("ADD ", sep);
686 }
687 sep->se_checked = 1;
688
689 switch (sep->se_family) {
690 case AF_UNIX:
691 if (sep->se_fd != -1)
692 break;
693 (void)unlink(sep->se_service);
694 n = strlen(sep->se_service);
695 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
696 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
697 strncpy(sep->se_ctrladdr_un.sun_path,
698 sep->se_service, n);
699 sep->se_ctrladdr_un.sun_family = AF_UNIX;
700 sep->se_ctrladdr_size = n +
701 sizeof sep->se_ctrladdr_un -
702 sizeof sep->se_ctrladdr_un.sun_path;
703 setup(sep);
704 break;
705 case AF_INET:
706 sep->se_ctrladdr_in.sin_family = AF_INET;
707 if (!strcmp(sep->se_hostaddr,"*"))
708 sep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
709 else if (!inet_aton(sep->se_hostaddr,&sep->se_ctrladdr_in.sin_addr)) {
710 /* Do we really want to support hostname lookups here? */
711 struct hostent *hp;
712 hp = gethostbyname(sep->se_hostaddr);
713 if (hp == 0) {
714 syslog(LOG_ERR,"%s: unknown host",sep->se_hostaddr);
715 continue;
716 } else if (hp->h_addrtype != AF_INET) {
717 syslog(LOG_ERR,"%s: address isn't an Internet address",sep->se_hostaddr);
718 continue;
719 } else if (hp->h_length != sizeof(struct in_addr)) {
720 syslog(LOG_ERR,"%s: address size wrong (under DNS corruption attack?)",sep->se_hostaddr);
721 continue;
722 } else {
723 bcopy(hp->h_addr_list[0],&sep->se_ctrladdr_in.sin_addr,sizeof(struct in_addr));
724 }
725 }
726 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
727 if (isrpcservice(sep)) {
728 struct rpcent *rp;
729
730 sep->se_rpcprog = atoi(sep->se_service);
731 if (sep->se_rpcprog == 0) {
732 rp = getrpcbyname(sep->se_service);
733 if (rp == 0) {
734 syslog(LOG_ERR,
735 "%s: unknown service",
736 sep->se_service);
737 continue;
738 }
739 sep->se_rpcprog = rp->r_number;
740 }
741 if (sep->se_fd == -1)
742 setup(sep);
743 if (sep->se_fd != -1)
744 register_rpc(sep);
745 } else {
746 u_short port = htons(atoi(sep->se_service));
747
748 if (!port) {
749 sp = getservbyname(sep->se_service,
750 sep->se_proto);
751 if (sp == 0) {
752 syslog(LOG_ERR,
753 "%s/%s: unknown service",
754 sep->se_service, sep->se_proto);
755 continue;
756 }
757 port = sp->s_port;
758 }
759 if (port != sep->se_ctrladdr_in.sin_port) {
760 sep->se_ctrladdr_in.sin_port = port;
761 if (sep->se_fd != -1) {
762 FD_CLR(sep->se_fd, &allsock);
763 nsock--;
764 (void) close(sep->se_fd);
765 }
766 sep->se_fd = -1;
767 }
768 if (sep->se_fd == -1)
769 setup(sep);
770 }
771 }
772 }
773 endconfig();
774 /*
775 * Purge anything not looked at above.
776 */
777 omask = sigblock(SIGBLOCK);
778 sepp = &servtab;
779 while (sep = *sepp) {
780 if (sep->se_checked) {
781 sepp = &sep->se_next;
782 continue;
783 }
784 *sepp = sep->se_next;
785 if (sep->se_fd != -1) {
786 FD_CLR(sep->se_fd, &allsock);
787 nsock--;
788 (void) close(sep->se_fd);
789 }
790 if (isrpcservice(sep))
791 unregister_rpc(sep);
792 if (sep->se_family == AF_UNIX)
793 (void)unlink(sep->se_service);
794 if (debug)
795 print_service("FREE", sep);
796 freeconfig(sep);
797 free((char *)sep);
798 }
799 (void) sigsetmask(omask);
800 }
801
802 void
803 retry()
804 {
805 register struct servtab *sep;
806
807 timingout = 0;
808 for (sep = servtab; sep; sep = sep->se_next) {
809 if (sep->se_fd == -1) {
810 switch (sep->se_family) {
811 case AF_UNIX:
812 case AF_INET:
813 setup(sep);
814 if (sep->se_fd != -1 && isrpcservice(sep))
815 register_rpc(sep);
816 break;
817 }
818 }
819 }
820 }
821
822 void
823 goaway()
824 {
825 register struct servtab *sep;
826
827 for (sep = servtab; sep; sep = sep->se_next) {
828 if (sep->se_fd == -1)
829 continue;
830
831 switch (sep->se_family) {
832 case AF_UNIX:
833 (void)unlink(sep->se_service);
834 break;
835 case AF_INET:
836 if (sep->se_wait == 1 && isrpcservice(sep))
837 unregister_rpc(sep);
838 break;
839 }
840 (void)close(sep->se_fd);
841 }
842 (void)unlink(_PATH_INETDPID);
843 exit(0);
844 }
845
846
847 setup(sep)
848 register struct servtab *sep;
849 {
850 int on = 1;
851
852 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
853 syslog(LOG_ERR, "%s/%s: socket: %m",
854 sep->se_service, sep->se_proto);
855 return;
856 }
857 #define turnon(fd, opt) \
858 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
859 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
860 turnon(sep->se_fd, SO_DEBUG) < 0)
861 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
862 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
863 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
864 #undef turnon
865 if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
866 syslog(LOG_ERR, "%s/%s: bind: %m",
867 sep->se_service, sep->se_proto);
868 (void) close(sep->se_fd);
869 sep->se_fd = -1;
870 if (!timingout) {
871 timingout = 1;
872 alarm(RETRYTIME);
873 }
874 return;
875 }
876 if (sep->se_socktype == SOCK_STREAM)
877 listen(sep->se_fd, 10);
878
879 FD_SET(sep->se_fd, &allsock);
880 nsock++;
881 if (sep->se_fd > maxsock) {
882 maxsock = sep->se_fd;
883 if (maxsock > rlim_ofile_cur - FD_MARGIN)
884 bump_nofile();
885 }
886 }
887
888 register_rpc(sep)
889 register struct servtab *sep;
890 {
891 #ifdef RPC
892 int n;
893 struct sockaddr_in sin;
894 struct protoent *pp;
895
896 if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
897 syslog(LOG_ERR, "%s: getproto: %m",
898 sep->se_proto);
899 return;
900 }
901 n = sizeof sin;
902 if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
903 syslog(LOG_ERR, "%s/%s: getsockname: %m",
904 sep->se_service, sep->se_proto);
905 return;
906 }
907
908 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
909 if (debug)
910 fprintf(stderr, "pmap_set: %u %u %u %u\n",
911 sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
912 (void)pmap_unset(sep->se_rpcprog, n);
913 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
914 syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
915 sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
916 }
917 #endif /* RPC */
918 }
919
920 unregister_rpc(sep)
921 register struct servtab *sep;
922 {
923 #ifdef RPC
924 int n;
925
926 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
927 if (debug)
928 fprintf(stderr, "pmap_unset(%u, %u)\n",
929 sep->se_rpcprog, n);
930 if (!pmap_unset(sep->se_rpcprog, n))
931 syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
932 sep->se_rpcprog, n);
933 }
934 #endif /* RPC */
935 }
936
937
938 struct servtab *
939 enter(cp)
940 struct servtab *cp;
941 {
942 register struct servtab *sep;
943 long omask;
944
945 sep = (struct servtab *)malloc(sizeof (*sep));
946 if (sep == (struct servtab *)0) {
947 syslog(LOG_ERR, "Out of memory.");
948 exit(-1);
949 }
950 *sep = *cp;
951 sep->se_fd = -1;
952 sep->se_rpcprog = -1;
953 omask = sigblock(SIGBLOCK);
954 sep->se_next = servtab;
955 servtab = sep;
956 sigsetmask(omask);
957 return (sep);
958 }
959
960 FILE *fconfig = NULL;
961 struct servtab serv;
962 char line[256];
963 char *skip(), *nextline();
964 char *defhost;
965
966 setconfig()
967 {
968 if (defhost) free(defhost);
969 defhost = newstr("*");
970 if (fconfig != NULL) {
971 fseek(fconfig, 0L, SEEK_SET);
972 return (1);
973 }
974 fconfig = fopen(CONFIG, "r");
975 return (fconfig != NULL);
976 }
977
978 endconfig()
979 {
980 if (fconfig) {
981 (void) fclose(fconfig);
982 fconfig = NULL;
983 }
984 if (defhost) {
985 free(defhost);
986 defhost = 0;
987 }
988 }
989
990 struct servtab *
991 getconfigent()
992 {
993 register struct servtab *sep = &serv;
994 int argc;
995 char *cp, *arg;
996 char *hostdelim;
997
998 more:
999 #ifdef MULOG
1000 while ((cp = nextline(fconfig)) && *cp == '#') {
1001 /* Avoid use of `skip' if there is a danger of it looking
1002 * at continuation lines.
1003 */
1004 do {
1005 cp++;
1006 } while (*cp == ' ' || *cp == '\t');
1007 if (*cp == '\0')
1008 continue;
1009 if ((arg = skip(&cp)) == NULL)
1010 continue;
1011 if (strcmp(arg, "DOMAIN"))
1012 continue;
1013 if (curdom)
1014 free(curdom);
1015 curdom = NULL;
1016 while (*cp == ' ' || *cp == '\t')
1017 cp++;
1018 if (*cp == '\0')
1019 continue;
1020 arg = cp;
1021 while (*cp && *cp != ' ' && *cp != '\t')
1022 cp++;
1023 if (*cp != '\0')
1024 *cp++ = '\0';
1025 curdom = newstr(arg);
1026 }
1027 #else
1028 while ((cp = nextline(fconfig)) && *cp == '#')
1029 ;
1030 #endif
1031 if (cp == NULL)
1032 return ((struct servtab *)0);
1033 bzero((char *)sep, sizeof *sep);
1034 sep->se_service = newstr(skip(&cp));
1035 hostdelim = rindex(sep->se_service,':');
1036 if (hostdelim) {
1037 *hostdelim = '\0';
1038 sep->se_hostaddr = sep->se_service;
1039 sep->se_service = newstr(hostdelim+1);
1040 } else {
1041 sep->se_hostaddr = newstr(defhost);
1042 }
1043 arg = skip(&cp);
1044 if (arg == NULL) {
1045 if (!strcmp(sep->se_service,"")) {
1046 /* if we didn't have a colon, still OK */
1047 free(defhost);
1048 defhost = sep->se_hostaddr;
1049 } else
1050 free(sep->se_hostaddr);
1051 free(sep->se_service);
1052 goto more;
1053 }
1054
1055 if (strcmp(arg, "stream") == 0)
1056 sep->se_socktype = SOCK_STREAM;
1057 else if (strcmp(arg, "dgram") == 0)
1058 sep->se_socktype = SOCK_DGRAM;
1059 else if (strcmp(arg, "rdm") == 0)
1060 sep->se_socktype = SOCK_RDM;
1061 else if (strcmp(arg, "seqpacket") == 0)
1062 sep->se_socktype = SOCK_SEQPACKET;
1063 else if (strcmp(arg, "raw") == 0)
1064 sep->se_socktype = SOCK_RAW;
1065 else
1066 sep->se_socktype = -1;
1067
1068 sep->se_proto = newstr(skip(&cp));
1069 if (strcmp(sep->se_proto, "unix") == 0) {
1070 sep->se_family = AF_UNIX;
1071 } else {
1072 sep->se_family = AF_INET;
1073 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1074 #ifdef RPC
1075 char *cp, *ccp;
1076 cp = index(sep->se_service, '/');
1077 if (cp == 0) {
1078 syslog(LOG_ERR, "%s: no rpc version",
1079 sep->se_service);
1080 goto more;
1081 }
1082 *cp++ = '\0';
1083 sep->se_rpcversl =
1084 sep->se_rpcversh = strtol(cp, &ccp, 0);
1085 if (ccp == cp) {
1086 badafterall:
1087 syslog(LOG_ERR, "%s/%s: bad rpc version",
1088 sep->se_service, cp);
1089 goto more;
1090 }
1091 if (*ccp == '-') {
1092 cp = ccp + 1;
1093 sep->se_rpcversh = strtol(cp, &ccp, 0);
1094 if (ccp == cp)
1095 goto badafterall;
1096 }
1097 #else
1098 syslog(LOG_ERR, "%s: rpc services not suported",
1099 sep->se_service);
1100 goto more;
1101 #endif /* RPC */
1102 }
1103 }
1104 arg = skip(&cp);
1105 if (arg == NULL)
1106 goto more;
1107 {
1108 char *s = index(arg, '.');
1109 if (s) {
1110 *s++ = '\0';
1111 sep->se_max = atoi(s);
1112 } else
1113 sep->se_max = TOOMANY;
1114 }
1115 sep->se_wait = strcmp(arg, "wait") == 0;
1116 sep->se_user = newstr(skip(&cp));
1117 if (sep->se_group = index(sep->se_user, '.')) {
1118 *sep->se_group++ = '\0';
1119 }
1120 sep->se_server = newstr(skip(&cp));
1121 if (strcmp(sep->se_server, "internal") == 0) {
1122 register struct biltin *bi;
1123
1124 for (bi = biltins; bi->bi_service; bi++)
1125 if (bi->bi_socktype == sep->se_socktype &&
1126 strcmp(bi->bi_service, sep->se_service) == 0)
1127 break;
1128 if (bi->bi_service == 0) {
1129 syslog(LOG_ERR, "internal service %s unknown\n",
1130 sep->se_service);
1131 goto more;
1132 }
1133 sep->se_bi = bi;
1134 sep->se_wait = bi->bi_wait;
1135 } else
1136 sep->se_bi = NULL;
1137 argc = 0;
1138 for (arg = skip(&cp); cp; arg = skip(&cp)) {
1139 #if MULOG
1140 char *colon, *rindex();
1141
1142 if (argc == 0 && (colon = rindex(arg, ':'))) {
1143 while (arg < colon) {
1144 int x;
1145 char *ccp;
1146
1147 switch (*arg++) {
1148 case 'l':
1149 x = 1;
1150 if (isdigit(*arg)) {
1151 x = strtol(arg, &ccp, 0);
1152 if (ccp == arg)
1153 break;
1154 arg = ccp;
1155 }
1156 sep->se_log &= ~MULOG_RFC931;
1157 sep->se_log |= x;
1158 break;
1159 case 'a':
1160 sep->se_log |= MULOG_RFC931;
1161 break;
1162 default:
1163 break;
1164 }
1165 }
1166 arg = colon + 1;
1167 }
1168 #endif
1169 if (argc < MAXARGV)
1170 sep->se_argv[argc++] = newstr(arg);
1171 }
1172 while (argc <= MAXARGV)
1173 sep->se_argv[argc++] = NULL;
1174 return (sep);
1175 }
1176
1177 freeconfig(cp)
1178 register struct servtab *cp;
1179 {
1180 int i;
1181
1182 if (cp->se_hostaddr)
1183 free(cp->se_hostaddr);
1184 if (cp->se_service)
1185 free(cp->se_service);
1186 if (cp->se_proto)
1187 free(cp->se_proto);
1188 if (cp->se_user)
1189 free(cp->se_user);
1190 /* Note: se_group is part of the newstr'ed se_user */
1191 if (cp->se_server)
1192 free(cp->se_server);
1193 for (i = 0; i < MAXARGV; i++)
1194 if (cp->se_argv[i])
1195 free(cp->se_argv[i]);
1196 }
1197
1198 char *
1199 skip(cpp)
1200 char **cpp;
1201 {
1202 register char *cp = *cpp;
1203 char *start;
1204
1205 if (*cpp == NULL)
1206 return ((char *)0);
1207
1208 again:
1209 while (*cp == ' ' || *cp == '\t')
1210 cp++;
1211 if (*cp == '\0') {
1212 int c;
1213
1214 c = getc(fconfig);
1215 (void) ungetc(c, fconfig);
1216 if (c == ' ' || c == '\t')
1217 if (cp = nextline(fconfig))
1218 goto again;
1219 *cpp = (char *)0;
1220 return ((char *)0);
1221 }
1222 start = cp;
1223 while (*cp && *cp != ' ' && *cp != '\t')
1224 cp++;
1225 if (*cp != '\0')
1226 *cp++ = '\0';
1227 *cpp = cp;
1228 return (start);
1229 }
1230
1231 char *
1232 nextline(fd)
1233 FILE *fd;
1234 {
1235 char *cp;
1236
1237 if (fgets(line, sizeof (line), fd) == NULL)
1238 return ((char *)0);
1239 cp = index(line, '\n');
1240 if (cp)
1241 *cp = '\0';
1242 return (line);
1243 }
1244
1245 char *
1246 newstr(cp)
1247 char *cp;
1248 {
1249 if (cp = strdup(cp ? cp : ""))
1250 return(cp);
1251 syslog(LOG_ERR, "strdup: %m");
1252 exit(-1);
1253 }
1254
1255 inetd_setproctitle(a, s)
1256 char *a;
1257 int s;
1258 {
1259 int size;
1260 register char *cp;
1261 struct sockaddr_in sin;
1262 char buf[80];
1263
1264 cp = Argv[0];
1265 size = sizeof(sin);
1266 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1267 (void)snprintf(buf, sizeof buf, "-%s [%s]", a,
1268 inet_ntoa(sin.sin_addr));
1269 else
1270 (void)snprintf(buf, sizeof buf, "-%s", a);
1271 strncpy(cp, buf, LastArg - cp);
1272 cp += strlen(cp);
1273 while (cp < LastArg)
1274 *cp++ = ' ';
1275 }
1276
1277 logpid()
1278 {
1279 FILE *fp;
1280
1281 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1282 fprintf(fp, "%u\n", getpid());
1283 (void)fclose(fp);
1284 }
1285 }
1286
1287 bump_nofile()
1288 {
1289 #ifdef RLIMIT_NOFILE
1290
1291 #define FD_CHUNK 32
1292
1293 struct rlimit rl;
1294
1295 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1296 syslog(LOG_ERR, "getrlimit: %m");
1297 return -1;
1298 }
1299 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1300 if (rl.rlim_cur <= rlim_ofile_cur) {
1301 syslog(LOG_ERR,
1302 "bump_nofile: cannot extend file limit, max = %d",
1303 rl.rlim_cur);
1304 return -1;
1305 }
1306
1307 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1308 syslog(LOG_ERR, "setrlimit: %m");
1309 return -1;
1310 }
1311
1312 rlim_ofile_cur = rl.rlim_cur;
1313 return 0;
1314
1315 #else
1316 syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
1317 return -1;
1318 #endif
1319 }
1320
1321 /*
1322 * Internet services provided internally by inetd:
1323 */
1324 #define BUFSIZE 4096
1325
1326 /* ARGSUSED */
1327 echo_stream(s, sep) /* Echo service -- echo data back */
1328 int s;
1329 struct servtab *sep;
1330 {
1331 char buffer[BUFSIZE];
1332 int i;
1333
1334 inetd_setproctitle(sep->se_service, s);
1335 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1336 write(s, buffer, i) > 0)
1337 ;
1338 exit(0);
1339 }
1340
1341 /* ARGSUSED */
1342 echo_dg(s, sep) /* Echo service -- echo data back */
1343 int s;
1344 struct servtab *sep;
1345 {
1346 char buffer[BUFSIZE];
1347 int i, size;
1348 struct sockaddr sa;
1349
1350 size = sizeof(sa);
1351 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1352 return;
1353 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1354 }
1355
1356 /* ARGSUSED */
1357 discard_stream(s, sep) /* Discard service -- ignore data */
1358 int s;
1359 struct servtab *sep;
1360 {
1361 char buffer[BUFSIZE];
1362
1363 inetd_setproctitle(sep->se_service, s);
1364 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1365 errno == EINTR)
1366 ;
1367 exit(0);
1368 }
1369
1370 /* ARGSUSED */
1371 discard_dg(s, sep) /* Discard service -- ignore data */
1372 int s;
1373 struct servtab *sep;
1374 {
1375 char buffer[BUFSIZE];
1376
1377 (void) read(s, buffer, sizeof(buffer));
1378 }
1379
1380 #include <ctype.h>
1381 #define LINESIZ 72
1382 char ring[128];
1383 char *endring;
1384
1385 initring()
1386 {
1387 register int i;
1388
1389 endring = ring;
1390
1391 for (i = 0; i <= 128; ++i)
1392 if (isprint(i))
1393 *endring++ = i;
1394 }
1395
1396 /* ARGSUSED */
1397 chargen_stream(s, sep) /* Character generator */
1398 int s;
1399 struct servtab *sep;
1400 {
1401 register char *rs;
1402 int len;
1403 char text[LINESIZ+2];
1404
1405 inetd_setproctitle(sep->se_service, s);
1406
1407 if (!endring) {
1408 initring();
1409 rs = ring;
1410 }
1411
1412 text[LINESIZ] = '\r';
1413 text[LINESIZ + 1] = '\n';
1414 for (rs = ring;;) {
1415 if ((len = endring - rs) >= LINESIZ)
1416 bcopy(rs, text, LINESIZ);
1417 else {
1418 bcopy(rs, text, len);
1419 bcopy(ring, text + len, LINESIZ - len);
1420 }
1421 if (++rs == endring)
1422 rs = ring;
1423 if (write(s, text, sizeof(text)) != sizeof(text))
1424 break;
1425 }
1426 exit(0);
1427 }
1428
1429 /* ARGSUSED */
1430 chargen_dg(s, sep) /* Character generator */
1431 int s;
1432 struct servtab *sep;
1433 {
1434 struct sockaddr sa;
1435 static char *rs;
1436 int len, size;
1437 char text[LINESIZ+2];
1438
1439 if (endring == 0) {
1440 initring();
1441 rs = ring;
1442 }
1443
1444 size = sizeof(sa);
1445 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1446 return;
1447
1448 if ((len = endring - rs) >= LINESIZ)
1449 bcopy(rs, text, LINESIZ);
1450 else {
1451 bcopy(rs, text, len);
1452 bcopy(ring, text + len, LINESIZ - len);
1453 }
1454 if (++rs == endring)
1455 rs = ring;
1456 text[LINESIZ] = '\r';
1457 text[LINESIZ + 1] = '\n';
1458 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1459 }
1460
1461 /*
1462 * Return a machine readable date and time, in the form of the
1463 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1464 * returns the number of seconds since midnight, Jan 1, 1970,
1465 * we must add 2208988800 seconds to this figure to make up for
1466 * some seventy years Bell Labs was asleep.
1467 */
1468
1469 long
1470 machtime()
1471 {
1472 struct timeval tv;
1473
1474 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1475 fprintf(stderr, "Unable to get time of day\n");
1476 return (0L);
1477 }
1478 return (htonl((long)tv.tv_sec + 2208988800UL));
1479 }
1480
1481 /* ARGSUSED */
1482 machtime_stream(s, sep)
1483 int s;
1484 struct servtab *sep;
1485 {
1486 long result;
1487
1488 result = machtime();
1489 (void) write(s, (char *) &result, sizeof(result));
1490 }
1491
1492 /* ARGSUSED */
1493 machtime_dg(s, sep)
1494 int s;
1495 struct servtab *sep;
1496 {
1497 long result;
1498 struct sockaddr sa;
1499 int size;
1500
1501 size = sizeof(sa);
1502 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1503 return;
1504 result = machtime();
1505 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1506 }
1507
1508 /* ARGSUSED */
1509 daytime_stream(s, sep) /* Return human-readable time of day */
1510 int s;
1511 struct servtab *sep;
1512 {
1513 char buffer[256];
1514 time_t time(), clock;
1515 int len;
1516
1517 clock = time((time_t *) 0);
1518
1519 len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1520 (void) write(s, buffer, len);
1521 }
1522
1523 /* ARGSUSED */
1524 daytime_dg(s, sep) /* Return human-readable time of day */
1525 int s;
1526 struct servtab *sep;
1527 {
1528 char buffer[256];
1529 time_t time(), clock;
1530 struct sockaddr sa;
1531 int size;
1532
1533 clock = time((time_t *) 0);
1534
1535 size = sizeof(sa);
1536 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1537 return;
1538 size = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1539 (void) sendto(s, buffer, size, 0, &sa, sizeof(sa));
1540 }
1541
1542 /*
1543 * print_service:
1544 * Dump relevant information to stderr
1545 */
1546 print_service(action, sep)
1547 char *action;
1548 struct servtab *sep;
1549 {
1550 if (isrpcservice(sep))
1551 fprintf(stderr,
1552 "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1553 action, sep->se_service,
1554 sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
1555 sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1556 (long)sep->se_bi, sep->se_server);
1557 else
1558 fprintf(stderr,
1559 "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1560 action, sep->se_service, sep->se_proto,
1561 sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1562 (long)sep->se_bi, sep->se_server);
1563 }
1564
1565 #ifdef MULOG
1566 dolog(sep, ctrl)
1567 struct servtab *sep;
1568 int ctrl;
1569 {
1570 struct sockaddr sa;
1571 struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
1572 int len = sizeof(sa);
1573 struct hostent *hp;
1574 char *host, *dp, buf[BUFSIZ], *rfc931_name();
1575 int connected = 1;
1576
1577 if (sep->se_family != AF_INET)
1578 return;
1579
1580 if (getpeername(ctrl, &sa, &len) < 0) {
1581 if (errno != ENOTCONN) {
1582 syslog(LOG_ERR, "getpeername: %m");
1583 return;
1584 }
1585 if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1586 syslog(LOG_ERR, "recvfrom: %m");
1587 return;
1588 }
1589 connected = 0;
1590 }
1591 if (sa.sa_family != AF_INET) {
1592 syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1593 return;
1594 }
1595
1596 hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1597 sizeof (sin->sin_addr.s_addr), AF_INET);
1598
1599 host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1600
1601 switch (sep->se_log & ~MULOG_RFC931) {
1602 case 0:
1603 return;
1604 case 1:
1605 if (curdom == NULL || *curdom == '\0')
1606 break;
1607 dp = host + strlen(host) - strlen(curdom);
1608 if (dp < host)
1609 break;
1610 if (debug)
1611 fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1612 host, curdom);
1613 if (strcasecmp(dp, curdom) == 0)
1614 return;
1615 break;
1616 case 2:
1617 default:
1618 break;
1619 }
1620
1621 openlog("", LOG_NOWAIT, MULOG);
1622
1623 if (connected && (sep->se_log & MULOG_RFC931))
1624 syslog(LOG_INFO, "%s@%s wants %s",
1625 rfc931_name(sin, ctrl), host, sep->se_service);
1626 else
1627 syslog(LOG_INFO, "%s wants %s",
1628 host, sep->se_service);
1629 }
1630 /*
1631 * From tcp_log by
1632 * Wietse Venema, Eindhoven University of Technology, The Netherlands.
1633 */
1634 #if 0
1635 static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1636 #endif
1637
1638 #include <setjmp.h>
1639
1640 #define RFC931_PORT 113 /* Semi-well-known port */
1641 #define TIMEOUT 4
1642 #define TIMEOUT2 10
1643
1644 static jmp_buf timebuf;
1645
1646 /* timeout - handle timeouts */
1647
1648 static void timeout(sig)
1649 int sig;
1650 {
1651 longjmp(timebuf, sig);
1652 }
1653
1654 /* rfc931_name - return remote user name */
1655
1656 char *
1657 rfc931_name(there, ctrl)
1658 struct sockaddr_in *there; /* remote link information */
1659 int ctrl;
1660 {
1661 struct sockaddr_in here; /* local link information */
1662 struct sockaddr_in sin; /* for talking to RFC931 daemon */
1663 int length;
1664 int s;
1665 unsigned remote;
1666 unsigned local;
1667 static char user[256]; /* XXX */
1668 char buf[256];
1669 char *cp;
1670 char *result = "USER_UNKNOWN";
1671 int len;
1672
1673 /* Find out local port number of our stdin. */
1674
1675 length = sizeof(here);
1676 if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1677 syslog(LOG_ERR, "getsockname: %m");
1678 return (result);
1679 }
1680 /* Set up timer so we won't get stuck. */
1681
1682 if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1683 syslog(LOG_ERR, "socket: %m");
1684 return (result);
1685 }
1686
1687 sin = here;
1688 sin.sin_port = htons(0);
1689 if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1690 syslog(LOG_ERR, "bind: %m");
1691 return (result);
1692 }
1693
1694 signal(SIGALRM, timeout);
1695 if (setjmp(timebuf)) {
1696 close(s); /* not: fclose(fp) */
1697 return (result);
1698 }
1699 alarm(TIMEOUT);
1700
1701 /* Connect to the RFC931 daemon. */
1702
1703 sin = *there;
1704 sin.sin_port = htons(RFC931_PORT);
1705 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1706 close(s);
1707 alarm(0);
1708 return (result);
1709 }
1710
1711 /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
1712 (void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
1713 ntohs(here.sin_port));
1714
1715
1716 for (len = 0, cp = buf; len < strlen(buf); ) {
1717 int n;
1718
1719 if ((n = write(s, cp, strlen(buf) - len)) == -1) {
1720 close(s);
1721 alarm(0);
1722 return (result);
1723 }
1724 cp += n;
1725 len += n;
1726 }
1727
1728 /* Read response */
1729 for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
1730 char c;
1731 if (read(s, &c, 1) != 1) {
1732 close(s);
1733 alarm(0);
1734 return (result);
1735 }
1736 if (c == '\n')
1737 break;
1738 *cp++ = c;
1739 }
1740 *cp = '\0';
1741
1742 if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
1743 && ntohs(there->sin_port) == remote
1744 && ntohs(here.sin_port) == local) {
1745
1746 /* Strip trailing carriage return. */
1747 if (cp = strchr(user, '\r'))
1748 *cp = 0;
1749 result = user;
1750 }
1751
1752 alarm(0);
1753 close(s);
1754 return (result);
1755 }
1756 #endif
1757