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.13 (Berkeley) 06/18/88"; 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 (5) 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 <stdio.h> 77 #include <signal.h> 78 #include <netdb.h> 79 #include <syslog.h> 80 #include <pwd.h> 81 82 #define TOOMANY 40 /* don't start more than TOOMANY */ 83 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 84 #define RETRYTIME (60*10) /* retry after bind or server fail */ 85 86 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 87 88 extern int errno; 89 90 int reapchild(), retry(); 91 char *index(); 92 char *malloc(); 93 94 int debug = 0; 95 int nsock, maxsock; 96 fd_set allsock; 97 int options; 98 int timingout; 99 struct servent *sp; 100 101 struct servtab { 102 char *se_service; /* name of service */ 103 int se_socktype; /* type of socket to use */ 104 char *se_proto; /* protocol used */ 105 short se_wait; /* single threaded server */ 106 short se_checked; /* looked at during merge */ 107 char *se_user; /* user name to run as */ 108 struct biltin *se_bi; /* if built-in, description */ 109 char *se_server; /* server program */ 110 #define MAXARGV 5 111 char *se_argv[MAXARGV+1]; /* program arguments */ 112 int se_fd; /* open descriptor */ 113 struct sockaddr_in se_ctrladdr;/* bound address */ 114 int se_count; /* number started since se_time */ 115 struct timeval se_time; /* start of se_count */ 116 struct servtab *se_next; 117 } *servtab; 118 119 int echo_stream(), discard_stream(), machtime_stream(); 120 int daytime_stream(), chargen_stream(); 121 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 122 123 struct biltin { 124 char *bi_service; /* internally provided service name */ 125 int bi_socktype; /* type of socket supported */ 126 short bi_fork; /* 1 if should fork before call */ 127 short bi_wait; /* 1 if should wait for child */ 128 int (*bi_fn)(); /* function which performs it */ 129 } biltins[] = { 130 /* Echo received data */ 131 "echo", SOCK_STREAM, 1, 0, echo_stream, 132 "echo", SOCK_DGRAM, 0, 0, echo_dg, 133 134 /* Internet /dev/null */ 135 "discard", SOCK_STREAM, 1, 0, discard_stream, 136 "discard", SOCK_DGRAM, 0, 0, discard_dg, 137 138 /* Return 32 bit time since 1970 */ 139 "time", SOCK_STREAM, 0, 0, machtime_stream, 140 "time", SOCK_DGRAM, 0, 0, machtime_dg, 141 142 /* Return human-readable time */ 143 "daytime", SOCK_STREAM, 0, 0, daytime_stream, 144 "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 145 146 /* Familiar character generator */ 147 "chargen", SOCK_STREAM, 1, 0, chargen_stream, 148 "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 149 0 150 }; 151 152 #define NUMINT (sizeof(intab) / sizeof(struct inent)) 153 char *CONFIG = "/etc/inetd.conf"; 154 char **Argv; 155 char *LastArg; 156 157 main(argc, argv, envp) 158 int argc; 159 char *argv[], *envp[]; 160 { 161 register struct servtab *sep; 162 register struct passwd *pwd; 163 char *cp, buf[50]; 164 int pid, i, dofork; 165 struct sigvec sv; 166 167 Argv = argv; 168 if (envp == 0 || *envp == 0) 169 envp = argv; 170 while (*envp) 171 envp++; 172 LastArg = envp[-1] + strlen(envp[-1]); 173 argc--, argv++; 174 while (argc > 0 && *argv[0] == '-') { 175 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 176 177 case 'd': 178 debug = 1; 179 options |= SO_DEBUG; 180 break; 181 182 default: 183 fprintf(stderr, 184 "inetd: Unknown flag -%c ignored.\n", *cp); 185 break; 186 } 187 nextopt: 188 argc--, argv++; 189 } 190 if (argc > 0) 191 CONFIG = argv[0]; 192 if (debug == 0) { 193 if (fork()) 194 exit(0); 195 { int s; 196 for (s = 0; s < 10; s++) 197 (void) close(s); 198 } 199 (void) open("/", O_RDONLY); 200 (void) dup2(0, 1); 201 (void) dup2(0, 2); 202 { int tt = open("/dev/tty", O_RDWR); 203 if (tt > 0) { 204 ioctl(tt, TIOCNOTTY, (char *)0); 205 close(tt); 206 } 207 } 208 (void) setpgrp(0, 0); 209 signal(SIGTSTP, SIG_IGN); 210 signal(SIGTTIN, SIG_IGN); 211 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 for (;;) { 225 int s, ctrl, n; 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_wait && 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: %m"); 256 continue; 257 } 258 } else 259 ctrl = sep->se_fd; 260 (void) sigblock(SIGBLOCK); 261 pid = 0; 262 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 263 if (dofork) { 264 if (sep->se_count++ == 0) 265 (void)gettimeofday(&sep->se_time, 266 (struct timezone *)0); 267 else if (sep->se_count >= TOOMANY) { 268 struct timeval now; 269 270 (void)gettimeofday(&now, (struct timezone *)0); 271 if (now.tv_sec - sep->se_time.tv_sec > 272 CNT_INTVL) { 273 sep->se_time = now; 274 sep->se_count = 1; 275 } else { 276 syslog(LOG_ERR, 277 "%s/%s server failing (looping), service terminated\n", 278 sep->se_service, sep->se_proto); 279 FD_CLR(sep->se_fd, &allsock); 280 (void) close(sep->se_fd); 281 sep->se_fd = -1; 282 sep->se_count = 0; 283 nsock--; 284 sigsetmask(0L); 285 if (!timingout) { 286 timingout = 1; 287 alarm(RETRYTIME); 288 } 289 continue; 290 } 291 } 292 pid = fork(); 293 } 294 if (pid < 0) { 295 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) 296 close(ctrl); 297 sigsetmask(0L); 298 sleep(1); 299 continue; 300 } 301 if (pid && sep->se_wait) { 302 sep->se_wait = pid; 303 FD_CLR(sep->se_fd, &allsock); 304 nsock--; 305 } 306 sigsetmask(0L); 307 if (pid == 0) { 308 if (debug) { 309 int tt; 310 311 if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) { 312 ioctl(tt, TIOCNOTTY, 0); 313 close(tt); 314 } 315 (void) setpgrp(0, 0); 316 signal(SIGTSTP, SIG_IGN); 317 signal(SIGTTIN, SIG_IGN); 318 signal(SIGTTOU, SIG_IGN); 319 } 320 if (dofork) 321 for (i = getdtablesize(); --i > 2; ) 322 if (i != ctrl) 323 close(i); 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_wait && sep->se_socktype == SOCK_STREAM) 355 close(ctrl); 356 } 357 } 358 } 359 360 reapchild() 361 { 362 union wait status; 363 int pid; 364 register struct servtab *sep; 365 366 for (;;) { 367 pid = wait3(&status, WNOHANG, (struct rusage *)0); 368 if (pid <= 0) 369 break; 370 if (debug) 371 fprintf(stderr, "%d reaped\n", pid); 372 for (sep = servtab; sep; sep = sep->se_next) 373 if (sep->se_wait == pid) { 374 if (status.w_status) 375 syslog(LOG_WARNING, 376 "%s: exit status 0x%x", 377 sep->se_server, status); 378 if (debug) 379 fprintf(stderr, "restored %s, fd %d\n", 380 sep->se_service, sep->se_fd); 381 FD_SET(sep->se_fd, &allsock); 382 nsock++; 383 sep->se_wait = 1; 384 } 385 } 386 } 387 388 config() 389 { 390 register struct servtab *sep, *cp, **sepp; 391 struct servtab *getconfigent(), *enter(); 392 long omask; 393 394 if (!setconfig()) { 395 syslog(LOG_ERR, "%s: %m", CONFIG); 396 return; 397 } 398 for (sep = servtab; sep; sep = sep->se_next) 399 sep->se_checked = 0; 400 while (cp = getconfigent()) { 401 for (sep = servtab; sep; sep = sep->se_next) 402 if (strcmp(sep->se_service, cp->se_service) == 0 && 403 strcmp(sep->se_proto, cp->se_proto) == 0) 404 break; 405 if (sep != 0) { 406 int i; 407 408 omask = sigblock(SIGBLOCK); 409 if (cp->se_bi == 0) 410 sep->se_wait = cp->se_wait; 411 #define SWAP(a, b) { char *c = a; a = b; b = c; } 412 if (cp->se_user) 413 SWAP(sep->se_user, cp->se_user); 414 if (cp->se_server) 415 SWAP(sep->se_server, cp->se_server); 416 for (i = 0; i < MAXARGV; i++) 417 SWAP(sep->se_argv[i], cp->se_argv[i]); 418 sigsetmask(omask); 419 freeconfig(cp); 420 if (debug) 421 print_service("REDO", sep); 422 } else { 423 sep = enter(cp); 424 if (debug) 425 print_service("ADD ", sep); 426 } 427 sep->se_checked = 1; 428 sp = getservbyname(sep->se_service, sep->se_proto); 429 if (sp == 0) { 430 syslog(LOG_ERR, "%s/%s: unknown service", 431 sep->se_service, sep->se_proto); 432 continue; 433 } 434 if (sp->s_port != sep->se_ctrladdr.sin_port) { 435 sep->se_ctrladdr.sin_port = sp->s_port; 436 if (sep->se_fd != -1) 437 (void) close(sep->se_fd); 438 sep->se_fd = -1; 439 } 440 if (sep->se_fd == -1) 441 setup(sep); 442 } 443 endconfig(); 444 /* 445 * Purge anything not looked at above. 446 */ 447 omask = sigblock(SIGBLOCK); 448 sepp = &servtab; 449 while (sep = *sepp) { 450 if (sep->se_checked) { 451 sepp = &sep->se_next; 452 continue; 453 } 454 *sepp = sep->se_next; 455 if (sep->se_fd != -1) { 456 FD_CLR(sep->se_fd, &allsock); 457 nsock--; 458 (void) close(sep->se_fd); 459 } 460 if (debug) 461 print_service("FREE", sep); 462 freeconfig(sep); 463 free((char *)sep); 464 } 465 (void) sigsetmask(omask); 466 } 467 468 retry() 469 { 470 register struct servtab *sep; 471 472 timingout = 0; 473 for (sep = servtab; sep; sep = sep->se_next) 474 if (sep->se_fd == -1) 475 setup(sep); 476 } 477 478 setup(sep) 479 register struct servtab *sep; 480 { 481 int on = 1; 482 483 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 484 syslog(LOG_ERR, "%s/%s: socket: %m", 485 sep->se_service, sep->se_proto); 486 return; 487 } 488 #define turnon(fd, opt) \ 489 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 490 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 491 turnon(sep->se_fd, SO_DEBUG) < 0) 492 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 493 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 494 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 495 #undef turnon 496 if (bind(sep->se_fd, &sep->se_ctrladdr, 497 sizeof (sep->se_ctrladdr)) < 0) { 498 syslog(LOG_ERR, "%s/%s: bind: %m", 499 sep->se_service, sep->se_proto); 500 (void) close(sep->se_fd); 501 sep->se_fd = -1; 502 if (!timingout) { 503 timingout = 1; 504 alarm(RETRYTIME); 505 } 506 return; 507 } 508 if (sep->se_socktype == SOCK_STREAM) 509 listen(sep->se_fd, 10); 510 FD_SET(sep->se_fd, &allsock); 511 nsock++; 512 if (sep->se_fd > maxsock) 513 maxsock = sep->se_fd; 514 } 515 516 struct servtab * 517 enter(cp) 518 struct servtab *cp; 519 { 520 register struct servtab *sep; 521 long omask; 522 523 sep = (struct servtab *)malloc(sizeof (*sep)); 524 if (sep == (struct servtab *)0) { 525 syslog(LOG_ERR, "Out of memory."); 526 exit(-1); 527 } 528 *sep = *cp; 529 sep->se_fd = -1; 530 omask = sigblock(SIGBLOCK); 531 sep->se_next = servtab; 532 servtab = sep; 533 sigsetmask(omask); 534 return (sep); 535 } 536 537 FILE *fconfig = NULL; 538 struct servtab serv; 539 char line[256]; 540 char *skip(), *nextline(); 541 542 setconfig() 543 { 544 545 if (fconfig != NULL) { 546 fseek(fconfig, 0L, L_SET); 547 return (1); 548 } 549 fconfig = fopen(CONFIG, "r"); 550 return (fconfig != NULL); 551 } 552 553 endconfig() 554 { 555 556 if (fconfig == NULL) 557 return; 558 fclose(fconfig); 559 fconfig = NULL; 560 } 561 562 struct servtab * 563 getconfigent() 564 { 565 register struct servtab *sep = &serv; 566 int argc; 567 char *cp, *arg, *strdup(); 568 569 more: 570 while ((cp = nextline(fconfig)) && *cp == '#') 571 ; 572 if (cp == NULL) 573 return ((struct servtab *)0); 574 sep->se_service = strdup(skip(&cp)); 575 arg = skip(&cp); 576 if (strcmp(arg, "stream") == 0) 577 sep->se_socktype = SOCK_STREAM; 578 else if (strcmp(arg, "dgram") == 0) 579 sep->se_socktype = SOCK_DGRAM; 580 else if (strcmp(arg, "rdm") == 0) 581 sep->se_socktype = SOCK_RDM; 582 else if (strcmp(arg, "seqpacket") == 0) 583 sep->se_socktype = SOCK_SEQPACKET; 584 else if (strcmp(arg, "raw") == 0) 585 sep->se_socktype = SOCK_RAW; 586 else 587 sep->se_socktype = -1; 588 sep->se_proto = strdup(skip(&cp)); 589 arg = skip(&cp); 590 sep->se_wait = strcmp(arg, "wait") == 0; 591 sep->se_user = strdup(skip(&cp)); 592 sep->se_server = strdup(skip(&cp)); 593 if (strcmp(sep->se_server, "internal") == 0) { 594 register struct biltin *bi; 595 596 for (bi = biltins; bi->bi_service; bi++) 597 if (bi->bi_socktype == sep->se_socktype && 598 strcmp(bi->bi_service, sep->se_service) == 0) 599 break; 600 if (bi->bi_service == 0) { 601 syslog(LOG_ERR, "internal service %s unknown\n", 602 sep->se_service); 603 goto more; 604 } 605 sep->se_bi = bi; 606 sep->se_wait = bi->bi_wait; 607 } else 608 sep->se_bi = NULL; 609 argc = 0; 610 for (arg = skip(&cp); cp; arg = skip(&cp)) 611 if (argc < MAXARGV) 612 sep->se_argv[argc++] = strdup(arg); 613 while (argc <= MAXARGV) 614 sep->se_argv[argc++] = NULL; 615 return (sep); 616 } 617 618 freeconfig(cp) 619 register struct servtab *cp; 620 { 621 int i; 622 623 if (cp->se_service) 624 free(cp->se_service); 625 if (cp->se_proto) 626 free(cp->se_proto); 627 if (cp->se_user) 628 free(cp->se_user); 629 if (cp->se_server) 630 free(cp->se_server); 631 for (i = 0; i < MAXARGV; i++) 632 if (cp->se_argv[i]) 633 free(cp->se_argv[i]); 634 } 635 636 char * 637 skip(cpp) 638 char **cpp; 639 { 640 register char *cp = *cpp; 641 char *start; 642 643 again: 644 while (*cp == ' ' || *cp == '\t') 645 cp++; 646 if (*cp == '\0') { 647 char c; 648 649 c = getc(fconfig); 650 ungetc(c, fconfig); 651 if (c == ' ' || c == '\t') 652 if (cp = nextline(fconfig)) 653 goto again; 654 *cpp = (char *)0; 655 return ((char *)0); 656 } 657 start = cp; 658 while (*cp && *cp != ' ' && *cp != '\t') 659 cp++; 660 if (*cp != '\0') 661 *cp++ = '\0'; 662 *cpp = cp; 663 return (start); 664 } 665 666 char * 667 nextline(fd) 668 FILE *fd; 669 { 670 char *cp; 671 672 if (fgets(line, sizeof (line), fd) == NULL) 673 return ((char *)0); 674 cp = index(line, '\n'); 675 if (cp) 676 *cp = '\0'; 677 return (line); 678 } 679 680 char * 681 strdup(cp) 682 char *cp; 683 { 684 char *new; 685 686 if (cp == NULL) 687 cp = ""; 688 new = malloc((unsigned)(strlen(cp) + 1)); 689 if (new == (char *)0) { 690 syslog(LOG_ERR, "Out of memory."); 691 exit(-1); 692 } 693 strcpy(new, cp); 694 return (new); 695 } 696 697 setproctitle(a, s) 698 char *a; 699 int s; 700 { 701 int size; 702 register char *cp; 703 struct sockaddr_in sin; 704 char buf[80]; 705 706 cp = Argv[0]; 707 size = sizeof(sin); 708 if (getpeername(s, &sin, &size) == 0) 709 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 710 else 711 (void) sprintf(buf, "-%s", a); 712 strncpy(cp, buf, LastArg - cp); 713 cp += strlen(cp); 714 while (cp < LastArg) 715 *cp++ = ' '; 716 } 717 718 /* 719 * Internet services provided internally by inetd: 720 */ 721 722 /* ARGSUSED */ 723 echo_stream(s, sep) /* Echo service -- echo data back */ 724 int s; 725 struct servtab *sep; 726 { 727 char buffer[BUFSIZ]; 728 int i; 729 730 setproctitle(sep->se_service, s); 731 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 732 write(s, buffer, i) > 0) 733 ; 734 exit(0); 735 } 736 737 /* ARGSUSED */ 738 echo_dg(s, sep) /* Echo service -- echo data back */ 739 int s; 740 struct servtab *sep; 741 { 742 char buffer[BUFSIZ]; 743 int i, size; 744 struct sockaddr sa; 745 746 size = sizeof(sa); 747 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 748 return; 749 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 750 } 751 752 /* ARGSUSED */ 753 discard_stream(s, sep) /* Discard service -- ignore data */ 754 int s; 755 struct servtab *sep; 756 { 757 char buffer[BUFSIZ]; 758 759 setproctitle(sep->se_service, s); 760 while (1) { 761 while (read(s, buffer, sizeof(buffer)) > 0) 762 ; 763 if (errno != EINTR) 764 break; 765 } 766 exit(0); 767 } 768 769 /* ARGSUSED */ 770 discard_dg(s, sep) /* Discard service -- ignore data */ 771 int s; 772 struct servtab *sep; 773 { 774 char buffer[BUFSIZ]; 775 776 (void) read(s, buffer, sizeof(buffer)); 777 } 778 779 #include <ctype.h> 780 #define LINESIZ 72 781 char ring[128]; 782 char *endring; 783 784 initring() 785 { 786 register int i; 787 788 endring = ring; 789 790 for (i = 0; i <= 128; ++i) 791 if (isprint(i)) 792 *endring++ = i; 793 } 794 795 /* ARGSUSED */ 796 chargen_stream(s, sep) /* Character generator */ 797 int s; 798 struct servtab *sep; 799 { 800 register char *rs; 801 int len; 802 char text[LINESIZ+2]; 803 804 setproctitle(sep->se_service, s); 805 806 if (!endring) { 807 initring(); 808 rs = ring; 809 } 810 811 text[LINESIZ] = '\r'; 812 text[LINESIZ + 1] = '\n'; 813 for (rs = ring;;) { 814 if ((len = endring - rs) >= LINESIZ) 815 bcopy(rs, text, LINESIZ); 816 else { 817 bcopy(rs, text, len); 818 bcopy(ring, text + len, LINESIZ - len); 819 } 820 if (++rs == endring) 821 rs = ring; 822 if (write(s, text, sizeof(text)) != sizeof(text)) 823 break; 824 } 825 exit(0); 826 } 827 828 /* ARGSUSED */ 829 chargen_dg(s, sep) /* Character generator */ 830 int s; 831 struct servtab *sep; 832 { 833 struct sockaddr sa; 834 static char *rs; 835 int len, size; 836 char text[LINESIZ+2]; 837 838 if (endring == 0) { 839 initring(); 840 rs = ring; 841 } 842 843 size = sizeof(sa); 844 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 845 return; 846 847 if ((len = endring - rs) >= LINESIZ) 848 bcopy(rs, text, LINESIZ); 849 else { 850 bcopy(rs, text, len); 851 bcopy(ring, text + len, LINESIZ - len); 852 } 853 if (++rs == endring) 854 rs = ring; 855 text[LINESIZ] = '\r'; 856 text[LINESIZ + 1] = '\n'; 857 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 858 } 859 860 /* 861 * Return a machine readable date and time, in the form of the 862 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 863 * returns the number of seconds since midnight, Jan 1, 1970, 864 * we must add 2208988800 seconds to this figure to make up for 865 * some seventy years Bell Labs was asleep. 866 */ 867 868 long 869 machtime() 870 { 871 struct timeval tv; 872 873 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 874 fprintf(stderr, "Unable to get time of day\n"); 875 return (0L); 876 } 877 return (htonl((long)tv.tv_sec + 2208988800)); 878 } 879 880 /* ARGSUSED */ 881 machtime_stream(s, sep) 882 int s; 883 struct servtab *sep; 884 { 885 long result; 886 887 result = machtime(); 888 (void) write(s, (char *) &result, sizeof(result)); 889 } 890 891 /* ARGSUSED */ 892 machtime_dg(s, sep) 893 int s; 894 struct servtab *sep; 895 { 896 long result; 897 struct sockaddr sa; 898 int size; 899 900 size = sizeof(sa); 901 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 902 return; 903 result = machtime(); 904 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 905 } 906 907 /* ARGSUSED */ 908 daytime_stream(s, sep) /* Return human-readable time of day */ 909 int s; 910 struct servtab *sep; 911 { 912 char buffer[256]; 913 time_t time(), clock; 914 char *ctime(); 915 916 clock = time((time_t *) 0); 917 918 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 919 (void) write(s, buffer, strlen(buffer)); 920 } 921 922 /* ARGSUSED */ 923 daytime_dg(s, sep) /* Return human-readable time of day */ 924 int s; 925 struct servtab *sep; 926 { 927 char buffer[256]; 928 time_t time(), clock; 929 struct sockaddr sa; 930 int size; 931 char *ctime(); 932 933 clock = time((time_t *) 0); 934 935 size = sizeof(sa); 936 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 937 return; 938 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 939 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 940 } 941 942 /* 943 * print_service: 944 * Dump relevant information to stderr 945 */ 946 print_service(action, sep) 947 char *action; 948 struct servtab *sep; 949 { 950 fprintf(stderr, 951 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 952 action, sep->se_service, sep->se_proto, 953 sep->se_wait, sep->se_user, sep->se_bi, sep->se_server); 954 } 955