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