inetd.c revision 1.2 1 /*
2 * Copyright (c) 1983,1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)inetd.c 5.30 (Berkeley) 6/3/91";
42 #endif /* not lint */
43
44 /*
45 * Inetd - Internet super-server
46 *
47 * This program invokes all internet services as needed.
48 * connection-oriented services are invoked each time a
49 * connection is made, by creating a process. This process
50 * is passed the connection as file descriptor 0 and is
51 * expected to do a getpeername to find out the source host
52 * and port.
53 *
54 * Datagram oriented services are invoked when a datagram
55 * arrives; a process is created and passed a pending message
56 * on file descriptor 0. Datagram servers may either connect
57 * to their peer, freeing up the original socket for inetd
58 * to receive further messages on, or ``take over the socket'',
59 * processing all arriving datagrams and, eventually, timing
60 * out. The first type of server is said to be ``multi-threaded'';
61 * the second type of server ``single-threaded''.
62 *
63 * Inetd uses a configuration file which is read at startup
64 * and, possibly, at some later time in response to a hangup signal.
65 * The configuration file is ``free format'' with fields given in the
66 * order shown below. Continuation lines for an entry must being with
67 * a space or tab. All fields must be present in each entry.
68 *
69 * service name must be in /etc/services
70 * socket type stream/dgram/raw/rdm/seqpacket
71 * protocol must be in /etc/protocols
72 * wait/nowait single-threaded/multi-threaded
73 * user user to run daemon as
74 * server program full path name
75 * server program arguments maximum of MAXARGS (20)
76 *
77 * For RPC services
78 * service name/version must be in /etc/rpc
79 * socket type stream/dgram/raw/rdm/seqpacket
80 * protocol must be in /etc/protocols
81 * wait/nowait single-threaded/multi-threaded
82 * user user to run daemon as
83 * server program full path name
84 * server program arguments maximum of MAXARGS (20)
85 *
86 * Comment lines are indicated by a `#' in column 1.
87 */
88 #include <sys/param.h>
89 #include <sys/stat.h>
90 #include <sys/ioctl.h>
91 #include <sys/socket.h>
92 #include <sys/file.h>
93 #include <sys/wait.h>
94 #include <sys/time.h>
95 #include <sys/resource.h>
96
97 #include <netinet/in.h>
98 #include <arpa/inet.h>
99
100 #include <errno.h>
101 #include <signal.h>
102 #include <netdb.h>
103 #include <syslog.h>
104 #include <pwd.h>
105 #include <stdio.h>
106 #include <string.h>
107 #include <rpc/rpc.h>
108 #include "pathnames.h"
109
110 #define TOOMANY 40 /* don't start more than TOOMANY */
111 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
112 #define RETRYTIME (60*10) /* retry after bind or server fail */
113
114 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
115
116 void config(), reapchild(), retry(), unregisterrpc();
117
118 int debug = 0;
119 int nsock, maxsock;
120 fd_set allsock;
121 int options;
122 int timingout;
123 struct servent *sp;
124 struct rpcent *rpc;
125
126 struct servtab {
127 char *se_service; /* name of service */
128 int se_socktype; /* type of socket to use */
129 char *se_proto; /* protocol used */
130 short se_wait; /* single threaded server */
131 short se_checked; /* looked at during merge */
132 char *se_user; /* user name to run as */
133 struct biltin *se_bi; /* if built-in, description */
134 char *se_server; /* server program */
135 #define MAXARGV 20
136 char *se_argv[MAXARGV+1]; /* program arguments */
137 int se_fd; /* open descriptor */
138 struct sockaddr_in se_ctrladdr;/* bound address */
139 int se_rpc; /* ==1 if this is an RPC service */
140 int se_rpc_prog; /* RPC program number */
141 u_int se_rpc_lowvers; /* RPC low version */
142 u_int se_rpc_highvers; /* RPC high version */
143 int se_count; /* number started since se_time */
144 struct timeval se_time; /* start of se_count */
145 struct servtab *se_next;
146 } *servtab;
147
148 int echo_stream(), discard_stream(), machtime_stream();
149 int daytime_stream(), chargen_stream();
150 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
151
152 struct biltin {
153 char *bi_service; /* internally provided service name */
154 int bi_socktype; /* type of socket supported */
155 short bi_fork; /* 1 if should fork before call */
156 short bi_wait; /* 1 if should wait for child */
157 int (*bi_fn)(); /* function which performs it */
158 } biltins[] = {
159 /* Echo received data */
160 "echo", SOCK_STREAM, 1, 0, echo_stream,
161 "echo", SOCK_DGRAM, 0, 0, echo_dg,
162
163 /* Internet /dev/null */
164 "discard", SOCK_STREAM, 1, 0, discard_stream,
165 "discard", SOCK_DGRAM, 0, 0, discard_dg,
166
167 /* Return 32 bit time since 1970 */
168 "time", SOCK_STREAM, 0, 0, machtime_stream,
169 "time", SOCK_DGRAM, 0, 0, machtime_dg,
170
171 /* Return human-readable time */
172 "daytime", SOCK_STREAM, 0, 0, daytime_stream,
173 "daytime", SOCK_DGRAM, 0, 0, daytime_dg,
174
175 /* Familiar character generator */
176 "chargen", SOCK_STREAM, 1, 0, chargen_stream,
177 "chargen", SOCK_DGRAM, 0, 0, chargen_dg,
178 0
179 };
180
181 #define NUMINT (sizeof(intab) / sizeof(struct inent))
182 char *CONFIG = _PATH_INETDCONF;
183 char **Argv;
184 char *LastArg;
185
186 main(argc, argv, envp)
187 int argc;
188 char *argv[], *envp[];
189 {
190 extern char *optarg;
191 extern int optind;
192 register struct servtab *sep;
193 register struct passwd *pwd;
194 register int tmpint;
195 struct sigvec sv;
196 int ch, pid, dofork;
197 char buf[50];
198
199 Argv = argv;
200 if (envp == 0 || *envp == 0)
201 envp = argv;
202 while (*envp)
203 envp++;
204 LastArg = envp[-1] + strlen(envp[-1]);
205
206 while ((ch = getopt(argc, argv, "d")) != EOF)
207 switch(ch) {
208 case 'd':
209 debug = 1;
210 options |= SO_DEBUG;
211 break;
212 case '?':
213 default:
214 fprintf(stderr, "usage: inetd [-d]");
215 exit(1);
216 }
217 argc -= optind;
218 argv += optind;
219
220 if (argc > 0)
221 CONFIG = argv[0];
222 if (debug == 0)
223 daemon(0, 0);
224 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
225 bzero((char *)&sv, sizeof(sv));
226 sv.sv_mask = SIGBLOCK;
227 sv.sv_handler = retry;
228 sigvec(SIGALRM, &sv, (struct sigvec *)0);
229 config();
230 sv.sv_handler = config;
231 sigvec(SIGHUP, &sv, (struct sigvec *)0);
232 sv.sv_handler = reapchild;
233 sigvec(SIGCHLD, &sv, (struct sigvec *)0);
234
235 {
236 /* space for daemons to overwrite environment for ps */
237 #define DUMMYSIZE 100
238 char dummy[DUMMYSIZE];
239
240 (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
241 dummy[DUMMYSIZE - 1] = '\0';
242 (void)setenv("inetd_dummy", dummy, 1);
243 }
244
245 for (;;) {
246 int n, ctrl;
247 fd_set readable;
248
249 if (nsock == 0) {
250 (void) sigblock(SIGBLOCK);
251 while (nsock == 0)
252 sigpause(0L);
253 (void) sigsetmask(0L);
254 }
255 readable = allsock;
256 if ((n = select(maxsock + 1, &readable, (fd_set *)0,
257 (fd_set *)0, (struct timeval *)0)) <= 0) {
258 if (n < 0 && errno != EINTR)
259 syslog(LOG_WARNING, "select: %m\n");
260 sleep(1);
261 continue;
262 }
263 for (sep = servtab; n && sep; sep = sep->se_next)
264 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
265 n--;
266 if (debug)
267 fprintf(stderr, "someone wants %s\n",
268 sep->se_service);
269 if (sep->se_socktype == SOCK_STREAM) {
270 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
271 (int *)0);
272 if (debug)
273 fprintf(stderr, "accept, ctrl %d\n", ctrl);
274 if (ctrl < 0) {
275 if (errno == EINTR)
276 continue;
277 syslog(LOG_WARNING, "accept (for %s): %m",
278 sep->se_service);
279 continue;
280 }
281 } else
282 ctrl = sep->se_fd;
283 (void) sigblock(SIGBLOCK);
284 pid = 0;
285 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
286 if (dofork) {
287 if (sep->se_count++ == 0)
288 (void)gettimeofday(&sep->se_time,
289 (struct timezone *)0);
290 else if (sep->se_count >= TOOMANY) {
291 struct timeval now;
292
293 (void)gettimeofday(&now, (struct timezone *)0);
294 if (now.tv_sec - sep->se_time.tv_sec >
295 CNT_INTVL) {
296 sep->se_time = now;
297 sep->se_count = 1;
298 } else {
299 syslog(LOG_ERR,
300 "%s/%s server failing (looping), service terminated\n",
301 sep->se_service, sep->se_proto);
302 FD_CLR(sep->se_fd, &allsock);
303 (void) close(sep->se_fd);
304 sep->se_fd = -1;
305 sep->se_count = 0;
306 nsock--;
307 if (!timingout) {
308 timingout = 1;
309 alarm(RETRYTIME);
310 }
311 }
312 }
313 pid = fork();
314 }
315 if (pid < 0) {
316 syslog(LOG_ERR, "fork: %m");
317 if (sep->se_socktype == SOCK_STREAM)
318 close(ctrl);
319 sigsetmask(0L);
320 sleep(1);
321 continue;
322 }
323 if (pid && sep->se_wait) {
324 sep->se_wait = pid;
325 if (sep->se_fd >= 0) {
326 FD_CLR(sep->se_fd, &allsock);
327 nsock--;
328 }
329 }
330 sigsetmask(0L);
331 if (pid == 0) {
332 if (debug && dofork)
333 setsid();
334 if (dofork)
335 for (tmpint = maxsock; --tmpint > 2; )
336 if (tmpint != ctrl)
337 close(tmpint);
338 if (sep->se_bi)
339 (*sep->se_bi->bi_fn)(ctrl, sep);
340 else {
341 if (debug)
342 fprintf(stderr, "%d execl %s\n",
343 getpid(), sep->se_server);
344 dup2(ctrl, 0);
345 close(ctrl);
346 dup2(0, 1);
347 dup2(0, 2);
348 if ((pwd = getpwnam(sep->se_user)) == NULL) {
349 syslog(LOG_ERR,
350 "getpwnam: %s: No such user",
351 sep->se_user);
352 if (sep->se_socktype != SOCK_STREAM)
353 recv(0, buf, sizeof (buf), 0);
354 _exit(1);
355 }
356 if (pwd->pw_uid) {
357 (void) setgid((gid_t)pwd->pw_gid);
358 initgroups(pwd->pw_name, pwd->pw_gid);
359 (void) setuid((uid_t)pwd->pw_uid);
360 }
361 execv(sep->se_server, sep->se_argv);
362 if (sep->se_socktype != SOCK_STREAM)
363 recv(0, buf, sizeof (buf), 0);
364 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
365 _exit(1);
366 }
367 }
368 if (sep->se_socktype == SOCK_STREAM)
369 close(ctrl);
370 }
371 }
372 }
373
374 void
375 reapchild()
376 {
377 int status;
378 int pid;
379 register struct servtab *sep;
380
381 for (;;) {
382 pid = wait3(&status, WNOHANG, (struct rusage *)0);
383 if (pid <= 0)
384 break;
385 if (debug)
386 fprintf(stderr, "%d reaped\n", pid);
387 for (sep = servtab; sep; sep = sep->se_next)
388 if (sep->se_wait == pid) {
389 if (status)
390 syslog(LOG_WARNING,
391 "%s: exit status 0x%x",
392 sep->se_server, status);
393 if (debug)
394 fprintf(stderr, "restored %s, fd %d\n",
395 sep->se_service, sep->se_fd);
396 FD_SET(sep->se_fd, &allsock);
397 nsock++;
398 sep->se_wait = 1;
399 }
400 }
401 }
402
403 void
404 config()
405 {
406 register struct servtab *sep, *cp, **sepp;
407 struct servtab *getconfigent(), *enter();
408 long omask;
409
410 if (!setconfig()) {
411 syslog(LOG_ERR, "%s: %m", CONFIG);
412 return;
413 }
414 for (sep = servtab; sep; sep = sep->se_next)
415 sep->se_checked = 0;
416 while (cp = getconfigent()) {
417 for (sep = servtab; sep; sep = sep->se_next)
418 if (strcmp(sep->se_service, cp->se_service) == 0 &&
419 strcmp(sep->se_proto, cp->se_proto) == 0)
420 break;
421 if (sep != 0) {
422 int i;
423
424 omask = sigblock(SIGBLOCK);
425 /*
426 * sep->se_wait may be holding the pid of a daemon
427 * that we're waiting for. If so, don't overwrite
428 * it unless the config file explicitly says don't
429 * wait.
430 */
431 if (cp->se_bi == 0 &&
432 (sep->se_wait == 1 || cp->se_wait == 0))
433 sep->se_wait = cp->se_wait;
434 #define SWAP(a, b) { char *c = a; a = b; b = c; }
435 if (cp->se_user)
436 SWAP(sep->se_user, cp->se_user);
437 if (cp->se_server)
438 SWAP(sep->se_server, cp->se_server);
439 for (i = 0; i < MAXARGV; i++)
440 SWAP(sep->se_argv[i], cp->se_argv[i]);
441 sigsetmask(omask);
442 freeconfig(cp);
443 if (debug)
444 print_service("REDO", sep);
445 } else {
446 sep = enter(cp);
447 if (debug)
448 print_service("ADD ", sep);
449 }
450 sep->se_checked = 1;
451 if (!sep->se_rpc) {
452 sp = getservbyname(sep->se_service, sep->se_proto);
453 if (sp == 0) {
454 syslog(LOG_ERR, "%s/%s: unknown service",
455 sep->se_service, sep->se_proto);
456 if (sep->se_fd != -1)
457 (void) close(sep->se_fd);
458 sep->se_fd = -1;
459 continue;
460 }
461 if (sp->s_port != sep->se_ctrladdr.sin_port) {
462 sep->se_ctrladdr.sin_port = sp->s_port;
463 if (sep->se_fd != -1)
464 (void) close(sep->se_fd);
465 sep->se_fd = -1;
466 }
467 }
468 else {
469 rpc = getrpcbyname(sep->se_service);
470 if (rpc == 0) {
471 syslog(LOG_ERR, "%s/%s unknown RPC service.",
472 sep->se_service, sep->se_proto);
473 if (sep->se_fd != -1)
474 (void) close(sep->se_fd);
475 sep->se_fd = -1;
476 continue;
477 }
478 if (rpc->r_number != sep->se_rpc_prog) {
479 if (sep->se_rpc_prog)
480 unregisterrpc(sep);
481 sep->se_rpc_prog = rpc->r_number;
482 if (sep->se_fd != -1)
483 (void) close(sep->se_fd);
484 sep->se_fd = -1;
485 }
486 }
487
488 if (sep->se_fd == -1)
489 setup(sep);
490 }
491 endconfig();
492 /*
493 * Purge anything not looked at above.
494 */
495 omask = sigblock(SIGBLOCK);
496 sepp = &servtab;
497 while (sep = *sepp) {
498 if (sep->se_checked) {
499 sepp = &sep->se_next;
500 continue;
501 }
502 *sepp = sep->se_next;
503 if (sep->se_fd != -1) {
504 FD_CLR(sep->se_fd, &allsock);
505 nsock--;
506 (void) close(sep->se_fd);
507 }
508 if (debug)
509 print_service("FREE", sep);
510 if (sep->se_rpc && sep->se_rpc_prog > 0)
511 unregisterrpc(sep);
512 freeconfig(sep);
513 free((char *)sep);
514 }
515 (void) sigsetmask(omask);
516 }
517
518 void
519 unregisterrpc(sep)
520 register struct servtab *sep;
521 {
522 int i;
523 struct servtab *sepp;
524 long omask;
525
526 omask = sigblock(SIGBLOCK);
527 for (sepp = servtab; sepp; sepp = sepp->se_next) {
528 if (sepp == sep)
529 continue;
530 if (sep->se_checked == 0 ||
531 !sepp->se_rpc ||
532 sep->se_rpc_prog != sepp->se_rpc_prog)
533 continue;
534 return;
535 }
536 if (debug)
537 print_service("UNREG", sep);
538 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
539 pmap_unset(sep->se_rpc_prog, i);
540 if (sep->se_fd != -1)
541 (void) close(sep->se_fd);
542 sep->se_fd = -1;
543 (void) sigsetmask(omask);
544 }
545
546 void
547 retry()
548 {
549 register struct servtab *sep;
550
551 timingout = 0;
552 for (sep = servtab; sep; sep = sep->se_next)
553 if (sep->se_fd == -1)
554 setup(sep);
555 }
556
557 setup(sep)
558 register struct servtab *sep;
559 {
560 int on = 1;
561
562 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
563 syslog(LOG_ERR, "%s/%s: socket: %m",
564 sep->se_service, sep->se_proto);
565 return;
566 }
567 #define turnon(fd, opt) \
568 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
569 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
570 turnon(sep->se_fd, SO_DEBUG) < 0)
571 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
572 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
573 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
574 #undef turnon
575 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
576 sizeof (sep->se_ctrladdr)) < 0) {
577 syslog(LOG_ERR, "%s/%s: bind: %m",
578 sep->se_service, sep->se_proto);
579 (void) close(sep->se_fd);
580 sep->se_fd = -1;
581 if (!timingout) {
582 timingout = 1;
583 alarm(RETRYTIME);
584 }
585 return;
586 }
587 if (sep->se_rpc) {
588 int i, len;
589 if (getsockname(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
590 &len) < 0) {
591 syslog(LOG_ERR, "%s/%s: getsockname: %m",
592 sep->se_service, sep->se_proto);
593 (void) close(sep->se_fd);
594 sep->se_fd = -1;
595 return;
596 }
597 if (debug)
598 print_service("REG ", sep);
599 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
600 pmap_unset(sep->se_rpc_prog, i);
601 pmap_set(sep->se_rpc_prog, i,
602 (sep->se_socktype == SOCK_DGRAM)
603 ? IPPROTO_UDP : IPPROTO_TCP,
604 ntohs(sep->se_ctrladdr.sin_port));
605 }
606
607 }
608 if (sep->se_socktype == SOCK_STREAM)
609 listen(sep->se_fd, 10);
610 FD_SET(sep->se_fd, &allsock);
611 nsock++;
612 if (sep->se_fd > maxsock)
613 maxsock = sep->se_fd;
614 }
615
616 struct servtab *
617 enter(cp)
618 struct servtab *cp;
619 {
620 register struct servtab *sep;
621 long omask;
622
623 sep = (struct servtab *)malloc(sizeof (*sep));
624 if (sep == (struct servtab *)0) {
625 syslog(LOG_ERR, "Out of memory.");
626 exit(-1);
627 }
628 *sep = *cp;
629 sep->se_fd = -1;
630 omask = sigblock(SIGBLOCK);
631 sep->se_next = servtab;
632 servtab = sep;
633 sigsetmask(omask);
634 return (sep);
635 }
636
637 FILE *fconfig = NULL;
638 struct servtab serv;
639 char line[256];
640 char *skip(), *nextline();
641
642 setconfig()
643 {
644
645 if (fconfig != NULL) {
646 fseek(fconfig, 0L, L_SET);
647 return (1);
648 }
649 fconfig = fopen(CONFIG, "r");
650 return (fconfig != NULL);
651 }
652
653 endconfig()
654 {
655 if (fconfig) {
656 (void) fclose(fconfig);
657 fconfig = NULL;
658 }
659 }
660
661 struct servtab *
662 getconfigent()
663 {
664 register struct servtab *sep = &serv;
665 int argc;
666 char *cp, *arg, *newstr();
667 char *versp;
668
669 more:
670 while ((cp = nextline(fconfig)) && *cp == '#')
671 ;
672 if (cp == NULL)
673 return ((struct servtab *)0);
674 sep->se_service = newstr(skip(&cp));
675 arg = skip(&cp);
676 if (strcmp(arg, "stream") == 0)
677 sep->se_socktype = SOCK_STREAM;
678 else if (strcmp(arg, "dgram") == 0)
679 sep->se_socktype = SOCK_DGRAM;
680 else if (strcmp(arg, "rdm") == 0)
681 sep->se_socktype = SOCK_RDM;
682 else if (strcmp(arg, "seqpacket") == 0)
683 sep->se_socktype = SOCK_SEQPACKET;
684 else if (strcmp(arg, "raw") == 0)
685 sep->se_socktype = SOCK_RAW;
686 else
687 sep->se_socktype = -1;
688 sep->se_proto = newstr(skip(&cp));
689 sep->se_rpc = 0;
690 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
691 sep->se_proto += 4;
692 sep->se_rpc = 1;
693 sep->se_rpc_prog = sep->se_rpc_lowvers = sep->se_rpc_lowvers = 0;
694 sep->se_ctrladdr.sin_family = AF_INET;
695 sep->se_ctrladdr.sin_port = 0;
696 sep->se_ctrladdr.sin_addr.s_addr = htonl(INADDR_ANY);
697 if (versp = rindex(sep->se_service, '/')) {
698 *versp++ = '\0';
699 switch (sscanf(versp, "%d-%d",
700 &sep->se_rpc_lowvers,
701 &sep->se_rpc_highvers)) {
702 case 2:
703 break;
704 case 1:
705 sep->se_rpc_highvers =
706 sep->se_rpc_lowvers;
707 break;
708 default:
709 syslog(LOG_ERR, "bad RPC version specifier; %s\n", sep->se_service);
710 freeconfig(sep);
711 goto more;
712 }
713 }
714 else {
715 sep->se_rpc_lowvers =
716 sep->se_rpc_highvers = 1;
717 }
718 }
719 arg = skip(&cp);
720 sep->se_wait = strcmp(arg, "wait") == 0;
721 sep->se_user = newstr(skip(&cp));
722 sep->se_server = newstr(skip(&cp));
723 if (strcmp(sep->se_server, "internal") == 0) {
724 register struct biltin *bi;
725
726 for (bi = biltins; bi->bi_service; bi++)
727 if (bi->bi_socktype == sep->se_socktype &&
728 strcmp(bi->bi_service, sep->se_service) == 0)
729 break;
730 if (bi->bi_service == 0) {
731 syslog(LOG_ERR, "internal service %s unknown\n",
732 sep->se_service);
733 goto more;
734 }
735 sep->se_bi = bi;
736 sep->se_wait = bi->bi_wait;
737 } else
738 sep->se_bi = NULL;
739 argc = 0;
740 for (arg = skip(&cp); cp; arg = skip(&cp))
741 if (argc < MAXARGV)
742 sep->se_argv[argc++] = newstr(arg);
743 while (argc <= MAXARGV)
744 sep->se_argv[argc++] = NULL;
745 return (sep);
746 }
747
748 freeconfig(cp)
749 register struct servtab *cp;
750 {
751 int i;
752
753 if (cp->se_service)
754 free(cp->se_service);
755 if (cp->se_proto)
756 free(cp->se_proto);
757 if (cp->se_user)
758 free(cp->se_user);
759 if (cp->se_server)
760 free(cp->se_server);
761 for (i = 0; i < MAXARGV; i++)
762 if (cp->se_argv[i])
763 free(cp->se_argv[i]);
764 }
765
766 char *
767 skip(cpp)
768 char **cpp;
769 {
770 register char *cp = *cpp;
771 char *start;
772
773 again:
774 while (*cp == ' ' || *cp == '\t')
775 cp++;
776 if (*cp == '\0') {
777 int c;
778
779 c = getc(fconfig);
780 (void) ungetc(c, fconfig);
781 if (c == ' ' || c == '\t')
782 if (cp = nextline(fconfig))
783 goto again;
784 *cpp = (char *)0;
785 return ((char *)0);
786 }
787 start = cp;
788 while (*cp && *cp != ' ' && *cp != '\t')
789 cp++;
790 if (*cp != '\0')
791 *cp++ = '\0';
792 *cpp = cp;
793 return (start);
794 }
795
796 char *
797 nextline(fd)
798 FILE *fd;
799 {
800 char *cp;
801
802 if (fgets(line, sizeof (line), fd) == NULL)
803 return ((char *)0);
804 cp = index(line, '\n');
805 if (cp)
806 *cp = '\0';
807 return (line);
808 }
809
810 char *
811 newstr(cp)
812 char *cp;
813 {
814 if (cp = strdup(cp ? cp : ""))
815 return(cp);
816 syslog(LOG_ERR, "strdup: %m");
817 exit(-1);
818 }
819
820 setproctitle(a, s)
821 char *a;
822 int s;
823 {
824 int size;
825 register char *cp;
826 struct sockaddr_in sin;
827 char buf[80];
828
829 cp = Argv[0];
830 size = sizeof(sin);
831 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
832 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
833 else
834 (void) sprintf(buf, "-%s", a);
835 strncpy(cp, buf, LastArg - cp);
836 cp += strlen(cp);
837 while (cp < LastArg)
838 *cp++ = ' ';
839 }
840
841 /*
842 * Internet services provided internally by inetd:
843 */
844 #define BUFSIZE 8192
845
846 /* ARGSUSED */
847 echo_stream(s, sep) /* Echo service -- echo data back */
848 int s;
849 struct servtab *sep;
850 {
851 char buffer[BUFSIZE];
852 int i;
853
854 setproctitle(sep->se_service, s);
855 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
856 write(s, buffer, i) > 0)
857 ;
858 exit(0);
859 }
860
861 /* ARGSUSED */
862 echo_dg(s, sep) /* Echo service -- echo data back */
863 int s;
864 struct servtab *sep;
865 {
866 char buffer[BUFSIZE];
867 int i, size;
868 struct sockaddr sa;
869
870 size = sizeof(sa);
871 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
872 return;
873 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
874 }
875
876 /* ARGSUSED */
877 discard_stream(s, sep) /* Discard service -- ignore data */
878 int s;
879 struct servtab *sep;
880 {
881 int ret;
882 char buffer[BUFSIZE];
883
884 setproctitle(sep->se_service, s);
885 while (1) {
886 while ((ret = read(s, buffer, sizeof(buffer))) > 0)
887 ;
888 if (ret == 0 || errno != EINTR)
889 break;
890 }
891 exit(0);
892 }
893
894 /* ARGSUSED */
895 discard_dg(s, sep) /* Discard service -- ignore data */
896 int s;
897 struct servtab *sep;
898 {
899 char buffer[BUFSIZE];
900
901 (void) read(s, buffer, sizeof(buffer));
902 }
903
904 #include <ctype.h>
905 #define LINESIZ 72
906 char ring[128];
907 char *endring;
908
909 initring()
910 {
911 register int i;
912
913 endring = ring;
914
915 for (i = 0; i <= 128; ++i)
916 if (isprint(i))
917 *endring++ = i;
918 }
919
920 /* ARGSUSED */
921 chargen_stream(s, sep) /* Character generator */
922 int s;
923 struct servtab *sep;
924 {
925 register char *rs;
926 int len;
927 char text[LINESIZ+2];
928
929 setproctitle(sep->se_service, s);
930
931 if (!endring) {
932 initring();
933 rs = ring;
934 }
935
936 text[LINESIZ] = '\r';
937 text[LINESIZ + 1] = '\n';
938 for (rs = ring;;) {
939 if ((len = endring - rs) >= LINESIZ)
940 bcopy(rs, text, LINESIZ);
941 else {
942 bcopy(rs, text, len);
943 bcopy(ring, text + len, LINESIZ - len);
944 }
945 if (++rs == endring)
946 rs = ring;
947 if (write(s, text, sizeof(text)) != sizeof(text))
948 break;
949 }
950 exit(0);
951 }
952
953 /* ARGSUSED */
954 chargen_dg(s, sep) /* Character generator */
955 int s;
956 struct servtab *sep;
957 {
958 struct sockaddr sa;
959 static char *rs;
960 int len, size;
961 char text[LINESIZ+2];
962
963 if (endring == 0) {
964 initring();
965 rs = ring;
966 }
967
968 size = sizeof(sa);
969 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
970 return;
971
972 if ((len = endring - rs) >= LINESIZ)
973 bcopy(rs, text, LINESIZ);
974 else {
975 bcopy(rs, text, len);
976 bcopy(ring, text + len, LINESIZ - len);
977 }
978 if (++rs == endring)
979 rs = ring;
980 text[LINESIZ] = '\r';
981 text[LINESIZ + 1] = '\n';
982 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
983 }
984
985 /*
986 * Return a machine readable date and time, in the form of the
987 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
988 * returns the number of seconds since midnight, Jan 1, 1970,
989 * we must add 2208988800 seconds to this figure to make up for
990 * some seventy years Bell Labs was asleep.
991 */
992
993 long
994 machtime()
995 {
996 struct timeval tv;
997
998 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
999 fprintf(stderr, "Unable to get time of day\n");
1000 return (0L);
1001 }
1002 return (htonl((long)tv.tv_sec + 2208988800));
1003 }
1004
1005 /* ARGSUSED */
1006 machtime_stream(s, sep)
1007 int s;
1008 struct servtab *sep;
1009 {
1010 long result;
1011
1012 result = machtime();
1013 (void) write(s, (char *) &result, sizeof(result));
1014 }
1015
1016 /* ARGSUSED */
1017 machtime_dg(s, sep)
1018 int s;
1019 struct servtab *sep;
1020 {
1021 long result;
1022 struct sockaddr sa;
1023 int size;
1024
1025 size = sizeof(sa);
1026 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1027 return;
1028 result = machtime();
1029 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1030 }
1031
1032 /* ARGSUSED */
1033 daytime_stream(s, sep) /* Return human-readable time of day */
1034 int s;
1035 struct servtab *sep;
1036 {
1037 char buffer[256];
1038 time_t time(), clock;
1039 char *ctime();
1040
1041 clock = time((time_t *) 0);
1042
1043 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1044 (void) write(s, buffer, strlen(buffer));
1045 }
1046
1047 /* ARGSUSED */
1048 daytime_dg(s, sep) /* Return human-readable time of day */
1049 int s;
1050 struct servtab *sep;
1051 {
1052 char buffer[256];
1053 time_t time(), clock;
1054 struct sockaddr sa;
1055 int size;
1056 char *ctime();
1057
1058 clock = time((time_t *) 0);
1059
1060 size = sizeof(sa);
1061 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1062 return;
1063 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1064 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1065 }
1066
1067 /*
1068 * print_service:
1069 * Dump relevant information to stderr
1070 */
1071 print_service(action, sep)
1072 char *action;
1073 struct servtab *sep;
1074 {
1075 if (sep->se_rpc)
1076 fprintf(stderr,
1077 "%s: %s rpcnum=%d, rpcvers=%d/%d, wait=%d, user=%s builtin=%x server=%s\n",
1078 action, sep->se_service,
1079 sep->se_rpc_prog, sep->se_rpc_lowvers, sep->se_rpc_highvers,
1080 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1081 else
1082 fprintf(stderr,
1083 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1084 action, sep->se_service, sep->se_proto,
1085 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1086 }
1087