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