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