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