1 /* 2 * Copyright (c) 1983, 1991, 1993 The 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, 1991, 1993 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.32 (Berkeley) 05/16/93"; 16 #endif /* not lint */ 17 18 /* 19 * Inetd - Internet super-server 20 * 21 * This program invokes all internet services as needed. Connection-oriented 22 * services are invoked each time a connection is made, by creating a process. 23 * This process is passed the connection as file descriptor 0 and is expected 24 * to do a getpeername to find out the source host and port. 25 * 26 * Datagram oriented services are invoked when a datagram 27 * arrives; a process is created and passed a pending message 28 * on file descriptor 0. Datagram servers may either connect 29 * to their peer, freeing up the original socket for inetd 30 * to receive further messages on, or ``take over the socket'', 31 * processing all arriving datagrams and, eventually, timing 32 * out. The first type of server is said to be ``multi-threaded''; 33 * the second type of server ``single-threaded''. 34 * 35 * Inetd uses a configuration file which is read at startup 36 * and, possibly, at some later time in response to a hangup signal. 37 * The configuration file is ``free format'' with fields given in the 38 * order shown below. Continuation lines for an entry must being with 39 * a space or tab. All fields must be present in each entry. 40 * 41 * service name must be in /etc/services or must 42 * name a tcpmux service 43 * socket type stream/dgram/raw/rdm/seqpacket 44 * protocol must be in /etc/protocols 45 * wait/nowait single-threaded/multi-threaded 46 * user user to run daemon as 47 * server program full path name 48 * server program arguments maximum of MAXARGS (20) 49 * 50 * TCP services without official port numbers are handled with the 51 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for 52 * requests. When a connection is made from a foreign host, the service 53 * requested is passed to tcpmux, which looks it up in the servtab list 54 * and returns the proper entry for the service. Tcpmux returns a 55 * negative reply if the service doesn't exist, otherwise the invoked 56 * server is expected to return the positive reply if the service type in 57 * inetd.conf file has the prefix "tcpmux/". If the service type has the 58 * prefix "tcpmux/+", tcpmux will return the positive reply for the 59 * process; this is for compatibility with older server code, and also 60 * allows you to invoke programs that use stdin/stdout without putting any 61 * special server code in them. Services that use tcpmux are "nowait" 62 * because they do not have a well-known port and hence cannot listen 63 * for new requests. 64 * 65 * Comment lines are indicated by a `#' in column 1. 66 */ 67 #include <sys/param.h> 68 #include <sys/stat.h> 69 #include <sys/ioctl.h> 70 #include <sys/socket.h> 71 #include <sys/wait.h> 72 #include <sys/time.h> 73 #include <sys/resource.h> 74 75 #include <netinet/in.h> 76 #include <arpa/inet.h> 77 78 #include <errno.h> 79 #include <fcntl.h> 80 #include <netdb.h> 81 #include <pwd.h> 82 #include <signal.h> 83 #include <stdio.h> 84 #include <stdlib.h> 85 #include <string.h> 86 #include <syslog.h> 87 #include <unistd.h> 88 89 #include "pathnames.h" 90 91 #define TOOMANY 40 /* don't start more than TOOMANY */ 92 #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ 93 #define RETRYTIME (60*10) /* retry after bind or server fail */ 94 95 #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) 96 97 98 void config(), reapchild(), retry(); 99 100 int debug = 0; 101 int nsock, maxsock; 102 fd_set allsock; 103 int options; 104 int timingout; 105 int toomany = TOOMANY; 106 struct servent *sp; 107 108 struct servtab { 109 char *se_service; /* name of service */ 110 int se_socktype; /* type of socket to use */ 111 char *se_proto; /* protocol used */ 112 short se_wait; /* single threaded server */ 113 short se_checked; /* looked at during merge */ 114 char *se_user; /* user name to run as */ 115 struct biltin *se_bi; /* if built-in, description */ 116 char *se_server; /* server program */ 117 #define MAXARGV 20 118 char *se_argv[MAXARGV+1]; /* program arguments */ 119 int se_fd; /* open descriptor */ 120 int se_type; /* type */ 121 struct sockaddr_in se_ctrladdr;/* bound address */ 122 int se_count; /* number started since se_time */ 123 struct timeval se_time; /* start of se_count */ 124 struct servtab *se_next; 125 } *servtab; 126 127 #define NORM_TYPE 0 128 #define MUX_TYPE 1 129 #define MUXPLUS_TYPE 2 130 #define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \ 131 ((sep)->se_type == MUXPLUS_TYPE)) 132 #define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE) 133 134 int echo_stream(), discard_stream(), machtime_stream(); 135 int daytime_stream(), chargen_stream(); 136 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); 137 struct servtab *tcpmux(); 138 139 struct biltin { 140 char *bi_service; /* internally provided service name */ 141 int bi_socktype; /* type of socket supported */ 142 short bi_fork; /* 1 if should fork before call */ 143 short bi_wait; /* 1 if should wait for child */ 144 int (*bi_fn)(); /* function which performs it */ 145 } biltins[] = { 146 /* Echo received data */ 147 "echo", SOCK_STREAM, 1, 0, echo_stream, 148 "echo", SOCK_DGRAM, 0, 0, echo_dg, 149 150 /* Internet /dev/null */ 151 "discard", SOCK_STREAM, 1, 0, discard_stream, 152 "discard", SOCK_DGRAM, 0, 0, discard_dg, 153 154 /* Return 32 bit time since 1970 */ 155 "time", SOCK_STREAM, 0, 0, machtime_stream, 156 "time", SOCK_DGRAM, 0, 0, machtime_dg, 157 158 /* Return human-readable time */ 159 "daytime", SOCK_STREAM, 0, 0, daytime_stream, 160 "daytime", SOCK_DGRAM, 0, 0, daytime_dg, 161 162 /* Familiar character generator */ 163 "chargen", SOCK_STREAM, 1, 0, chargen_stream, 164 "chargen", SOCK_DGRAM, 0, 0, chargen_dg, 165 166 "tcpmux", SOCK_STREAM, 1, 0, (int (*)())tcpmux, 167 168 NULL 169 }; 170 171 #define NUMINT (sizeof(intab) / sizeof(struct inent)) 172 char *CONFIG = _PATH_INETDCONF; 173 char **Argv; 174 char *LastArg; 175 176 main(argc, argv, envp) 177 int argc; 178 char *argv[], *envp[]; 179 { 180 register struct servtab *sep; 181 register struct passwd *pwd; 182 register int tmpint; 183 struct sigvec sv; 184 int ch, pid, dofork; 185 char buf[50]; 186 187 Argv = argv; 188 if (envp == 0 || *envp == 0) 189 envp = argv; 190 while (*envp) 191 envp++; 192 LastArg = envp[-1] + strlen(envp[-1]); 193 194 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); 195 196 while ((ch = getopt(argc, argv, "dR:")) != EOF) 197 switch(ch) { 198 case 'd': 199 debug = 1; 200 options |= SO_DEBUG; 201 break; 202 case 'R': { /* invocation rate */ 203 char *p; 204 205 tmpint = strtol(optarg, &p, 0); 206 if (tmpint < 1 || *p) 207 syslog(LOG_ERR, 208 "-R %s: bad value for service invocation rate", 209 optarg); 210 else 211 toomany = tmpint; 212 break; 213 } 214 case '?': 215 default: 216 syslog(LOG_ERR, 217 "usage: inetd [-d] [-R rate] [conf-file]"); 218 exit(1); 219 } 220 argc -= optind; 221 argv += optind; 222 223 if (argc > 0) 224 CONFIG = argv[0]; 225 if (debug == 0) { 226 daemon(0, 0); 227 } 228 bzero(&sv, sizeof(sv)); 229 sv.sv_mask = SIGBLOCK; 230 sv.sv_handler = retry; 231 sigvec(SIGALRM, &sv, (struct sigvec *)0); 232 config(); 233 sv.sv_handler = config; 234 sigvec(SIGHUP, &sv, (struct sigvec *)0); 235 sv.sv_handler = reapchild; 236 sigvec(SIGCHLD, &sv, (struct sigvec *)0); 237 238 { 239 /* space for daemons to overwrite environment for ps */ 240 #define DUMMYSIZE 100 241 char dummy[DUMMYSIZE]; 242 243 (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); 244 dummy[DUMMYSIZE - 1] = '\0'; 245 (void)setenv("inetd_dummy", dummy, 1); 246 } 247 248 for (;;) { 249 int n, ctrl; 250 fd_set readable; 251 252 if (nsock == 0) { 253 (void) sigblock(SIGBLOCK); 254 while (nsock == 0) 255 sigpause(0L); 256 (void) sigsetmask(0L); 257 } 258 readable = allsock; 259 if ((n = select(maxsock + 1, &readable, (fd_set *)0, 260 (fd_set *)0, (struct timeval *)0)) <= 0) { 261 if (n < 0 && errno != EINTR) 262 syslog(LOG_WARNING, "select: %m"); 263 sleep(1); 264 continue; 265 } 266 for (sep = servtab; n && sep; sep = sep->se_next) 267 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { 268 n--; 269 if (debug) 270 fprintf(stderr, "someone wants %s\n", 271 sep->se_service); 272 if (sep->se_socktype == SOCK_STREAM) { 273 ctrl = accept(sep->se_fd, (struct sockaddr *)0, 274 (int *)0); 275 if (debug) 276 fprintf(stderr, "accept, ctrl %d\n", ctrl); 277 if (ctrl < 0) { 278 if (errno != EINTR) 279 syslog(LOG_WARNING, 280 "accept (for %s): %m", 281 sep->se_service); 282 continue; 283 } 284 /* 285 * Call tcpmux to find the real service to exec. 286 */ 287 if (sep->se_bi && 288 sep->se_bi->bi_fn == (int (*)()) tcpmux) { 289 sep = tcpmux(ctrl); 290 if (sep == NULL) { 291 close(ctrl); 292 continue; 293 } 294 } 295 } else 296 ctrl = sep->se_fd; 297 (void) sigblock(SIGBLOCK); 298 pid = 0; 299 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); 300 if (dofork) { 301 if (sep->se_count++ == 0) 302 (void)gettimeofday(&sep->se_time, 303 (struct timezone *)0); 304 else if (sep->se_count >= toomany) { 305 struct timeval now; 306 307 (void)gettimeofday(&now, (struct timezone *)0); 308 if (now.tv_sec - sep->se_time.tv_sec > 309 CNT_INTVL) { 310 sep->se_time = now; 311 sep->se_count = 1; 312 } else { 313 syslog(LOG_ERR, 314 "%s/%s server failing (looping), service terminated", 315 sep->se_service, sep->se_proto); 316 close_sep(sep); 317 sigsetmask(0L); 318 if (!timingout) { 319 timingout = 1; 320 alarm(RETRYTIME); 321 } 322 continue; 323 } 324 } 325 pid = fork(); 326 } 327 if (pid < 0) { 328 syslog(LOG_ERR, "fork: %m"); 329 if (sep->se_socktype == SOCK_STREAM) 330 close(ctrl); 331 sigsetmask(0L); 332 sleep(1); 333 continue; 334 } 335 if (pid && sep->se_wait) { 336 sep->se_wait = pid; 337 if (sep->se_fd >= 0) { 338 FD_CLR(sep->se_fd, &allsock); 339 nsock--; 340 } 341 } 342 sigsetmask(0L); 343 if (pid == 0) { 344 if (debug && dofork) 345 setsid(); 346 if (dofork) { 347 if (debug) 348 fprintf(stderr, "+ Closing from %d\n", 349 maxsock); 350 for (tmpint = maxsock; tmpint > 2; tmpint--) 351 if (tmpint != ctrl) 352 close(tmpint); 353 } 354 if (sep->se_bi) 355 (*sep->se_bi->bi_fn)(ctrl, sep); 356 else { 357 if (debug) 358 fprintf(stderr, "%d execl %s\n", 359 getpid(), sep->se_server); 360 dup2(ctrl, 0); 361 close(ctrl); 362 dup2(0, 1); 363 dup2(0, 2); 364 if ((pwd = getpwnam(sep->se_user)) == NULL) { 365 syslog(LOG_ERR, 366 "%s/%s: %s: No such user", 367 sep->se_service, sep->se_proto, 368 sep->se_user); 369 if (sep->se_socktype != SOCK_STREAM) 370 recv(0, buf, sizeof (buf), 0); 371 _exit(1); 372 } 373 if (pwd->pw_uid) { 374 if (setgid(pwd->pw_gid) < 0) { 375 syslog(LOG_ERR, 376 "%s: can't set gid %d: %m", 377 sep->se_service, pwd->pw_gid); 378 _exit(1); 379 } 380 (void) initgroups(pwd->pw_name, 381 pwd->pw_gid); 382 if (setuid(pwd->pw_uid) < 0) { 383 syslog(LOG_ERR, 384 "%s: can't set uid %d: %m", 385 sep->se_service, pwd->pw_uid); 386 _exit(1); 387 } 388 } 389 execv(sep->se_server, sep->se_argv); 390 if (sep->se_socktype != SOCK_STREAM) 391 recv(0, buf, sizeof (buf), 0); 392 syslog(LOG_ERR, 393 "cannot execute %s: %m", sep->se_server); 394 _exit(1); 395 } 396 } 397 if (sep->se_socktype == SOCK_STREAM) 398 close(ctrl); 399 } 400 } 401 } 402 403 void 404 reapchild() 405 { 406 int status; 407 int pid; 408 register struct servtab *sep; 409 410 for (;;) { 411 pid = wait3(&status, WNOHANG, (struct rusage *)0); 412 if (pid <= 0) 413 break; 414 if (debug) 415 fprintf(stderr, "%d reaped, status %#x\n", 416 pid, status); 417 for (sep = servtab; sep; sep = sep->se_next) 418 if (sep->se_wait == pid) { 419 if (status) 420 syslog(LOG_WARNING, 421 "%s: exit status 0x%x", 422 sep->se_server, status); 423 if (debug) 424 fprintf(stderr, "restored %s, fd %d\n", 425 sep->se_service, sep->se_fd); 426 FD_SET(sep->se_fd, &allsock); 427 nsock++; 428 sep->se_wait = 1; 429 } 430 } 431 } 432 433 void 434 config() 435 { 436 register struct servtab *sep, *cp, **sepp; 437 struct servtab *getconfigent(), *enter(); 438 struct passwd *pwd; 439 long omask; 440 441 if (!setconfig()) { 442 syslog(LOG_ERR, "%s: %m", CONFIG); 443 return; 444 } 445 for (sep = servtab; sep; sep = sep->se_next) 446 sep->se_checked = 0; 447 while (cp = getconfigent()) { 448 if ((pwd = getpwnam(cp->se_user)) == NULL) { 449 syslog(LOG_ERR, 450 "%s/%s: No such user '%s', service ignored", 451 cp->se_service, cp->se_proto, cp->se_user); 452 continue; 453 } 454 for (sep = servtab; sep; sep = sep->se_next) 455 if (strcmp(sep->se_service, cp->se_service) == 0 && 456 strcmp(sep->se_proto, cp->se_proto) == 0) 457 break; 458 if (sep != 0) { 459 int i; 460 461 omask = sigblock(SIGBLOCK); 462 /* 463 * sep->se_wait may be holding the pid of a daemon 464 * that we're waiting for. If so, don't overwrite 465 * it unless the config file explicitly says don't 466 * wait. 467 */ 468 if (cp->se_bi == 0 && 469 (sep->se_wait == 1 || cp->se_wait == 0)) 470 sep->se_wait = cp->se_wait; 471 #define SWAP(a, b) { char *c = a; a = b; b = c; } 472 if (cp->se_user) 473 SWAP(sep->se_user, cp->se_user); 474 if (cp->se_server) 475 SWAP(sep->se_server, cp->se_server); 476 for (i = 0; i < MAXARGV; i++) 477 SWAP(sep->se_argv[i], cp->se_argv[i]); 478 sigsetmask(omask); 479 freeconfig(cp); 480 if (debug) 481 print_service("REDO", sep); 482 } else { 483 sep = enter(cp); 484 if (debug) 485 print_service("ADD ", sep); 486 } 487 sep->se_checked = 1; 488 if (ISMUX(sep)) { 489 sep->se_fd = -1; 490 continue; 491 } 492 sp = getservbyname(sep->se_service, sep->se_proto); 493 if (sp == 0) { 494 syslog(LOG_ERR, "%s/%s: unknown service", 495 sep->se_service, sep->se_proto); 496 sep->se_checked = 0; 497 continue; 498 } 499 if (sp->s_port != sep->se_ctrladdr.sin_port) { 500 sep->se_ctrladdr.sin_port = sp->s_port; 501 if (sep->se_fd >= 0) 502 close_sep(sep); 503 } 504 if (sep->se_fd == -1) 505 setup(sep); 506 } 507 endconfig(); 508 /* 509 * Purge anything not looked at above. 510 */ 511 omask = sigblock(SIGBLOCK); 512 sepp = &servtab; 513 while (sep = *sepp) { 514 if (sep->se_checked) { 515 sepp = &sep->se_next; 516 continue; 517 } 518 *sepp = sep->se_next; 519 if (sep->se_fd >= 0) 520 close_sep(sep); 521 if (debug) 522 print_service("FREE", sep); 523 freeconfig(sep); 524 free((char *)sep); 525 } 526 (void) sigsetmask(omask); 527 } 528 529 void 530 retry() 531 { 532 register struct servtab *sep; 533 534 timingout = 0; 535 for (sep = servtab; sep; sep = sep->se_next) 536 if (sep->se_fd == -1) 537 setup(sep); 538 } 539 540 setup(sep) 541 register struct servtab *sep; 542 { 543 int on = 1; 544 545 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 546 if (debug) 547 fprintf(stderr, "socket failed on %s/%s: %s\n", 548 sep->se_service, sep->se_proto, 549 strerror(errno)); 550 syslog(LOG_ERR, "%s/%s: socket: %m", 551 sep->se_service, sep->se_proto); 552 return; 553 } 554 #define turnon(fd, opt) \ 555 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 556 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 557 turnon(sep->se_fd, SO_DEBUG) < 0) 558 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 559 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 560 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 561 #undef turnon 562 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 563 sizeof (sep->se_ctrladdr)) < 0) { 564 if (debug) 565 fprintf(stderr, "bind failed on %s/%s: %s\n", 566 sep->se_service, sep->se_proto, 567 strerror(errno)); 568 syslog(LOG_ERR, "%s/%s: bind: %m", 569 sep->se_service, sep->se_proto); 570 (void) close(sep->se_fd); 571 sep->se_fd = -1; 572 if (!timingout) { 573 timingout = 1; 574 alarm(RETRYTIME); 575 } 576 return; 577 } 578 if (sep->se_socktype == SOCK_STREAM) 579 listen(sep->se_fd, 10); 580 FD_SET(sep->se_fd, &allsock); 581 nsock++; 582 if (sep->se_fd > maxsock) 583 maxsock = sep->se_fd; 584 if (debug) { 585 fprintf(stderr, "registered %s on %d\n", 586 sep->se_server, sep->se_fd); 587 } 588 } 589 590 /* 591 * Finish with a service and its socket. 592 */ 593 close_sep(sep) 594 register struct servtab *sep; 595 { 596 if (sep->se_fd >= 0) { 597 nsock--; 598 FD_CLR(sep->se_fd, &allsock); 599 (void) close(sep->se_fd); 600 sep->se_fd = -1; 601 } 602 sep->se_count = 0; 603 /* 604 * Don't keep the pid of this running deamon: when reapchild() 605 * reaps this pid, it would erroneously increment nsock. 606 */ 607 if (sep->se_wait > 1) 608 sep->se_wait = 1; 609 } 610 611 struct servtab * 612 enter(cp) 613 struct servtab *cp; 614 { 615 register struct servtab *sep; 616 long omask; 617 618 sep = (struct servtab *)malloc(sizeof (*sep)); 619 if (sep == (struct servtab *)0) { 620 syslog(LOG_ERR, "Out of memory."); 621 exit(-1); 622 } 623 *sep = *cp; 624 sep->se_fd = -1; 625 omask = sigblock(SIGBLOCK); 626 sep->se_next = servtab; 627 servtab = sep; 628 sigsetmask(omask); 629 return (sep); 630 } 631 632 FILE *fconfig = NULL; 633 struct servtab serv; 634 char line[256]; 635 char *sskip(), *skip(), *nextline(); 636 637 setconfig() 638 { 639 640 if (fconfig != NULL) { 641 fseek(fconfig, 0L, SEEK_SET); 642 return (1); 643 } 644 fconfig = fopen(CONFIG, "r"); 645 return (fconfig != NULL); 646 } 647 648 endconfig() 649 { 650 if (fconfig) { 651 (void) fclose(fconfig); 652 fconfig = NULL; 653 } 654 } 655 656 struct servtab * 657 getconfigent() 658 { 659 register struct servtab *sep = &serv; 660 int argc; 661 char *cp, *arg, *newstr(); 662 static char TCPMUX_TOKEN[] = "tcpmux/"; 663 #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 664 665 more: 666 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 667 ; 668 if (cp == NULL) 669 return ((struct servtab *)0); 670 /* 671 * clear the static buffer, since some fields (se_ctrladdr, 672 * for example) don't get initialized here. 673 */ 674 bzero((caddr_t)sep, sizeof *sep); 675 arg = skip(&cp); 676 if (cp == NULL) { 677 /* got an empty line containing just blanks/tabs. */ 678 goto more; 679 } 680 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 681 char *c = arg + MUX_LEN; 682 if (*c == '+') { 683 sep->se_type = MUXPLUS_TYPE; 684 c++; 685 } else 686 sep->se_type = MUX_TYPE; 687 sep->se_service = newstr(c); 688 } else { 689 sep->se_service = newstr(arg); 690 sep->se_type = NORM_TYPE; 691 } 692 arg = sskip(&cp); 693 if (strcmp(arg, "stream") == 0) 694 sep->se_socktype = SOCK_STREAM; 695 else if (strcmp(arg, "dgram") == 0) 696 sep->se_socktype = SOCK_DGRAM; 697 else if (strcmp(arg, "rdm") == 0) 698 sep->se_socktype = SOCK_RDM; 699 else if (strcmp(arg, "seqpacket") == 0) 700 sep->se_socktype = SOCK_SEQPACKET; 701 else if (strcmp(arg, "raw") == 0) 702 sep->se_socktype = SOCK_RAW; 703 else 704 sep->se_socktype = -1; 705 sep->se_proto = newstr(sskip(&cp)); 706 arg = sskip(&cp); 707 sep->se_wait = strcmp(arg, "wait") == 0; 708 if (ISMUX(sep)) { 709 /* 710 * Silently enforce "nowait" for TCPMUX services since 711 * they don't have an assigned port to listen on. 712 */ 713 sep->se_wait = 0; 714 715 if (strcmp(sep->se_proto, "tcp")) { 716 syslog(LOG_ERR, 717 "%s: bad protocol for tcpmux service %s", 718 CONFIG, sep->se_service); 719 goto more; 720 } 721 if (sep->se_socktype != SOCK_STREAM) { 722 syslog(LOG_ERR, 723 "%s: bad socket type for tcpmux service %s", 724 CONFIG, sep->se_service); 725 goto more; 726 } 727 } 728 sep->se_user = newstr(sskip(&cp)); 729 sep->se_server = newstr(sskip(&cp)); 730 if (strcmp(sep->se_server, "internal") == 0) { 731 register struct biltin *bi; 732 733 for (bi = biltins; bi->bi_service; bi++) 734 if (bi->bi_socktype == sep->se_socktype && 735 strcmp(bi->bi_service, sep->se_service) == 0) 736 break; 737 if (bi->bi_service == 0) { 738 syslog(LOG_ERR, "internal service %s unknown", 739 sep->se_service); 740 goto more; 741 } 742 sep->se_bi = bi; 743 sep->se_wait = bi->bi_wait; 744 } else 745 sep->se_bi = NULL; 746 argc = 0; 747 for (arg = skip(&cp); cp; arg = skip(&cp)) 748 if (argc < MAXARGV) 749 sep->se_argv[argc++] = newstr(arg); 750 while (argc <= MAXARGV) 751 sep->se_argv[argc++] = NULL; 752 return (sep); 753 } 754 755 freeconfig(cp) 756 register struct servtab *cp; 757 { 758 int i; 759 760 if (cp->se_service) 761 free(cp->se_service); 762 if (cp->se_proto) 763 free(cp->se_proto); 764 if (cp->se_user) 765 free(cp->se_user); 766 if (cp->se_server) 767 free(cp->se_server); 768 for (i = 0; i < MAXARGV; i++) 769 if (cp->se_argv[i]) 770 free(cp->se_argv[i]); 771 } 772 773 774 /* 775 * Safe skip - if skip returns null, log a syntax error in the 776 * configuration file and exit. 777 */ 778 char * 779 sskip(cpp) 780 char **cpp; 781 { 782 register char *cp; 783 784 cp = skip(cpp); 785 if (cp == NULL) { 786 syslog(LOG_ERR, "%s: syntax error", CONFIG); 787 exit(-1); 788 } 789 return (cp); 790 } 791 792 char * 793 skip(cpp) 794 char **cpp; 795 { 796 register char *cp = *cpp; 797 char *start; 798 799 again: 800 while (*cp == ' ' || *cp == '\t') 801 cp++; 802 if (*cp == '\0') { 803 int c; 804 805 c = getc(fconfig); 806 (void) ungetc(c, fconfig); 807 if (c == ' ' || c == '\t') 808 if (cp = nextline(fconfig)) 809 goto again; 810 *cpp = (char *)0; 811 return ((char *)0); 812 } 813 start = cp; 814 while (*cp && *cp != ' ' && *cp != '\t') 815 cp++; 816 if (*cp != '\0') 817 *cp++ = '\0'; 818 *cpp = cp; 819 return (start); 820 } 821 822 char * 823 nextline(fd) 824 FILE *fd; 825 { 826 char *cp; 827 828 if (fgets(line, sizeof (line), fd) == NULL) 829 return ((char *)0); 830 cp = index(line, '\n'); 831 if (cp) 832 *cp = '\0'; 833 return (line); 834 } 835 836 char * 837 newstr(cp) 838 char *cp; 839 { 840 if (cp = strdup(cp ? cp : "")) 841 return(cp); 842 syslog(LOG_ERR, "strdup: %m"); 843 exit(-1); 844 } 845 846 setproctitle(a, s) 847 char *a; 848 int s; 849 { 850 int size; 851 register char *cp; 852 struct sockaddr_in sin; 853 char buf[80]; 854 855 cp = Argv[0]; 856 size = sizeof(sin); 857 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 858 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 859 else 860 (void) sprintf(buf, "-%s", a); 861 strncpy(cp, buf, LastArg - cp); 862 cp += strlen(cp); 863 while (cp < LastArg) 864 *cp++ = ' '; 865 } 866 867 /* 868 * Internet services provided internally by inetd: 869 */ 870 #define BUFSIZE 8192 871 872 /* ARGSUSED */ 873 echo_stream(s, sep) /* Echo service -- echo data back */ 874 int s; 875 struct servtab *sep; 876 { 877 char buffer[BUFSIZE]; 878 int i; 879 880 setproctitle(sep->se_service, s); 881 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 882 write(s, buffer, i) > 0) 883 ; 884 exit(0); 885 } 886 887 /* ARGSUSED */ 888 echo_dg(s, sep) /* Echo service -- echo data back */ 889 int s; 890 struct servtab *sep; 891 { 892 char buffer[BUFSIZE]; 893 int i, size; 894 struct sockaddr sa; 895 896 size = sizeof(sa); 897 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 898 return; 899 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 900 } 901 902 /* ARGSUSED */ 903 discard_stream(s, sep) /* Discard service -- ignore data */ 904 int s; 905 struct servtab *sep; 906 { 907 int ret; 908 char buffer[BUFSIZE]; 909 910 setproctitle(sep->se_service, s); 911 while (1) { 912 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 913 ; 914 if (ret == 0 || errno != EINTR) 915 break; 916 } 917 exit(0); 918 } 919 920 /* ARGSUSED */ 921 discard_dg(s, sep) /* Discard service -- ignore data */ 922 int s; 923 struct servtab *sep; 924 { 925 char buffer[BUFSIZE]; 926 927 (void) read(s, buffer, sizeof(buffer)); 928 } 929 930 #include <ctype.h> 931 #define LINESIZ 72 932 char ring[128]; 933 char *endring; 934 935 initring() 936 { 937 register int i; 938 939 endring = ring; 940 941 for (i = 0; i <= 128; ++i) 942 if (isprint(i)) 943 *endring++ = i; 944 } 945 946 /* ARGSUSED */ 947 chargen_stream(s, sep) /* Character generator */ 948 int s; 949 struct servtab *sep; 950 { 951 register char *rs; 952 int len; 953 char text[LINESIZ+2]; 954 955 setproctitle(sep->se_service, s); 956 957 if (!endring) { 958 initring(); 959 rs = ring; 960 } 961 962 text[LINESIZ] = '\r'; 963 text[LINESIZ + 1] = '\n'; 964 for (rs = ring;;) { 965 if ((len = endring - rs) >= LINESIZ) 966 bcopy(rs, text, LINESIZ); 967 else { 968 bcopy(rs, text, len); 969 bcopy(ring, text + len, LINESIZ - len); 970 } 971 if (++rs == endring) 972 rs = ring; 973 if (write(s, text, sizeof(text)) != sizeof(text)) 974 break; 975 } 976 exit(0); 977 } 978 979 /* ARGSUSED */ 980 chargen_dg(s, sep) /* Character generator */ 981 int s; 982 struct servtab *sep; 983 { 984 struct sockaddr sa; 985 static char *rs; 986 int len, size; 987 char text[LINESIZ+2]; 988 989 if (endring == 0) { 990 initring(); 991 rs = ring; 992 } 993 994 size = sizeof(sa); 995 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 996 return; 997 998 if ((len = endring - rs) >= LINESIZ) 999 bcopy(rs, text, LINESIZ); 1000 else { 1001 bcopy(rs, text, len); 1002 bcopy(ring, text + len, LINESIZ - len); 1003 } 1004 if (++rs == endring) 1005 rs = ring; 1006 text[LINESIZ] = '\r'; 1007 text[LINESIZ + 1] = '\n'; 1008 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 1009 } 1010 1011 /* 1012 * Return a machine readable date and time, in the form of the 1013 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1014 * returns the number of seconds since midnight, Jan 1, 1970, 1015 * we must add 2208988800 seconds to this figure to make up for 1016 * some seventy years Bell Labs was asleep. 1017 */ 1018 1019 long 1020 machtime() 1021 { 1022 struct timeval tv; 1023 1024 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1025 if (debug) 1026 fprintf(stderr, "Unable to get time of day\n"); 1027 return (0L); 1028 } 1029 #define OFFSET ((u_long)25567 * 24*60*60) 1030 return (htonl((long)(tv.tv_sec + OFFSET))); 1031 #undef OFFSET 1032 } 1033 1034 /* ARGSUSED */ 1035 machtime_stream(s, sep) 1036 int s; 1037 struct servtab *sep; 1038 { 1039 long result; 1040 1041 result = machtime(); 1042 (void) write(s, (char *) &result, sizeof(result)); 1043 } 1044 1045 /* ARGSUSED */ 1046 machtime_dg(s, sep) 1047 int s; 1048 struct servtab *sep; 1049 { 1050 long result; 1051 struct sockaddr sa; 1052 int size; 1053 1054 size = sizeof(sa); 1055 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 1056 return; 1057 result = machtime(); 1058 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 1059 } 1060 1061 /* ARGSUSED */ 1062 daytime_stream(s, sep) /* Return human-readable time of day */ 1063 int s; 1064 struct servtab *sep; 1065 { 1066 char buffer[256]; 1067 time_t clock; 1068 1069 clock = time((time_t *) 0); 1070 1071 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1072 (void) write(s, buffer, strlen(buffer)); 1073 } 1074 1075 /* ARGSUSED */ 1076 daytime_dg(s, sep) /* Return human-readable time of day */ 1077 int s; 1078 struct servtab *sep; 1079 { 1080 char buffer[256]; 1081 time_t clock; 1082 struct sockaddr sa; 1083 int size; 1084 1085 clock = time((time_t *) 0); 1086 1087 size = sizeof(sa); 1088 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 1089 return; 1090 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1091 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 1092 } 1093 1094 /* 1095 * print_service: 1096 * Dump relevant information to stderr 1097 */ 1098 print_service(action, sep) 1099 char *action; 1100 struct servtab *sep; 1101 { 1102 fprintf(stderr, 1103 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 1104 action, sep->se_service, sep->se_proto, 1105 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 1106 } 1107 1108 /* 1109 * Based on TCPMUX.C by Mark K. Lottor November 1988 1110 * sri-nic::ps:<mkl>tcpmux.c 1111 */ 1112 1113 1114 static int /* # of characters upto \r,\n or \0 */ 1115 getline(fd, buf, len) 1116 int fd; 1117 char *buf; 1118 int len; 1119 { 1120 int count = 0, n; 1121 1122 do { 1123 n = read(fd, buf, len-count); 1124 if (n == 0) 1125 return count; 1126 if (n < 0) 1127 return (-1); 1128 while (--n >= 0) { 1129 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1130 return count; 1131 count++; 1132 buf++; 1133 } 1134 } while (count < len); 1135 return (count); 1136 } 1137 1138 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1139 1140 #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1141 1142 struct servtab * 1143 tcpmux(s) 1144 int s; 1145 { 1146 register struct servtab *sep; 1147 char service[MAX_SERV_LEN+1]; 1148 int len; 1149 1150 /* Get requested service name */ 1151 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1152 strwrite(s, "-Error reading service name\r\n"); 1153 return(NULL); 1154 } 1155 service[len] = '\0'; 1156 1157 if (debug) 1158 fprintf(stderr, "tcpmux: someone wants %s\n", service); 1159 1160 /* 1161 * Help is a required command, and lists available services, 1162 * one per line. 1163 */ 1164 if (!strcasecmp(service,"help")) { 1165 for (sep = servtab; sep; sep = sep->se_next) { 1166 if (!ISMUX(sep)) 1167 continue; 1168 (void) write(s, sep->se_service, strlen(sep->se_service)); 1169 strwrite(s, "\r\n"); 1170 } 1171 return(NULL); 1172 } 1173 1174 /* Try matching a service in inetd.conf with the request */ 1175 for (sep = servtab; sep; sep = sep->se_next) { 1176 if (!ISMUX(sep)) 1177 continue; 1178 if (!strcasecmp(service,sep->se_service)) { 1179 if (ISMUXPLUS(sep)) { 1180 strwrite(s, "+Go\r\n"); 1181 } 1182 return(sep); 1183 } 1184 } 1185 strwrite(s, "-Service not available\r\n"); 1186 return(NULL); 1187 } 1188