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