1 /* 2 * Copyright (c) 1983,1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)inetd.c 5.30 (Berkeley) 6/3/91"; 42 #endif /* not lint */ 43 44 /* 45 * Inetd - Internet super-server 46 * 47 * This program invokes all internet services as needed. 48 * connection-oriented services are invoked each time a 49 * connection is made, by creating a process. This process 50 * is passed the connection as file descriptor 0 and is 51 * expected to do a getpeername to find out the source host 52 * and port. 53 * 54 * Datagram oriented services are invoked when a datagram 55 * arrives; a process is created and passed a pending message 56 * on file descriptor 0. Datagram servers may either connect 57 * to their peer, freeing up the original socket for inetd 58 * to receive further messages on, or ``take over the socket'', 59 * processing all arriving datagrams and, eventually, timing 60 * out. The first type of server is said to be ``multi-threaded''; 61 * the second type of server ``single-threaded''. 62 * 63 * Inetd uses a configuration file which is read at startup 64 * and, possibly, at some later time in response to a hangup signal. 65 * The configuration file is ``free format'' with fields given in the 66 * order shown below. Continuation lines for an entry must being with 67 * a space or tab. All fields must be present in each entry. 68 * 69 * service name must be in /etc/services 70 * socket type stream/dgram/raw/rdm/seqpacket 71 * protocol must be in /etc/protocols 72 * wait/nowait single-threaded/multi-threaded 73 * user user to run daemon as 74 * server program full path name 75 * server program arguments maximum of MAXARGS (20) 76 * 77 * Comment lines are indicated by a `#' in column 1. 78 */ 79 #include <sys/param.h> 80 #include <sys/stat.h> 81 #include <sys/ioctl.h> 82 #include <sys/socket.h> 83 #include <sys/file.h> 84 #include <sys/wait.h> 85 #include <sys/time.h> 86 #include <sys/resource.h> 87 88 #include <netinet/in.h> 89 #include <arpa/inet.h> 90 91 #include <errno.h> 92 #include <signal.h> 93 #include <netdb.h> 94 #include <syslog.h> 95 #include <pwd.h> 96 #include <stdio.h> 97 #include <string.h> 98 #include "pathnames.h" 99 100 #define TOOMANY 40 /* don't start more than TOOMANY */ 101 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 102 #define RETRYTIME (60*10) /* retry after bind or server fail */ 103 104 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 105 106 extern int errno; 107 108 void config(), reapchild(), retry(); 109 char *index(); 110 char *malloc(); 111 112 int debug = 0; 113 int nsock, maxsock; 114 fd_set allsock; 115 int options; 116 int timingout; 117 struct servent *sp; 118 119 struct servtab { 120 char *se_service; /* name of service */ 121 int se_socktype; /* type of socket to use */ 122 char *se_proto; /* protocol used */ 123 short se_wait; /* single threaded server */ 124 short se_checked; /* looked at during merge */ 125 char *se_user; /* user name to run as */ 126 struct biltin *se_bi; /* if built-in, description */ 127 char *se_server; /* server program */ 128 #define MAXARGV 20 129 char *se_argv[MAXARGV+1]; /* program arguments */ 130 int se_fd; /* open descriptor */ 131 struct sockaddr_in se_ctrladdr;/* bound address */ 132 int se_count; /* number started since se_time */ 133 struct timeval se_time; /* start of se_count */ 134 struct servtab *se_next; 135 } *servtab; 136 137 int echo_stream(), discard_stream(), machtime_stream(); 138 int daytime_stream(), chargen_stream(); 139 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 140 141 struct biltin { 142 char *bi_service; /* internally provided service name */ 143 int bi_socktype; /* type of socket supported */ 144 short bi_fork; /* 1 if should fork before call */ 145 short bi_wait; /* 1 if should wait for child */ 146 int (*bi_fn)(); /* function which performs it */ 147 } biltins[] = { 148 /* Echo received data */ 149 "echo", SOCK_STREAM, 1, 0, echo_stream, 150 "echo", SOCK_DGRAM, 0, 0, echo_dg, 151 152 /* Internet /dev/null */ 153 "discard", SOCK_STREAM, 1, 0, discard_stream, 154 "discard", SOCK_DGRAM, 0, 0, discard_dg, 155 156 /* Return 32 bit time since 1970 */ 157 "time", SOCK_STREAM, 0, 0, machtime_stream, 158 "time", SOCK_DGRAM, 0, 0, machtime_dg, 159 160 /* Return human-readable time */ 161 "daytime", SOCK_STREAM, 0, 0, daytime_stream, 162 "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 163 164 /* Familiar character generator */ 165 "chargen", SOCK_STREAM, 1, 0, chargen_stream, 166 "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 167 0 168 }; 169 170 #define NUMINT (sizeof(intab) / sizeof(struct inent)) 171 char *CONFIG = _PATH_INETDCONF; 172 char **Argv; 173 char *LastArg; 174 175 main(argc, argv, envp) 176 int argc; 177 char *argv[], *envp[]; 178 { 179 extern char *optarg; 180 extern int optind; 181 register struct servtab *sep; 182 register struct passwd *pwd; 183 register int tmpint; 184 struct sigvec sv; 185 int ch, pid, dofork; 186 char buf[50]; 187 188 Argv = argv; 189 if (envp == 0 || *envp == 0) 190 envp = argv; 191 while (*envp) 192 envp++; 193 LastArg = envp[-1] + strlen(envp[-1]); 194 195 while ((ch = getopt(argc, argv, "d")) != EOF) 196 switch(ch) { 197 case 'd': 198 debug = 1; 199 options |= SO_DEBUG; 200 break; 201 case '?': 202 default: 203 fprintf(stderr, "usage: inetd [-d]"); 204 exit(1); 205 } 206 argc -= optind; 207 argv += optind; 208 209 if (argc > 0) 210 CONFIG = argv[0]; 211 if (debug == 0) 212 daemon(0, 0); 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 (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 254 n--; 255 if (debug) 256 fprintf(stderr, "someone wants %s\n", 257 sep->se_service); 258 if (sep->se_socktype == SOCK_STREAM) { 259 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 260 (int *)0); 261 if (debug) 262 fprintf(stderr, "accept, ctrl %d\n", ctrl); 263 if (ctrl < 0) { 264 if (errno == EINTR) 265 continue; 266 syslog(LOG_WARNING, "accept (for %s): %m", 267 sep->se_service); 268 continue; 269 } 270 } else 271 ctrl = sep->se_fd; 272 (void) sigblock(SIGBLOCK); 273 pid = 0; 274 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 275 if (dofork) { 276 if (sep->se_count++ == 0) 277 (void)gettimeofday(&sep->se_time, 278 (struct timezone *)0); 279 else if (sep->se_count >= TOOMANY) { 280 struct timeval now; 281 282 (void)gettimeofday(&now, (struct timezone *)0); 283 if (now.tv_sec - sep->se_time.tv_sec > 284 CNT_INTVL) { 285 sep->se_time = now; 286 sep->se_count = 1; 287 } else { 288 syslog(LOG_ERR, 289 "%s/%s server failing (looping), service terminated\n", 290 sep->se_service, sep->se_proto); 291 FD_CLR(sep->se_fd, &allsock); 292 (void) close(sep->se_fd); 293 sep->se_fd = -1; 294 sep->se_count = 0; 295 nsock--; 296 if (!timingout) { 297 timingout = 1; 298 alarm(RETRYTIME); 299 } 300 } 301 } 302 pid = fork(); 303 } 304 if (pid < 0) { 305 syslog(LOG_ERR, "fork: %m"); 306 if (sep->se_socktype == SOCK_STREAM) 307 close(ctrl); 308 sigsetmask(0L); 309 sleep(1); 310 continue; 311 } 312 if (pid && sep->se_wait) { 313 sep->se_wait = pid; 314 if (sep->se_fd >= 0) { 315 FD_CLR(sep->se_fd, &allsock); 316 nsock--; 317 } 318 } 319 sigsetmask(0L); 320 if (pid == 0) { 321 if (debug && dofork) 322 setsid(); 323 if (dofork) 324 for (tmpint = maxsock; --tmpint > 2; ) 325 if (tmpint != ctrl) 326 close(tmpint); 327 if (sep->se_bi) 328 (*sep->se_bi->bi_fn)(ctrl, sep); 329 else { 330 if (debug) 331 fprintf(stderr, "%d execl %s\n", 332 getpid(), sep->se_server); 333 dup2(ctrl, 0); 334 close(ctrl); 335 dup2(0, 1); 336 dup2(0, 2); 337 if ((pwd = getpwnam(sep->se_user)) == NULL) { 338 syslog(LOG_ERR, 339 "getpwnam: %s: No such user", 340 sep->se_user); 341 if (sep->se_socktype != SOCK_STREAM) 342 recv(0, buf, sizeof (buf), 0); 343 _exit(1); 344 } 345 if (pwd->pw_uid) { 346 (void) setgid((gid_t)pwd->pw_gid); 347 initgroups(pwd->pw_name, pwd->pw_gid); 348 (void) setuid((uid_t)pwd->pw_uid); 349 } 350 execv(sep->se_server, sep->se_argv); 351 if (sep->se_socktype != SOCK_STREAM) 352 recv(0, buf, sizeof (buf), 0); 353 syslog(LOG_ERR, "execv %s: %m", sep->se_server); 354 _exit(1); 355 } 356 } 357 if (sep->se_socktype == SOCK_STREAM) 358 close(ctrl); 359 } 360 } 361 } 362 363 void 364 reapchild() 365 { 366 int status; 367 int pid; 368 register struct servtab *sep; 369 370 for (;;) { 371 pid = wait3(&status, WNOHANG, (struct rusage *)0); 372 if (pid <= 0) 373 break; 374 if (debug) 375 fprintf(stderr, "%d reaped\n", pid); 376 for (sep = servtab; sep; sep = sep->se_next) 377 if (sep->se_wait == pid) { 378 if (status) 379 syslog(LOG_WARNING, 380 "%s: exit status 0x%x", 381 sep->se_server, status); 382 if (debug) 383 fprintf(stderr, "restored %s, fd %d\n", 384 sep->se_service, sep->se_fd); 385 FD_SET(sep->se_fd, &allsock); 386 nsock++; 387 sep->se_wait = 1; 388 } 389 } 390 } 391 392 void 393 config() 394 { 395 register struct servtab *sep, *cp, **sepp; 396 struct servtab *getconfigent(), *enter(); 397 long omask; 398 399 if (!setconfig()) { 400 syslog(LOG_ERR, "%s: %m", CONFIG); 401 return; 402 } 403 for (sep = servtab; sep; sep = sep->se_next) 404 sep->se_checked = 0; 405 while (cp = getconfigent()) { 406 for (sep = servtab; sep; sep = sep->se_next) 407 if (strcmp(sep->se_service, cp->se_service) == 0 && 408 strcmp(sep->se_proto, cp->se_proto) == 0) 409 break; 410 if (sep != 0) { 411 int i; 412 413 omask = sigblock(SIGBLOCK); 414 /* 415 * sep->se_wait may be holding the pid of a daemon 416 * that we're waiting for. If so, don't overwrite 417 * it unless the config file explicitly says don't 418 * wait. 419 */ 420 if (cp->se_bi == 0 && 421 (sep->se_wait == 1 || cp->se_wait == 0)) 422 sep->se_wait = cp->se_wait; 423 #define SWAP(a, b) { char *c = a; a = b; b = c; } 424 if (cp->se_user) 425 SWAP(sep->se_user, cp->se_user); 426 if (cp->se_server) 427 SWAP(sep->se_server, cp->se_server); 428 for (i = 0; i < MAXARGV; i++) 429 SWAP(sep->se_argv[i], cp->se_argv[i]); 430 sigsetmask(omask); 431 freeconfig(cp); 432 if (debug) 433 print_service("REDO", sep); 434 } else { 435 sep = enter(cp); 436 if (debug) 437 print_service("ADD ", sep); 438 } 439 sep->se_checked = 1; 440 sp = getservbyname(sep->se_service, sep->se_proto); 441 if (sp == 0) { 442 syslog(LOG_ERR, "%s/%s: unknown service", 443 sep->se_service, sep->se_proto); 444 if (sep->se_fd != -1) 445 (void) close(sep->se_fd); 446 sep->se_fd = -1; 447 continue; 448 } 449 if (sp->s_port != sep->se_ctrladdr.sin_port) { 450 sep->se_ctrladdr.sin_port = sp->s_port; 451 if (sep->se_fd != -1) 452 (void) close(sep->se_fd); 453 sep->se_fd = -1; 454 } 455 if (sep->se_fd == -1) 456 setup(sep); 457 } 458 endconfig(); 459 /* 460 * Purge anything not looked at above. 461 */ 462 omask = sigblock(SIGBLOCK); 463 sepp = &servtab; 464 while (sep = *sepp) { 465 if (sep->se_checked) { 466 sepp = &sep->se_next; 467 continue; 468 } 469 *sepp = sep->se_next; 470 if (sep->se_fd != -1) { 471 FD_CLR(sep->se_fd, &allsock); 472 nsock--; 473 (void) close(sep->se_fd); 474 } 475 if (debug) 476 print_service("FREE", sep); 477 freeconfig(sep); 478 free((char *)sep); 479 } 480 (void) sigsetmask(omask); 481 } 482 483 void 484 retry() 485 { 486 register struct servtab *sep; 487 488 timingout = 0; 489 for (sep = servtab; sep; sep = sep->se_next) 490 if (sep->se_fd == -1) 491 setup(sep); 492 } 493 494 setup(sep) 495 register struct servtab *sep; 496 { 497 int on = 1; 498 499 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 500 syslog(LOG_ERR, "%s/%s: socket: %m", 501 sep->se_service, sep->se_proto); 502 return; 503 } 504 #define turnon(fd, opt) \ 505 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 506 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 507 turnon(sep->se_fd, SO_DEBUG) < 0) 508 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 509 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 510 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 511 #undef turnon 512 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 513 sizeof (sep->se_ctrladdr)) < 0) { 514 syslog(LOG_ERR, "%s/%s: bind: %m", 515 sep->se_service, sep->se_proto); 516 (void) close(sep->se_fd); 517 sep->se_fd = -1; 518 if (!timingout) { 519 timingout = 1; 520 alarm(RETRYTIME); 521 } 522 return; 523 } 524 if (sep->se_socktype == SOCK_STREAM) 525 listen(sep->se_fd, 10); 526 FD_SET(sep->se_fd, &allsock); 527 nsock++; 528 if (sep->se_fd > maxsock) 529 maxsock = sep->se_fd; 530 } 531 532 struct servtab * 533 enter(cp) 534 struct servtab *cp; 535 { 536 register struct servtab *sep; 537 long omask; 538 539 sep = (struct servtab *)malloc(sizeof (*sep)); 540 if (sep == (struct servtab *)0) { 541 syslog(LOG_ERR, "Out of memory."); 542 exit(-1); 543 } 544 *sep = *cp; 545 sep->se_fd = -1; 546 omask = sigblock(SIGBLOCK); 547 sep->se_next = servtab; 548 servtab = sep; 549 sigsetmask(omask); 550 return (sep); 551 } 552 553 FILE *fconfig = NULL; 554 struct servtab serv; 555 char line[256]; 556 char *skip(), *nextline(); 557 558 setconfig() 559 { 560 561 if (fconfig != NULL) { 562 fseek(fconfig, 0L, L_SET); 563 return (1); 564 } 565 fconfig = fopen(CONFIG, "r"); 566 return (fconfig != NULL); 567 } 568 569 endconfig() 570 { 571 if (fconfig) { 572 (void) fclose(fconfig); 573 fconfig = NULL; 574 } 575 } 576 577 struct servtab * 578 getconfigent() 579 { 580 register struct servtab *sep = &serv; 581 int argc; 582 char *cp, *arg, *newstr(); 583 584 more: 585 while ((cp = nextline(fconfig)) && *cp == '#') 586 ; 587 if (cp == NULL) 588 return ((struct servtab *)0); 589 sep->se_service = newstr(skip(&cp)); 590 arg = skip(&cp); 591 if (strcmp(arg, "stream") == 0) 592 sep->se_socktype = SOCK_STREAM; 593 else if (strcmp(arg, "dgram") == 0) 594 sep->se_socktype = SOCK_DGRAM; 595 else if (strcmp(arg, "rdm") == 0) 596 sep->se_socktype = SOCK_RDM; 597 else if (strcmp(arg, "seqpacket") == 0) 598 sep->se_socktype = SOCK_SEQPACKET; 599 else if (strcmp(arg, "raw") == 0) 600 sep->se_socktype = SOCK_RAW; 601 else 602 sep->se_socktype = -1; 603 sep->se_proto = newstr(skip(&cp)); 604 arg = skip(&cp); 605 sep->se_wait = strcmp(arg, "wait") == 0; 606 sep->se_user = newstr(skip(&cp)); 607 sep->se_server = newstr(skip(&cp)); 608 if (strcmp(sep->se_server, "internal") == 0) { 609 register struct biltin *bi; 610 611 for (bi = biltins; bi->bi_service; bi++) 612 if (bi->bi_socktype == sep->se_socktype && 613 strcmp(bi->bi_service, sep->se_service) == 0) 614 break; 615 if (bi->bi_service == 0) { 616 syslog(LOG_ERR, "internal service %s unknown\n", 617 sep->se_service); 618 goto more; 619 } 620 sep->se_bi = bi; 621 sep->se_wait = bi->bi_wait; 622 } else 623 sep->se_bi = NULL; 624 argc = 0; 625 for (arg = skip(&cp); cp; arg = skip(&cp)) 626 if (argc < MAXARGV) 627 sep->se_argv[argc++] = newstr(arg); 628 while (argc <= MAXARGV) 629 sep->se_argv[argc++] = NULL; 630 return (sep); 631 } 632 633 freeconfig(cp) 634 register struct servtab *cp; 635 { 636 int i; 637 638 if (cp->se_service) 639 free(cp->se_service); 640 if (cp->se_proto) 641 free(cp->se_proto); 642 if (cp->se_user) 643 free(cp->se_user); 644 if (cp->se_server) 645 free(cp->se_server); 646 for (i = 0; i < MAXARGV; i++) 647 if (cp->se_argv[i]) 648 free(cp->se_argv[i]); 649 } 650 651 char * 652 skip(cpp) 653 char **cpp; 654 { 655 register char *cp = *cpp; 656 char *start; 657 658 again: 659 while (*cp == ' ' || *cp == '\t') 660 cp++; 661 if (*cp == '\0') { 662 int c; 663 664 c = getc(fconfig); 665 (void) ungetc(c, fconfig); 666 if (c == ' ' || c == '\t') 667 if (cp = nextline(fconfig)) 668 goto again; 669 *cpp = (char *)0; 670 return ((char *)0); 671 } 672 start = cp; 673 while (*cp && *cp != ' ' && *cp != '\t') 674 cp++; 675 if (*cp != '\0') 676 *cp++ = '\0'; 677 *cpp = cp; 678 return (start); 679 } 680 681 char * 682 nextline(fd) 683 FILE *fd; 684 { 685 char *cp; 686 687 if (fgets(line, sizeof (line), fd) == NULL) 688 return ((char *)0); 689 cp = index(line, '\n'); 690 if (cp) 691 *cp = '\0'; 692 return (line); 693 } 694 695 char * 696 newstr(cp) 697 char *cp; 698 { 699 if (cp = strdup(cp ? cp : "")) 700 return(cp); 701 syslog(LOG_ERR, "strdup: %m"); 702 exit(-1); 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, (struct sockaddr *)&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 #define BUFSIZE 8192 730 731 /* ARGSUSED */ 732 echo_stream(s, sep) /* Echo service -- echo data back */ 733 int s; 734 struct servtab *sep; 735 { 736 char buffer[BUFSIZE]; 737 int i; 738 739 setproctitle(sep->se_service, s); 740 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 741 write(s, buffer, i) > 0) 742 ; 743 exit(0); 744 } 745 746 /* ARGSUSED */ 747 echo_dg(s, sep) /* Echo service -- echo data back */ 748 int s; 749 struct servtab *sep; 750 { 751 char buffer[BUFSIZE]; 752 int i, size; 753 struct sockaddr sa; 754 755 size = sizeof(sa); 756 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 757 return; 758 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 759 } 760 761 /* ARGSUSED */ 762 discard_stream(s, sep) /* Discard service -- ignore data */ 763 int s; 764 struct servtab *sep; 765 { 766 int ret; 767 char buffer[BUFSIZE]; 768 769 setproctitle(sep->se_service, s); 770 while (1) { 771 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 772 ; 773 if (ret == 0 || 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