1 /* 2 * Copyright (c) 1983, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1983, 1991, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)inetd.c 8.1 (Berkeley) 06/06/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_family = AF_INET; 501 sep->se_ctrladdr.sin_port = sp->s_port; 502 if (sep->se_fd >= 0) 503 close_sep(sep); 504 } 505 if (sep->se_fd == -1) 506 setup(sep); 507 } 508 endconfig(); 509 /* 510 * Purge anything not looked at above. 511 */ 512 omask = sigblock(SIGBLOCK); 513 sepp = &servtab; 514 while (sep = *sepp) { 515 if (sep->se_checked) { 516 sepp = &sep->se_next; 517 continue; 518 } 519 *sepp = sep->se_next; 520 if (sep->se_fd >= 0) 521 close_sep(sep); 522 if (debug) 523 print_service("FREE", sep); 524 freeconfig(sep); 525 free((char *)sep); 526 } 527 (void) sigsetmask(omask); 528 } 529 530 void 531 retry() 532 { 533 register struct servtab *sep; 534 535 timingout = 0; 536 for (sep = servtab; sep; sep = sep->se_next) 537 if (sep->se_fd == -1) 538 setup(sep); 539 } 540 541 setup(sep) 542 register struct servtab *sep; 543 { 544 int on = 1; 545 546 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { 547 if (debug) 548 fprintf(stderr, "socket failed on %s/%s: %s\n", 549 sep->se_service, sep->se_proto, 550 strerror(errno)); 551 syslog(LOG_ERR, "%s/%s: socket: %m", 552 sep->se_service, sep->se_proto); 553 return; 554 } 555 #define turnon(fd, opt) \ 556 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) 557 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && 558 turnon(sep->se_fd, SO_DEBUG) < 0) 559 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 560 if (turnon(sep->se_fd, SO_REUSEADDR) < 0) 561 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); 562 #undef turnon 563 if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr, 564 sizeof (sep->se_ctrladdr)) < 0) { 565 if (debug) 566 fprintf(stderr, "bind failed on %s/%s: %s\n", 567 sep->se_service, sep->se_proto, 568 strerror(errno)); 569 syslog(LOG_ERR, "%s/%s: bind: %m", 570 sep->se_service, sep->se_proto); 571 (void) close(sep->se_fd); 572 sep->se_fd = -1; 573 if (!timingout) { 574 timingout = 1; 575 alarm(RETRYTIME); 576 } 577 return; 578 } 579 if (sep->se_socktype == SOCK_STREAM) 580 listen(sep->se_fd, 10); 581 FD_SET(sep->se_fd, &allsock); 582 nsock++; 583 if (sep->se_fd > maxsock) 584 maxsock = sep->se_fd; 585 if (debug) { 586 fprintf(stderr, "registered %s on %d\n", 587 sep->se_server, sep->se_fd); 588 } 589 } 590 591 /* 592 * Finish with a service and its socket. 593 */ 594 close_sep(sep) 595 register struct servtab *sep; 596 { 597 if (sep->se_fd >= 0) { 598 nsock--; 599 FD_CLR(sep->se_fd, &allsock); 600 (void) close(sep->se_fd); 601 sep->se_fd = -1; 602 } 603 sep->se_count = 0; 604 /* 605 * Don't keep the pid of this running deamon: when reapchild() 606 * reaps this pid, it would erroneously increment nsock. 607 */ 608 if (sep->se_wait > 1) 609 sep->se_wait = 1; 610 } 611 612 struct servtab * 613 enter(cp) 614 struct servtab *cp; 615 { 616 register struct servtab *sep; 617 long omask; 618 619 sep = (struct servtab *)malloc(sizeof (*sep)); 620 if (sep == (struct servtab *)0) { 621 syslog(LOG_ERR, "Out of memory."); 622 exit(-1); 623 } 624 *sep = *cp; 625 sep->se_fd = -1; 626 omask = sigblock(SIGBLOCK); 627 sep->se_next = servtab; 628 servtab = sep; 629 sigsetmask(omask); 630 return (sep); 631 } 632 633 FILE *fconfig = NULL; 634 struct servtab serv; 635 char line[256]; 636 char *sskip(), *skip(), *nextline(); 637 638 setconfig() 639 { 640 641 if (fconfig != NULL) { 642 fseek(fconfig, 0L, SEEK_SET); 643 return (1); 644 } 645 fconfig = fopen(CONFIG, "r"); 646 return (fconfig != NULL); 647 } 648 649 endconfig() 650 { 651 if (fconfig) { 652 (void) fclose(fconfig); 653 fconfig = NULL; 654 } 655 } 656 657 struct servtab * 658 getconfigent() 659 { 660 register struct servtab *sep = &serv; 661 int argc; 662 char *cp, *arg, *newstr(); 663 static char TCPMUX_TOKEN[] = "tcpmux/"; 664 #define MUX_LEN (sizeof(TCPMUX_TOKEN)-1) 665 666 more: 667 while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) 668 ; 669 if (cp == NULL) 670 return ((struct servtab *)0); 671 /* 672 * clear the static buffer, since some fields (se_ctrladdr, 673 * for example) don't get initialized here. 674 */ 675 bzero((caddr_t)sep, sizeof *sep); 676 arg = skip(&cp); 677 if (cp == NULL) { 678 /* got an empty line containing just blanks/tabs. */ 679 goto more; 680 } 681 if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) { 682 char *c = arg + MUX_LEN; 683 if (*c == '+') { 684 sep->se_type = MUXPLUS_TYPE; 685 c++; 686 } else 687 sep->se_type = MUX_TYPE; 688 sep->se_service = newstr(c); 689 } else { 690 sep->se_service = newstr(arg); 691 sep->se_type = NORM_TYPE; 692 } 693 arg = sskip(&cp); 694 if (strcmp(arg, "stream") == 0) 695 sep->se_socktype = SOCK_STREAM; 696 else if (strcmp(arg, "dgram") == 0) 697 sep->se_socktype = SOCK_DGRAM; 698 else if (strcmp(arg, "rdm") == 0) 699 sep->se_socktype = SOCK_RDM; 700 else if (strcmp(arg, "seqpacket") == 0) 701 sep->se_socktype = SOCK_SEQPACKET; 702 else if (strcmp(arg, "raw") == 0) 703 sep->se_socktype = SOCK_RAW; 704 else 705 sep->se_socktype = -1; 706 sep->se_proto = newstr(sskip(&cp)); 707 arg = sskip(&cp); 708 sep->se_wait = strcmp(arg, "wait") == 0; 709 if (ISMUX(sep)) { 710 /* 711 * Silently enforce "nowait" for TCPMUX services since 712 * they don't have an assigned port to listen on. 713 */ 714 sep->se_wait = 0; 715 716 if (strcmp(sep->se_proto, "tcp")) { 717 syslog(LOG_ERR, 718 "%s: bad protocol for tcpmux service %s", 719 CONFIG, sep->se_service); 720 goto more; 721 } 722 if (sep->se_socktype != SOCK_STREAM) { 723 syslog(LOG_ERR, 724 "%s: bad socket type for tcpmux service %s", 725 CONFIG, sep->se_service); 726 goto more; 727 } 728 } 729 sep->se_user = newstr(sskip(&cp)); 730 sep->se_server = newstr(sskip(&cp)); 731 if (strcmp(sep->se_server, "internal") == 0) { 732 register struct biltin *bi; 733 734 for (bi = biltins; bi->bi_service; bi++) 735 if (bi->bi_socktype == sep->se_socktype && 736 strcmp(bi->bi_service, sep->se_service) == 0) 737 break; 738 if (bi->bi_service == 0) { 739 syslog(LOG_ERR, "internal service %s unknown", 740 sep->se_service); 741 goto more; 742 } 743 sep->se_bi = bi; 744 sep->se_wait = bi->bi_wait; 745 } else 746 sep->se_bi = NULL; 747 argc = 0; 748 for (arg = skip(&cp); cp; arg = skip(&cp)) 749 if (argc < MAXARGV) 750 sep->se_argv[argc++] = newstr(arg); 751 while (argc <= MAXARGV) 752 sep->se_argv[argc++] = NULL; 753 return (sep); 754 } 755 756 freeconfig(cp) 757 register struct servtab *cp; 758 { 759 int i; 760 761 if (cp->se_service) 762 free(cp->se_service); 763 if (cp->se_proto) 764 free(cp->se_proto); 765 if (cp->se_user) 766 free(cp->se_user); 767 if (cp->se_server) 768 free(cp->se_server); 769 for (i = 0; i < MAXARGV; i++) 770 if (cp->se_argv[i]) 771 free(cp->se_argv[i]); 772 } 773 774 775 /* 776 * Safe skip - if skip returns null, log a syntax error in the 777 * configuration file and exit. 778 */ 779 char * 780 sskip(cpp) 781 char **cpp; 782 { 783 register char *cp; 784 785 cp = skip(cpp); 786 if (cp == NULL) { 787 syslog(LOG_ERR, "%s: syntax error", CONFIG); 788 exit(-1); 789 } 790 return (cp); 791 } 792 793 char * 794 skip(cpp) 795 char **cpp; 796 { 797 register char *cp = *cpp; 798 char *start; 799 800 again: 801 while (*cp == ' ' || *cp == '\t') 802 cp++; 803 if (*cp == '\0') { 804 int c; 805 806 c = getc(fconfig); 807 (void) ungetc(c, fconfig); 808 if (c == ' ' || c == '\t') 809 if (cp = nextline(fconfig)) 810 goto again; 811 *cpp = (char *)0; 812 return ((char *)0); 813 } 814 start = cp; 815 while (*cp && *cp != ' ' && *cp != '\t') 816 cp++; 817 if (*cp != '\0') 818 *cp++ = '\0'; 819 *cpp = cp; 820 return (start); 821 } 822 823 char * 824 nextline(fd) 825 FILE *fd; 826 { 827 char *cp; 828 829 if (fgets(line, sizeof (line), fd) == NULL) 830 return ((char *)0); 831 cp = index(line, '\n'); 832 if (cp) 833 *cp = '\0'; 834 return (line); 835 } 836 837 char * 838 newstr(cp) 839 char *cp; 840 { 841 if (cp = strdup(cp ? cp : "")) 842 return(cp); 843 syslog(LOG_ERR, "strdup: %m"); 844 exit(-1); 845 } 846 847 setproctitle(a, s) 848 char *a; 849 int s; 850 { 851 int size; 852 register char *cp; 853 struct sockaddr_in sin; 854 char buf[80]; 855 856 cp = Argv[0]; 857 size = sizeof(sin); 858 if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) 859 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 860 else 861 (void) sprintf(buf, "-%s", a); 862 strncpy(cp, buf, LastArg - cp); 863 cp += strlen(cp); 864 while (cp < LastArg) 865 *cp++ = ' '; 866 } 867 868 /* 869 * Internet services provided internally by inetd: 870 */ 871 #define BUFSIZE 8192 872 873 /* ARGSUSED */ 874 echo_stream(s, sep) /* Echo service -- echo data back */ 875 int s; 876 struct servtab *sep; 877 { 878 char buffer[BUFSIZE]; 879 int i; 880 881 setproctitle(sep->se_service, s); 882 while ((i = read(s, buffer, sizeof(buffer))) > 0 && 883 write(s, buffer, i) > 0) 884 ; 885 exit(0); 886 } 887 888 /* ARGSUSED */ 889 echo_dg(s, sep) /* Echo service -- echo data back */ 890 int s; 891 struct servtab *sep; 892 { 893 char buffer[BUFSIZE]; 894 int i, size; 895 struct sockaddr sa; 896 897 size = sizeof(sa); 898 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) 899 return; 900 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); 901 } 902 903 /* ARGSUSED */ 904 discard_stream(s, sep) /* Discard service -- ignore data */ 905 int s; 906 struct servtab *sep; 907 { 908 int ret; 909 char buffer[BUFSIZE]; 910 911 setproctitle(sep->se_service, s); 912 while (1) { 913 while ((ret = read(s, buffer, sizeof(buffer))) > 0) 914 ; 915 if (ret == 0 || errno != EINTR) 916 break; 917 } 918 exit(0); 919 } 920 921 /* ARGSUSED */ 922 discard_dg(s, sep) /* Discard service -- ignore data */ 923 int s; 924 struct servtab *sep; 925 { 926 char buffer[BUFSIZE]; 927 928 (void) read(s, buffer, sizeof(buffer)); 929 } 930 931 #include <ctype.h> 932 #define LINESIZ 72 933 char ring[128]; 934 char *endring; 935 936 initring() 937 { 938 register int i; 939 940 endring = ring; 941 942 for (i = 0; i <= 128; ++i) 943 if (isprint(i)) 944 *endring++ = i; 945 } 946 947 /* ARGSUSED */ 948 chargen_stream(s, sep) /* Character generator */ 949 int s; 950 struct servtab *sep; 951 { 952 register char *rs; 953 int len; 954 char text[LINESIZ+2]; 955 956 setproctitle(sep->se_service, s); 957 958 if (!endring) { 959 initring(); 960 rs = ring; 961 } 962 963 text[LINESIZ] = '\r'; 964 text[LINESIZ + 1] = '\n'; 965 for (rs = ring;;) { 966 if ((len = endring - rs) >= LINESIZ) 967 bcopy(rs, text, LINESIZ); 968 else { 969 bcopy(rs, text, len); 970 bcopy(ring, text + len, LINESIZ - len); 971 } 972 if (++rs == endring) 973 rs = ring; 974 if (write(s, text, sizeof(text)) != sizeof(text)) 975 break; 976 } 977 exit(0); 978 } 979 980 /* ARGSUSED */ 981 chargen_dg(s, sep) /* Character generator */ 982 int s; 983 struct servtab *sep; 984 { 985 struct sockaddr sa; 986 static char *rs; 987 int len, size; 988 char text[LINESIZ+2]; 989 990 if (endring == 0) { 991 initring(); 992 rs = ring; 993 } 994 995 size = sizeof(sa); 996 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) 997 return; 998 999 if ((len = endring - rs) >= LINESIZ) 1000 bcopy(rs, text, LINESIZ); 1001 else { 1002 bcopy(rs, text, len); 1003 bcopy(ring, text + len, LINESIZ - len); 1004 } 1005 if (++rs == endring) 1006 rs = ring; 1007 text[LINESIZ] = '\r'; 1008 text[LINESIZ + 1] = '\n'; 1009 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); 1010 } 1011 1012 /* 1013 * Return a machine readable date and time, in the form of the 1014 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday 1015 * returns the number of seconds since midnight, Jan 1, 1970, 1016 * we must add 2208988800 seconds to this figure to make up for 1017 * some seventy years Bell Labs was asleep. 1018 */ 1019 1020 long 1021 machtime() 1022 { 1023 struct timeval tv; 1024 1025 if (gettimeofday(&tv, (struct timezone *)0) < 0) { 1026 if (debug) 1027 fprintf(stderr, "Unable to get time of day\n"); 1028 return (0L); 1029 } 1030 #define OFFSET ((u_long)25567 * 24*60*60) 1031 return (htonl((long)(tv.tv_sec + OFFSET))); 1032 #undef OFFSET 1033 } 1034 1035 /* ARGSUSED */ 1036 machtime_stream(s, sep) 1037 int s; 1038 struct servtab *sep; 1039 { 1040 long result; 1041 1042 result = machtime(); 1043 (void) write(s, (char *) &result, sizeof(result)); 1044 } 1045 1046 /* ARGSUSED */ 1047 machtime_dg(s, sep) 1048 int s; 1049 struct servtab *sep; 1050 { 1051 long result; 1052 struct sockaddr sa; 1053 int size; 1054 1055 size = sizeof(sa); 1056 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) 1057 return; 1058 result = machtime(); 1059 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); 1060 } 1061 1062 /* ARGSUSED */ 1063 daytime_stream(s, sep) /* Return human-readable time of day */ 1064 int s; 1065 struct servtab *sep; 1066 { 1067 char buffer[256]; 1068 time_t clock; 1069 1070 clock = time((time_t *) 0); 1071 1072 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1073 (void) write(s, buffer, strlen(buffer)); 1074 } 1075 1076 /* ARGSUSED */ 1077 daytime_dg(s, sep) /* Return human-readable time of day */ 1078 int s; 1079 struct servtab *sep; 1080 { 1081 char buffer[256]; 1082 time_t clock; 1083 struct sockaddr sa; 1084 int size; 1085 1086 clock = time((time_t *) 0); 1087 1088 size = sizeof(sa); 1089 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) 1090 return; 1091 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); 1092 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); 1093 } 1094 1095 /* 1096 * print_service: 1097 * Dump relevant information to stderr 1098 */ 1099 print_service(action, sep) 1100 char *action; 1101 struct servtab *sep; 1102 { 1103 fprintf(stderr, 1104 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", 1105 action, sep->se_service, sep->se_proto, 1106 sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); 1107 } 1108 1109 /* 1110 * Based on TCPMUX.C by Mark K. Lottor November 1988 1111 * sri-nic::ps:<mkl>tcpmux.c 1112 */ 1113 1114 1115 static int /* # of characters upto \r,\n or \0 */ 1116 getline(fd, buf, len) 1117 int fd; 1118 char *buf; 1119 int len; 1120 { 1121 int count = 0, n; 1122 1123 do { 1124 n = read(fd, buf, len-count); 1125 if (n == 0) 1126 return count; 1127 if (n < 0) 1128 return (-1); 1129 while (--n >= 0) { 1130 if (*buf == '\r' || *buf == '\n' || *buf == '\0') 1131 return count; 1132 count++; 1133 buf++; 1134 } 1135 } while (count < len); 1136 return (count); 1137 } 1138 1139 #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */ 1140 1141 #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1) 1142 1143 struct servtab * 1144 tcpmux(s) 1145 int s; 1146 { 1147 register struct servtab *sep; 1148 char service[MAX_SERV_LEN+1]; 1149 int len; 1150 1151 /* Get requested service name */ 1152 if ((len = getline(s, service, MAX_SERV_LEN)) < 0) { 1153 strwrite(s, "-Error reading service name\r\n"); 1154 return(NULL); 1155 } 1156 service[len] = '\0'; 1157 1158 if (debug) 1159 fprintf(stderr, "tcpmux: someone wants %s\n", service); 1160 1161 /* 1162 * Help is a required command, and lists available services, 1163 * one per line. 1164 */ 1165 if (!strcasecmp(service,"help")) { 1166 for (sep = servtab; sep; sep = sep->se_next) { 1167 if (!ISMUX(sep)) 1168 continue; 1169 (void) write(s, sep->se_service, strlen(sep->se_service)); 1170 strwrite(s, "\r\n"); 1171 } 1172 return(NULL); 1173 } 1174 1175 /* Try matching a service in inetd.conf with the request */ 1176 for (sep = servtab; sep; sep = sep->se_next) { 1177 if (!ISMUX(sep)) 1178 continue; 1179 if (!strcasecmp(service,sep->se_service)) { 1180 if (ISMUXPLUS(sep)) { 1181 strwrite(s, "+Go\r\n"); 1182 } 1183 return(sep); 1184 } 1185 } 1186 strwrite(s, "-Service not available\r\n"); 1187 return(NULL); 1188 } 1189