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