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.16 (Berkeley) 05/11/89"; 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 <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 int 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 5 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 reapchild() 370 { 371 union wait status; 372 int pid; 373 register struct servtab *sep; 374 375 for (;;) { 376 pid = wait3(&status, WNOHANG, (struct rusage *)0); 377 if (pid <= 0) 378 break; 379 if (debug) 380 fprintf(stderr, "%d reaped\n", pid); 381 for (sep = servtab; sep; sep = sep->se_next) 382 if (sep->se_wait == pid) { 383 if (status.w_status) 384 syslog(LOG_WARNING, 385 "%s: exit status 0x%x", 386 sep->se_server, status); 387 if (debug) 388 fprintf(stderr, "restored %s, fd %d\n", 389 sep->se_service, sep->se_fd); 390 FD_SET(sep->se_fd, &allsock); 391 nsock++; 392 sep->se_wait = 1; 393 } 394 } 395 } 396 397 config() 398 { 399 register struct servtab *sep, *cp, **sepp; 400 struct servtab *getconfigent(), *enter(); 401 long omask; 402 403 if (!setconfig()) { 404 syslog(LOG_ERR, "%s: %m", CONFIG); 405 return; 406 } 407 for (sep = servtab; sep; sep = sep->se_next) 408 sep->se_checked = 0; 409 while (cp = getconfigent()) { 410 for (sep = servtab; sep; sep = sep->se_next) 411 if (strcmp(sep->se_service, cp->se_service) == 0 && 412 strcmp(sep->se_proto, cp->se_proto) == 0) 413 break; 414 if (sep != 0) { 415 int i; 416 417 omask = sigblock(SIGBLOCK); 418 if (cp->se_bi == 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 retry() 478 { 479 register struct servtab *sep; 480 481 timingout = 0; 482 for (sep = servtab; sep; sep = sep->se_next) 483 if (sep->se_fd == -1) 484 setup(sep); 485 } 486 487 setup(sep) 488 register struct servtab *sep; 489 { 490 int on = 1; 491 492 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 493 syslog(LOG_ERR, "%s/%s: socket: %m", 494 sep->se_service, sep->se_proto); 495 return; 496 } 497 #define turnon(fd, opt) \ 498 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 499 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 500 turnon(sep->se_fd, SO_DEBUG) < 0) 501 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 502 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 503 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 504 #undef turnon 505 if (bind(sep->se_fd, &sep->se_ctrladdr, 506 sizeof (sep->se_ctrladdr)) < 0) { 507 syslog(LOG_ERR, "%s/%s: bind: %m", 508 sep->se_service, sep->se_proto); 509 (void) close(sep->se_fd); 510 sep->se_fd = -1; 511 if (!timingout) { 512 timingout = 1; 513 alarm(RETRYTIME); 514 } 515 return; 516 } 517 if (sep->se_socktype == SOCK_STREAM) 518 listen(sep->se_fd, 10); 519 FD_SET(sep->se_fd, &allsock); 520 nsock++; 521 if (sep->se_fd > maxsock) 522 maxsock = sep->se_fd; 523 } 524 525 struct servtab * 526 enter(cp) 527 struct servtab *cp; 528 { 529 register struct servtab *sep; 530 long omask; 531 532 sep = (struct servtab *)malloc(sizeof (*sep)); 533 if (sep == (struct servtab *)0) { 534 syslog(LOG_ERR, "Out of memory."); 535 exit(-1); 536 } 537 *sep = *cp; 538 sep->se_fd = -1; 539 omask = sigblock(SIGBLOCK); 540 sep->se_next = servtab; 541 servtab = sep; 542 sigsetmask(omask); 543 return (sep); 544 } 545 546 FILE *fconfig = NULL; 547 struct servtab serv; 548 char line[256]; 549 char *skip(), *nextline(); 550 551 setconfig() 552 { 553 554 if (fconfig != NULL) { 555 fseek(fconfig, 0L, L_SET); 556 return (1); 557 } 558 fconfig = fopen(CONFIG, "r"); 559 return (fconfig != NULL); 560 } 561 562 endconfig() 563 { 564 if (fconfig) { 565 (void) fclose(fconfig); 566 fconfig = NULL; 567 } 568 } 569 570 struct servtab * 571 getconfigent() 572 { 573 register struct servtab *sep = &serv; 574 int argc; 575 char *cp, *arg, *strdup(); 576 577 more: 578 while ((cp = nextline(fconfig)) && *cp == '#') 579 ; 580 if (cp == NULL) 581 return ((struct servtab *)0); 582 sep->se_service = strdup(skip(&cp)); 583 arg = skip(&cp); 584 if (strcmp(arg, "stream") == 0) 585 sep->se_socktype = SOCK_STREAM; 586 else if (strcmp(arg, "dgram") == 0) 587 sep->se_socktype = SOCK_DGRAM; 588 else if (strcmp(arg, "rdm") == 0) 589 sep->se_socktype = SOCK_RDM; 590 else if (strcmp(arg, "seqpacket") == 0) 591 sep->se_socktype = SOCK_SEQPACKET; 592 else if (strcmp(arg, "raw") == 0) 593 sep->se_socktype = SOCK_RAW; 594 else 595 sep->se_socktype = -1; 596 sep->se_proto = strdup(skip(&cp)); 597 arg = skip(&cp); 598 sep->se_wait = strcmp(arg, "wait") == 0; 599 sep->se_user = strdup(skip(&cp)); 600 sep->se_server = strdup(skip(&cp)); 601 if (strcmp(sep->se_server, "internal") == 0) { 602 register struct biltin *bi; 603 604 for (bi = biltins; bi->bi_service; bi++) 605 if (bi->bi_socktype == sep->se_socktype && 606 strcmp(bi->bi_service, sep->se_service) == 0) 607 break; 608 if (bi->bi_service == 0) { 609 syslog(LOG_ERR, "internal service %s unknown\n", 610 sep->se_service); 611 goto more; 612 } 613 sep->se_bi = bi; 614 sep->se_wait = bi->bi_wait; 615 } else 616 sep->se_bi = NULL; 617 argc = 0; 618 for (arg = skip(&cp); cp; arg = skip(&cp)) 619 if (argc < MAXARGV) 620 sep->se_argv[argc++] = strdup(arg); 621 while (argc <= MAXARGV) 622 sep->se_argv[argc++] = NULL; 623 return (sep); 624 } 625 626 freeconfig(cp) 627 register struct servtab *cp; 628 { 629 int i; 630 631 if (cp->se_service) 632 free(cp->se_service); 633 if (cp->se_proto) 634 free(cp->se_proto); 635 if (cp->se_user) 636 free(cp->se_user); 637 if (cp->se_server) 638 free(cp->se_server); 639 for (i = 0; i < MAXARGV; i++) 640 if (cp->se_argv[i]) 641 free(cp->se_argv[i]); 642 } 643 644 char * 645 skip(cpp) 646 char **cpp; 647 { 648 register char *cp = *cpp; 649 char *start; 650 651 again: 652 while (*cp == ' ' || *cp == '\t') 653 cp++; 654 if (*cp == '\0') { 655 char c; 656 657 c = getc(fconfig); 658 (void) ungetc(c, fconfig); 659 if (c == ' ' || c == '\t') 660 if (cp = nextline(fconfig)) 661 goto again; 662 *cpp = (char *)0; 663 return ((char *)0); 664 } 665 start = cp; 666 while (*cp && *cp != ' ' && *cp != '\t') 667 cp++; 668 if (*cp != '\0') 669 *cp++ = '\0'; 670 *cpp = cp; 671 return (start); 672 } 673 674 char * 675 nextline(fd) 676 FILE *fd; 677 { 678 char *cp; 679 680 if (fgets(line, sizeof (line), fd) == NULL) 681 return ((char *)0); 682 cp = index(line, '\n'); 683 if (cp) 684 *cp = '\0'; 685 return (line); 686 } 687 688 char * 689 strdup(cp) 690 char *cp; 691 { 692 char *new; 693 694 if (cp == NULL) 695 cp = ""; 696 new = malloc((unsigned)(strlen(cp) + 1)); 697 if (new == (char *)0) { 698 syslog(LOG_ERR, "Out of memory."); 699 exit(-1); 700 } 701 (void)strcpy(new, cp); 702 return (new); 703 } 704 705 setproctitle(a, s) 706 char *a; 707 int s; 708 { 709 int size; 710 register char *cp; 711 struct sockaddr_in sin; 712 char buf[80]; 713 714 cp = Argv[0]; 715 size = sizeof(sin); 716 if (getpeername(s, &sin, &size) == 0) 717 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 718 else 719 (void) sprintf(buf, "-%s", a); 720 strncpy(cp, buf, LastArg - cp); 721 cp += strlen(cp); 722 while (cp < LastArg) 723 *cp++ = ' '; 724 } 725 726 /* 727 * Internet services provided internally by inetd: 728 */ 729 730 /* ARGSUSED */ 731 echo_stream(s, sep) /* Echo service -- echo data back */ 732 int s; 733 struct servtab *sep; 734 { 735 char buffer[BUFSIZ]; 736 int i; 737 738 setproctitle(sep->se_service, s); 739 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 740 write(s, buffer, i) > 0) 741 ; 742 exit(0); 743 } 744 745 /* ARGSUSED */ 746 echo_dg(s, sep) /* Echo service -- echo data back */ 747 int s; 748 struct servtab *sep; 749 { 750 char buffer[BUFSIZ]; 751 int i, size; 752 struct sockaddr sa; 753 754 size = sizeof(sa); 755 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 756 return; 757 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 758 } 759 760 /* ARGSUSED */ 761 discard_stream(s, sep) /* Discard service -- ignore data */ 762 int s; 763 struct servtab *sep; 764 { 765 char buffer[BUFSIZ]; 766 767 setproctitle(sep->se_service, s); 768 while (1) { 769 while (read(s, buffer, sizeof(buffer)) > 0) 770 ; 771 if (errno != EINTR) 772 break; 773 } 774 exit(0); 775 } 776 777 /* ARGSUSED */ 778 discard_dg(s, sep) /* Discard service -- ignore data */ 779 int s; 780 struct servtab *sep; 781 { 782 char buffer[BUFSIZ]; 783 784 (void) read(s, buffer, sizeof(buffer)); 785 } 786 787 #include <ctype.h> 788 #define LINESIZ 72 789 char ring[128]; 790 char *endring; 791 792 initring() 793 { 794 register int i; 795 796 endring = ring; 797 798 for (i = 0; i <= 128; ++i) 799 if (isprint(i)) 800 *endring++ = i; 801 } 802 803 /* ARGSUSED */ 804 chargen_stream(s, sep) /* Character generator */ 805 int s; 806 struct servtab *sep; 807 { 808 register char *rs; 809 int len; 810 char text[LINESIZ+2]; 811 812 setproctitle(sep->se_service, s); 813 814 if (!endring) { 815 initring(); 816 rs = ring; 817 } 818 819 text[LINESIZ] = '\r'; 820 text[LINESIZ + 1] = '\n'; 821 for (rs = ring;;) { 822 if ((len = endring - rs) >= LINESIZ) 823 bcopy(rs, text, LINESIZ); 824 else { 825 bcopy(rs, text, len); 826 bcopy(ring, text + len, LINESIZ - len); 827 } 828 if (++rs == endring) 829 rs = ring; 830 if (write(s, text, sizeof(text)) != sizeof(text)) 831 break; 832 } 833 exit(0); 834 } 835 836 /* ARGSUSED */ 837 chargen_dg(s, sep) /* Character generator */ 838 int s; 839 struct servtab *sep; 840 { 841 struct sockaddr sa; 842 static char *rs; 843 int len, size; 844 char text[LINESIZ+2]; 845 846 if (endring == 0) { 847 initring(); 848 rs = ring; 849 } 850 851 size = sizeof(sa); 852 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 853 return; 854 855 if ((len = endring - rs) >= LINESIZ) 856 bcopy(rs, text, LINESIZ); 857 else { 858 bcopy(rs, text, len); 859 bcopy(ring, text + len, LINESIZ - len); 860 } 861 if (++rs == endring) 862 rs = ring; 863 text[LINESIZ] = '\r'; 864 text[LINESIZ + 1] = '\n'; 865 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 866 } 867 868 /* 869 * Return a machine readable date and time, in the form of the 870 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 871 * returns the number of seconds since midnight, Jan 1, 1970, 872 * we must add 2208988800 seconds to this figure to make up for 873 * some seventy years Bell Labs was asleep. 874 */ 875 876 long 877 machtime() 878 { 879 struct timeval tv; 880 881 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 882 fprintf(stderr, "Unable to get time of day\n"); 883 return (0L); 884 } 885 return (htonl((long)tv.tv_sec + 2208988800)); 886 } 887 888 /* ARGSUSED */ 889 machtime_stream(s, sep) 890 int s; 891 struct servtab *sep; 892 { 893 long result; 894 895 result = machtime(); 896 (void) write(s, (char *) &result, sizeof(result)); 897 } 898 899 /* ARGSUSED */ 900 machtime_dg(s, sep) 901 int s; 902 struct servtab *sep; 903 { 904 long result; 905 struct sockaddr sa; 906 int size; 907 908 size = sizeof(sa); 909 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 910 return; 911 result = machtime(); 912 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 913 } 914 915 /* ARGSUSED */ 916 daytime_stream(s, sep) /* Return human-readable time of day */ 917 int s; 918 struct servtab *sep; 919 { 920 char buffer[256]; 921 time_t time(), clock; 922 char *ctime(); 923 924 clock = time((time_t *) 0); 925 926 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 927 (void) write(s, buffer, strlen(buffer)); 928 } 929 930 /* ARGSUSED */ 931 daytime_dg(s, sep) /* Return human-readable time of day */ 932 int s; 933 struct servtab *sep; 934 { 935 char buffer[256]; 936 time_t time(), clock; 937 struct sockaddr sa; 938 int size; 939 char *ctime(); 940 941 clock = time((time_t *) 0); 942 943 size = sizeof(sa); 944 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 945 return; 946 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 947 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 948 } 949 950 /* 951 * print_service: 952 * Dump relevant information to stderr 953 */ 954 print_service(action, sep) 955 char *action; 956 struct servtab *sep; 957 { 958 fprintf(stderr, 959 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 960 action, sep->se_service, sep->se_proto, 961 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 962 } 963