|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)inetd.c 5.25 (Berkeley) 6/29/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: * Inetd - Internet super-server ! 32: * ! 33: * This program invokes all internet services as needed. ! 34: * connection-oriented services are invoked each time a ! 35: * connection is made, by creating a process. This process ! 36: * is passed the connection as file descriptor 0 and is ! 37: * expected to do a getpeername to find out the source host ! 38: * and port. ! 39: * ! 40: * Datagram oriented services are invoked when a datagram ! 41: * arrives; a process is created and passed a pending message ! 42: * on file descriptor 0. Datagram servers may either connect ! 43: * to their peer, freeing up the original socket for inetd ! 44: * to receive further messages on, or ``take over the socket'', ! 45: * processing all arriving datagrams and, eventually, timing ! 46: * out. The first type of server is said to be ``multi-threaded''; ! 47: * the second type of server ``single-threaded''. ! 48: * ! 49: * Inetd uses a configuration file which is read at startup ! 50: * and, possibly, at some later time in response to a hangup signal. ! 51: * The configuration file is ``free format'' with fields given in the ! 52: * order shown below. Continuation lines for an entry must being with ! 53: * a space or tab. All fields must be present in each entry. ! 54: * ! 55: * service name must be in /etc/services ! 56: * socket type stream/dgram/raw/rdm/seqpacket ! 57: * protocol must be in /etc/protocols ! 58: * wait/nowait single-threaded/multi-threaded ! 59: * user user to run daemon as ! 60: * server program full path name ! 61: * server program arguments maximum of MAXARGS (20) ! 62: * ! 63: * Comment lines are indicated by a `#' in column 1. ! 64: */ ! 65: #include <sys/param.h> ! 66: #include <sys/stat.h> ! 67: #include <sys/ioctl.h> ! 68: #include <sys/socket.h> ! 69: #include <sys/file.h> ! 70: #include <sys/wait.h> ! 71: #include <sys/time.h> ! 72: #include <sys/resource.h> ! 73: ! 74: #include <netinet/in.h> ! 75: #include <arpa/inet.h> ! 76: ! 77: #include <errno.h> ! 78: #include <signal.h> ! 79: #include <netdb.h> ! 80: #include <syslog.h> ! 81: #include <pwd.h> ! 82: #include <stdio.h> ! 83: #include <string.h> ! 84: #include "pathnames.h" ! 85: ! 86: #define TOOMANY 40 /* don't start more than TOOMANY */ ! 87: #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ ! 88: #define RETRYTIME (60*10) /* retry after bind or server fail */ ! 89: ! 90: #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) ! 91: ! 92: extern int errno; ! 93: ! 94: void config(), reapchild(), retry(); ! 95: char *index(); ! 96: char *malloc(); ! 97: ! 98: int debug = 0; ! 99: int nsock, maxsock; ! 100: fd_set allsock; ! 101: int options; ! 102: int timingout; ! 103: struct servent *sp; ! 104: ! 105: struct servtab { ! 106: char *se_service; /* name of service */ ! 107: int se_socktype; /* type of socket to use */ ! 108: char *se_proto; /* protocol used */ ! 109: short se_wait; /* single threaded server */ ! 110: short se_checked; /* looked at during merge */ ! 111: char *se_user; /* user name to run as */ ! 112: struct biltin *se_bi; /* if built-in, description */ ! 113: char *se_server; /* server program */ ! 114: #define MAXARGV 20 ! 115: char *se_argv[MAXARGV+1]; /* program arguments */ ! 116: int se_fd; /* open descriptor */ ! 117: struct sockaddr_in se_ctrladdr;/* bound address */ ! 118: int se_count; /* number started since se_time */ ! 119: struct timeval se_time; /* start of se_count */ ! 120: struct servtab *se_next; ! 121: } *servtab; ! 122: ! 123: int echo_stream(), discard_stream(), machtime_stream(); ! 124: int daytime_stream(), chargen_stream(); ! 125: int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg(); ! 126: ! 127: struct biltin { ! 128: char *bi_service; /* internally provided service name */ ! 129: int bi_socktype; /* type of socket supported */ ! 130: short bi_fork; /* 1 if should fork before call */ ! 131: short bi_wait; /* 1 if should wait for child */ ! 132: int (*bi_fn)(); /* function which performs it */ ! 133: } biltins[] = { ! 134: /* Echo received data */ ! 135: "echo", SOCK_STREAM, 1, 0, echo_stream, ! 136: "echo", SOCK_DGRAM, 0, 0, echo_dg, ! 137: ! 138: /* Internet /dev/null */ ! 139: "discard", SOCK_STREAM, 1, 0, discard_stream, ! 140: "discard", SOCK_DGRAM, 0, 0, discard_dg, ! 141: ! 142: /* Return 32 bit time since 1970 */ ! 143: "time", SOCK_STREAM, 0, 0, machtime_stream, ! 144: "time", SOCK_DGRAM, 0, 0, machtime_dg, ! 145: ! 146: /* Return human-readable time */ ! 147: "daytime", SOCK_STREAM, 0, 0, daytime_stream, ! 148: "daytime", SOCK_DGRAM, 0, 0, daytime_dg, ! 149: ! 150: /* Familiar character generator */ ! 151: "chargen", SOCK_STREAM, 1, 0, chargen_stream, ! 152: "chargen", SOCK_DGRAM, 0, 0, chargen_dg, ! 153: 0 ! 154: }; ! 155: ! 156: #define NUMINT (sizeof(intab) / sizeof(struct inent)) ! 157: char *CONFIG = _PATH_INETDCONF; ! 158: char **Argv; ! 159: char *LastArg; ! 160: ! 161: main(argc, argv, envp) ! 162: int argc; ! 163: char *argv[], *envp[]; ! 164: { ! 165: extern char *optarg; ! 166: extern int optind; ! 167: register struct servtab *sep; ! 168: register struct passwd *pwd; ! 169: register int tmpint; ! 170: struct sigvec sv; ! 171: int ch, pid, dofork; ! 172: char buf[50]; ! 173: ! 174: Argv = argv; ! 175: if (envp == 0 || *envp == 0) ! 176: envp = argv; ! 177: while (*envp) ! 178: envp++; ! 179: LastArg = envp[-1] + strlen(envp[-1]); ! 180: ! 181: while ((ch = getopt(argc, argv, "d")) != EOF) ! 182: switch(ch) { ! 183: case 'd': ! 184: debug = 1; ! 185: options |= SO_DEBUG; ! 186: break; ! 187: case '?': ! 188: default: ! 189: fprintf(stderr, "usage: inetd [-d]"); ! 190: exit(1); ! 191: } ! 192: argc -= optind; ! 193: argv += optind; ! 194: ! 195: if (argc > 0) ! 196: CONFIG = argv[0]; ! 197: if (debug == 0) ! 198: daemon(0, 0); ! 199: openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON); ! 200: bzero((char *)&sv, sizeof(sv)); ! 201: sv.sv_mask = SIGBLOCK; ! 202: sv.sv_handler = retry; ! 203: sigvec(SIGALRM, &sv, (struct sigvec *)0); ! 204: config(); ! 205: sv.sv_handler = config; ! 206: sigvec(SIGHUP, &sv, (struct sigvec *)0); ! 207: sv.sv_handler = reapchild; ! 208: sigvec(SIGCHLD, &sv, (struct sigvec *)0); ! 209: ! 210: { ! 211: /* space for daemons to overwrite environment for ps */ ! 212: #define DUMMYSIZE 100 ! 213: char dummy[DUMMYSIZE]; ! 214: ! 215: (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1); ! 216: dummy[DUMMYSIZE - 1] = '\0'; ! 217: (void)setenv("inetd_dummy", dummy, 1); ! 218: } ! 219: ! 220: for (;;) { ! 221: int n, ctrl; ! 222: fd_set readable; ! 223: ! 224: if (nsock == 0) { ! 225: (void) sigblock(SIGBLOCK); ! 226: while (nsock == 0) ! 227: sigpause(0L); ! 228: (void) sigsetmask(0L); ! 229: } ! 230: readable = allsock; ! 231: if ((n = select(maxsock + 1, &readable, (fd_set *)0, ! 232: (fd_set *)0, (struct timeval *)0)) <= 0) { ! 233: if (n < 0 && errno != EINTR) ! 234: syslog(LOG_WARNING, "select: %m\n"); ! 235: sleep(1); ! 236: continue; ! 237: } ! 238: for (sep = servtab; n && sep; sep = sep->se_next) ! 239: if (FD_ISSET(sep->se_fd, &readable)) { ! 240: n--; ! 241: if (debug) ! 242: fprintf(stderr, "someone wants %s\n", sep->se_service); ! 243: if (sep->se_socktype == SOCK_STREAM) { ! 244: ctrl = accept(sep->se_fd, (struct sockaddr *)0, ! 245: (int *)0); ! 246: if (debug) ! 247: fprintf(stderr, "accept, ctrl %d\n", ctrl); ! 248: if (ctrl < 0) { ! 249: if (errno == EINTR) ! 250: continue; ! 251: syslog(LOG_WARNING, "accept (for %s): %m", ! 252: sep->se_service); ! 253: continue; ! 254: } ! 255: } else ! 256: ctrl = sep->se_fd; ! 257: (void) sigblock(SIGBLOCK); ! 258: pid = 0; ! 259: dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork); ! 260: if (dofork) { ! 261: if (sep->se_count++ == 0) ! 262: (void)gettimeofday(&sep->se_time, ! 263: (struct timezone *)0); ! 264: else if (sep->se_count >= TOOMANY) { ! 265: struct timeval now; ! 266: ! 267: (void)gettimeofday(&now, (struct timezone *)0); ! 268: if (now.tv_sec - sep->se_time.tv_sec > ! 269: CNT_INTVL) { ! 270: sep->se_time = now; ! 271: sep->se_count = 1; ! 272: } else { ! 273: syslog(LOG_ERR, ! 274: "%s/%s server failing (looping), service terminated\n", ! 275: sep->se_service, sep->se_proto); ! 276: FD_CLR(sep->se_fd, &allsock); ! 277: (void) close(sep->se_fd); ! 278: sep->se_fd = -1; ! 279: sep->se_count = 0; ! 280: nsock--; ! 281: sigsetmask(0L); ! 282: if (!timingout) { ! 283: timingout = 1; ! 284: alarm(RETRYTIME); ! 285: } ! 286: continue; ! 287: } ! 288: } ! 289: pid = fork(); ! 290: } ! 291: if (pid < 0) { ! 292: if (sep->se_socktype == SOCK_STREAM) ! 293: close(ctrl); ! 294: sigsetmask(0L); ! 295: sleep(1); ! 296: continue; ! 297: } ! 298: if (pid && sep->se_wait) { ! 299: sep->se_wait = pid; ! 300: FD_CLR(sep->se_fd, &allsock); ! 301: nsock--; ! 302: } ! 303: sigsetmask(0L); ! 304: if (pid == 0) { ! 305: if (debug && dofork) ! 306: setsid(); ! 307: if (dofork) ! 308: for (tmpint = getdtablesize(); --tmpint > 2; ) ! 309: if (tmpint != ctrl) ! 310: close(tmpint); ! 311: if (sep->se_bi) ! 312: (*sep->se_bi->bi_fn)(ctrl, sep); ! 313: else { ! 314: dup2(ctrl, 0); ! 315: close(ctrl); ! 316: dup2(0, 1); ! 317: dup2(0, 2); ! 318: if ((pwd = getpwnam(sep->se_user)) == NULL) { ! 319: syslog(LOG_ERR, ! 320: "getpwnam: %s: No such user", ! 321: sep->se_user); ! 322: if (sep->se_socktype != SOCK_STREAM) ! 323: recv(0, buf, sizeof (buf), 0); ! 324: _exit(1); ! 325: } ! 326: if (pwd->pw_uid) { ! 327: (void) setgid((gid_t)pwd->pw_gid); ! 328: initgroups(pwd->pw_name, pwd->pw_gid); ! 329: (void) setuid((uid_t)pwd->pw_uid); ! 330: } ! 331: if (debug) ! 332: fprintf(stderr, "%d execl %s\n", ! 333: getpid(), sep->se_server); ! 334: execv(sep->se_server, sep->se_argv); ! 335: if (sep->se_socktype != SOCK_STREAM) ! 336: recv(0, buf, sizeof (buf), 0); ! 337: syslog(LOG_ERR, "execv %s: %m", sep->se_server); ! 338: _exit(1); ! 339: } ! 340: } ! 341: if (sep->se_socktype == SOCK_STREAM) ! 342: close(ctrl); ! 343: } ! 344: } ! 345: } ! 346: ! 347: void ! 348: reapchild() ! 349: { ! 350: union wait status; ! 351: int pid; ! 352: register struct servtab *sep; ! 353: ! 354: for (;;) { ! 355: pid = wait3(&status, WNOHANG, (struct rusage *)0); ! 356: if (pid <= 0) ! 357: break; ! 358: if (debug) ! 359: fprintf(stderr, "%d reaped\n", pid); ! 360: for (sep = servtab; sep; sep = sep->se_next) ! 361: if (sep->se_wait == pid) { ! 362: if (status.w_status) ! 363: syslog(LOG_WARNING, ! 364: "%s: exit status 0x%x", ! 365: sep->se_server, status); ! 366: if (debug) ! 367: fprintf(stderr, "restored %s, fd %d\n", ! 368: sep->se_service, sep->se_fd); ! 369: FD_SET(sep->se_fd, &allsock); ! 370: nsock++; ! 371: sep->se_wait = 1; ! 372: } ! 373: } ! 374: } ! 375: ! 376: void ! 377: config() ! 378: { ! 379: register struct servtab *sep, *cp, **sepp; ! 380: struct servtab *getconfigent(), *enter(); ! 381: long omask; ! 382: ! 383: if (!setconfig()) { ! 384: syslog(LOG_ERR, "%s: %m", CONFIG); ! 385: return; ! 386: } ! 387: for (sep = servtab; sep; sep = sep->se_next) ! 388: sep->se_checked = 0; ! 389: while (cp = getconfigent()) { ! 390: for (sep = servtab; sep; sep = sep->se_next) ! 391: if (strcmp(sep->se_service, cp->se_service) == 0 && ! 392: strcmp(sep->se_proto, cp->se_proto) == 0) ! 393: break; ! 394: if (sep != 0) { ! 395: int i; ! 396: ! 397: omask = sigblock(SIGBLOCK); ! 398: /* ! 399: * sep->se_wait may be holding the pid of a daemon ! 400: * that we're waiting for. If so, don't overwrite ! 401: * it unless the config file explicitly says don't ! 402: * wait. ! 403: */ ! 404: if (cp->se_bi == 0 && ! 405: (sep->se_wait == 1 || cp->se_wait == 0)) ! 406: sep->se_wait = cp->se_wait; ! 407: #define SWAP(a, b) { char *c = a; a = b; b = c; } ! 408: if (cp->se_user) ! 409: SWAP(sep->se_user, cp->se_user); ! 410: if (cp->se_server) ! 411: SWAP(sep->se_server, cp->se_server); ! 412: for (i = 0; i < MAXARGV; i++) ! 413: SWAP(sep->se_argv[i], cp->se_argv[i]); ! 414: sigsetmask(omask); ! 415: freeconfig(cp); ! 416: if (debug) ! 417: print_service("REDO", sep); ! 418: } else { ! 419: sep = enter(cp); ! 420: if (debug) ! 421: print_service("ADD ", sep); ! 422: } ! 423: sep->se_checked = 1; ! 424: sp = getservbyname(sep->se_service, sep->se_proto); ! 425: if (sp == 0) { ! 426: syslog(LOG_ERR, "%s/%s: unknown service", ! 427: sep->se_service, sep->se_proto); ! 428: continue; ! 429: } ! 430: if (sp->s_port != sep->se_ctrladdr.sin_port) { ! 431: sep->se_ctrladdr.sin_port = sp->s_port; ! 432: if (sep->se_fd != -1) ! 433: (void) close(sep->se_fd); ! 434: sep->se_fd = -1; ! 435: } ! 436: if (sep->se_fd == -1) ! 437: setup(sep); ! 438: } ! 439: endconfig(); ! 440: /* ! 441: * Purge anything not looked at above. ! 442: */ ! 443: omask = sigblock(SIGBLOCK); ! 444: sepp = &servtab; ! 445: while (sep = *sepp) { ! 446: if (sep->se_checked) { ! 447: sepp = &sep->se_next; ! 448: continue; ! 449: } ! 450: *sepp = sep->se_next; ! 451: if (sep->se_fd != -1) { ! 452: FD_CLR(sep->se_fd, &allsock); ! 453: nsock--; ! 454: (void) close(sep->se_fd); ! 455: } ! 456: if (debug) ! 457: print_service("FREE", sep); ! 458: freeconfig(sep); ! 459: free((char *)sep); ! 460: } ! 461: (void) sigsetmask(omask); ! 462: } ! 463: ! 464: void ! 465: retry() ! 466: { ! 467: register struct servtab *sep; ! 468: ! 469: timingout = 0; ! 470: for (sep = servtab; sep; sep = sep->se_next) ! 471: if (sep->se_fd == -1) ! 472: setup(sep); ! 473: } ! 474: ! 475: setup(sep) ! 476: register struct servtab *sep; ! 477: { ! 478: int on = 1; ! 479: ! 480: if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) { ! 481: syslog(LOG_ERR, "%s/%s: socket: %m", ! 482: sep->se_service, sep->se_proto); ! 483: return; ! 484: } ! 485: #define turnon(fd, opt) \ ! 486: setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) ! 487: if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) && ! 488: turnon(sep->se_fd, SO_DEBUG) < 0) ! 489: syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); ! 490: if (turnon(sep->se_fd, SO_REUSEADDR) < 0) ! 491: syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); ! 492: #undef turnon ! 493: if (bind(sep->se_fd, &sep->se_ctrladdr, ! 494: sizeof (sep->se_ctrladdr)) < 0) { ! 495: syslog(LOG_ERR, "%s/%s: bind: %m", ! 496: sep->se_service, sep->se_proto); ! 497: (void) close(sep->se_fd); ! 498: sep->se_fd = -1; ! 499: if (!timingout) { ! 500: timingout = 1; ! 501: alarm(RETRYTIME); ! 502: } ! 503: return; ! 504: } ! 505: if (sep->se_socktype == SOCK_STREAM) ! 506: listen(sep->se_fd, 10); ! 507: FD_SET(sep->se_fd, &allsock); ! 508: nsock++; ! 509: if (sep->se_fd > maxsock) ! 510: maxsock = sep->se_fd; ! 511: } ! 512: ! 513: struct servtab * ! 514: enter(cp) ! 515: struct servtab *cp; ! 516: { ! 517: register struct servtab *sep; ! 518: long omask; ! 519: ! 520: sep = (struct servtab *)malloc(sizeof (*sep)); ! 521: if (sep == (struct servtab *)0) { ! 522: syslog(LOG_ERR, "Out of memory."); ! 523: exit(-1); ! 524: } ! 525: *sep = *cp; ! 526: sep->se_fd = -1; ! 527: omask = sigblock(SIGBLOCK); ! 528: sep->se_next = servtab; ! 529: servtab = sep; ! 530: sigsetmask(omask); ! 531: return (sep); ! 532: } ! 533: ! 534: FILE *fconfig = NULL; ! 535: struct servtab serv; ! 536: char line[256]; ! 537: char *skip(), *nextline(); ! 538: ! 539: setconfig() ! 540: { ! 541: ! 542: if (fconfig != NULL) { ! 543: fseek(fconfig, 0L, L_SET); ! 544: return (1); ! 545: } ! 546: fconfig = fopen(CONFIG, "r"); ! 547: return (fconfig != NULL); ! 548: } ! 549: ! 550: endconfig() ! 551: { ! 552: if (fconfig) { ! 553: (void) fclose(fconfig); ! 554: fconfig = NULL; ! 555: } ! 556: } ! 557: ! 558: struct servtab * ! 559: getconfigent() ! 560: { ! 561: register struct servtab *sep = &serv; ! 562: int argc; ! 563: char *cp, *arg, *strdup(); ! 564: ! 565: more: ! 566: while ((cp = nextline(fconfig)) && *cp == '#') ! 567: ; ! 568: if (cp == NULL) ! 569: return ((struct servtab *)0); ! 570: sep->se_service = strdup(skip(&cp)); ! 571: arg = skip(&cp); ! 572: if (strcmp(arg, "stream") == 0) ! 573: sep->se_socktype = SOCK_STREAM; ! 574: else if (strcmp(arg, "dgram") == 0) ! 575: sep->se_socktype = SOCK_DGRAM; ! 576: else if (strcmp(arg, "rdm") == 0) ! 577: sep->se_socktype = SOCK_RDM; ! 578: else if (strcmp(arg, "seqpacket") == 0) ! 579: sep->se_socktype = SOCK_SEQPACKET; ! 580: else if (strcmp(arg, "raw") == 0) ! 581: sep->se_socktype = SOCK_RAW; ! 582: else ! 583: sep->se_socktype = -1; ! 584: sep->se_proto = strdup(skip(&cp)); ! 585: arg = skip(&cp); ! 586: sep->se_wait = strcmp(arg, "wait") == 0; ! 587: sep->se_user = strdup(skip(&cp)); ! 588: sep->se_server = strdup(skip(&cp)); ! 589: if (strcmp(sep->se_server, "internal") == 0) { ! 590: register struct biltin *bi; ! 591: ! 592: for (bi = biltins; bi->bi_service; bi++) ! 593: if (bi->bi_socktype == sep->se_socktype && ! 594: strcmp(bi->bi_service, sep->se_service) == 0) ! 595: break; ! 596: if (bi->bi_service == 0) { ! 597: syslog(LOG_ERR, "internal service %s unknown\n", ! 598: sep->se_service); ! 599: goto more; ! 600: } ! 601: sep->se_bi = bi; ! 602: sep->se_wait = bi->bi_wait; ! 603: } else ! 604: sep->se_bi = NULL; ! 605: argc = 0; ! 606: for (arg = skip(&cp); cp; arg = skip(&cp)) ! 607: if (argc < MAXARGV) ! 608: sep->se_argv[argc++] = strdup(arg); ! 609: while (argc <= MAXARGV) ! 610: sep->se_argv[argc++] = NULL; ! 611: return (sep); ! 612: } ! 613: ! 614: freeconfig(cp) ! 615: register struct servtab *cp; ! 616: { ! 617: int i; ! 618: ! 619: if (cp->se_service) ! 620: free(cp->se_service); ! 621: if (cp->se_proto) ! 622: free(cp->se_proto); ! 623: if (cp->se_user) ! 624: free(cp->se_user); ! 625: if (cp->se_server) ! 626: free(cp->se_server); ! 627: for (i = 0; i < MAXARGV; i++) ! 628: if (cp->se_argv[i]) ! 629: free(cp->se_argv[i]); ! 630: } ! 631: ! 632: char * ! 633: skip(cpp) ! 634: char **cpp; ! 635: { ! 636: register char *cp = *cpp; ! 637: char *start; ! 638: ! 639: again: ! 640: while (*cp == ' ' || *cp == '\t') ! 641: cp++; ! 642: if (*cp == '\0') { ! 643: int c; ! 644: ! 645: c = getc(fconfig); ! 646: (void) ungetc(c, fconfig); ! 647: if (c == ' ' || c == '\t') ! 648: if (cp = nextline(fconfig)) ! 649: goto again; ! 650: *cpp = (char *)0; ! 651: return ((char *)0); ! 652: } ! 653: start = cp; ! 654: while (*cp && *cp != ' ' && *cp != '\t') ! 655: cp++; ! 656: if (*cp != '\0') ! 657: *cp++ = '\0'; ! 658: *cpp = cp; ! 659: return (start); ! 660: } ! 661: ! 662: char * ! 663: nextline(fd) ! 664: FILE *fd; ! 665: { ! 666: char *cp; ! 667: ! 668: if (fgets(line, sizeof (line), fd) == NULL) ! 669: return ((char *)0); ! 670: cp = index(line, '\n'); ! 671: if (cp) ! 672: *cp = '\0'; ! 673: return (line); ! 674: } ! 675: ! 676: char * ! 677: strdup(cp) ! 678: char *cp; ! 679: { ! 680: char *new; ! 681: ! 682: if (cp == NULL) ! 683: cp = ""; ! 684: new = malloc((unsigned)(strlen(cp) + 1)); ! 685: if (new == (char *)0) { ! 686: syslog(LOG_ERR, "Out of memory."); ! 687: exit(-1); ! 688: } ! 689: (void)strcpy(new, cp); ! 690: return (new); ! 691: } ! 692: ! 693: setproctitle(a, s) ! 694: char *a; ! 695: int s; ! 696: { ! 697: int size; ! 698: register char *cp; ! 699: struct sockaddr_in sin; ! 700: char buf[80]; ! 701: ! 702: cp = Argv[0]; ! 703: size = sizeof(sin); ! 704: if (getpeername(s, &sin, &size) == 0) ! 705: (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); ! 706: else ! 707: (void) sprintf(buf, "-%s", a); ! 708: strncpy(cp, buf, LastArg - cp); ! 709: cp += strlen(cp); ! 710: while (cp < LastArg) ! 711: *cp++ = ' '; ! 712: } ! 713: ! 714: /* ! 715: * Internet services provided internally by inetd: ! 716: */ ! 717: #define BUFSIZE 4096 ! 718: ! 719: /* ARGSUSED */ ! 720: echo_stream(s, sep) /* Echo service -- echo data back */ ! 721: int s; ! 722: struct servtab *sep; ! 723: { ! 724: char buffer[BUFSIZE]; ! 725: int i; ! 726: ! 727: setproctitle(sep->se_service, s); ! 728: while ((i = read(s, buffer, sizeof(buffer))) > 0 && ! 729: write(s, buffer, i) > 0) ! 730: ; ! 731: exit(0); ! 732: } ! 733: ! 734: /* ARGSUSED */ ! 735: echo_dg(s, sep) /* Echo service -- echo data back */ ! 736: int s; ! 737: struct servtab *sep; ! 738: { ! 739: char buffer[BUFSIZE]; ! 740: int i, size; ! 741: struct sockaddr sa; ! 742: ! 743: size = sizeof(sa); ! 744: if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) ! 745: return; ! 746: (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); ! 747: } ! 748: ! 749: /* ARGSUSED */ ! 750: discard_stream(s, sep) /* Discard service -- ignore data */ ! 751: int s; ! 752: struct servtab *sep; ! 753: { ! 754: char buffer[BUFSIZE]; ! 755: ! 756: setproctitle(sep->se_service, s); ! 757: while (1) { ! 758: while (read(s, buffer, sizeof(buffer)) > 0) ! 759: ; ! 760: if (errno != EINTR) ! 761: break; ! 762: } ! 763: exit(0); ! 764: } ! 765: ! 766: /* ARGSUSED */ ! 767: discard_dg(s, sep) /* Discard service -- ignore data */ ! 768: int s; ! 769: struct servtab *sep; ! 770: { ! 771: char buffer[BUFSIZE]; ! 772: ! 773: (void) read(s, buffer, sizeof(buffer)); ! 774: } ! 775: ! 776: #include <ctype.h> ! 777: #define LINESIZ 72 ! 778: char ring[128]; ! 779: char *endring; ! 780: ! 781: initring() ! 782: { ! 783: register int i; ! 784: ! 785: endring = ring; ! 786: ! 787: for (i = 0; i <= 128; ++i) ! 788: if (isprint(i)) ! 789: *endring++ = i; ! 790: } ! 791: ! 792: /* ARGSUSED */ ! 793: chargen_stream(s, sep) /* Character generator */ ! 794: int s; ! 795: struct servtab *sep; ! 796: { ! 797: register char *rs; ! 798: int len; ! 799: char text[LINESIZ+2]; ! 800: ! 801: setproctitle(sep->se_service, s); ! 802: ! 803: if (!endring) { ! 804: initring(); ! 805: rs = ring; ! 806: } ! 807: ! 808: text[LINESIZ] = '\r'; ! 809: text[LINESIZ + 1] = '\n'; ! 810: for (rs = ring;;) { ! 811: if ((len = endring - rs) >= LINESIZ) ! 812: bcopy(rs, text, LINESIZ); ! 813: else { ! 814: bcopy(rs, text, len); ! 815: bcopy(ring, text + len, LINESIZ - len); ! 816: } ! 817: if (++rs == endring) ! 818: rs = ring; ! 819: if (write(s, text, sizeof(text)) != sizeof(text)) ! 820: break; ! 821: } ! 822: exit(0); ! 823: } ! 824: ! 825: /* ARGSUSED */ ! 826: chargen_dg(s, sep) /* Character generator */ ! 827: int s; ! 828: struct servtab *sep; ! 829: { ! 830: struct sockaddr sa; ! 831: static char *rs; ! 832: int len, size; ! 833: char text[LINESIZ+2]; ! 834: ! 835: if (endring == 0) { ! 836: initring(); ! 837: rs = ring; ! 838: } ! 839: ! 840: size = sizeof(sa); ! 841: if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) ! 842: return; ! 843: ! 844: if ((len = endring - rs) >= LINESIZ) ! 845: bcopy(rs, text, LINESIZ); ! 846: else { ! 847: bcopy(rs, text, len); ! 848: bcopy(ring, text + len, LINESIZ - len); ! 849: } ! 850: if (++rs == endring) ! 851: rs = ring; ! 852: text[LINESIZ] = '\r'; ! 853: text[LINESIZ + 1] = '\n'; ! 854: (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); ! 855: } ! 856: ! 857: /* ! 858: * Return a machine readable date and time, in the form of the ! 859: * number of seconds since midnight, Jan 1, 1900. Since gettimeofday ! 860: * returns the number of seconds since midnight, Jan 1, 1970, ! 861: * we must add 2208988800 seconds to this figure to make up for ! 862: * some seventy years Bell Labs was asleep. ! 863: */ ! 864: ! 865: long ! 866: machtime() ! 867: { ! 868: struct timeval tv; ! 869: ! 870: if (gettimeofday(&tv, (struct timezone *)0) < 0) { ! 871: fprintf(stderr, "Unable to get time of day\n"); ! 872: return (0L); ! 873: } ! 874: return (htonl((long)tv.tv_sec + 2208988800)); ! 875: } ! 876: ! 877: /* ARGSUSED */ ! 878: machtime_stream(s, sep) ! 879: int s; ! 880: struct servtab *sep; ! 881: { ! 882: long result; ! 883: ! 884: result = machtime(); ! 885: (void) write(s, (char *) &result, sizeof(result)); ! 886: } ! 887: ! 888: /* ARGSUSED */ ! 889: machtime_dg(s, sep) ! 890: int s; ! 891: struct servtab *sep; ! 892: { ! 893: long result; ! 894: struct sockaddr sa; ! 895: int size; ! 896: ! 897: size = sizeof(sa); ! 898: if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) ! 899: return; ! 900: result = machtime(); ! 901: (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); ! 902: } ! 903: ! 904: /* ARGSUSED */ ! 905: daytime_stream(s, sep) /* Return human-readable time of day */ ! 906: int s; ! 907: struct servtab *sep; ! 908: { ! 909: char buffer[256]; ! 910: time_t time(), clock; ! 911: char *ctime(); ! 912: ! 913: clock = time((time_t *) 0); ! 914: ! 915: (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); ! 916: (void) write(s, buffer, strlen(buffer)); ! 917: } ! 918: ! 919: /* ARGSUSED */ ! 920: daytime_dg(s, sep) /* Return human-readable time of day */ ! 921: int s; ! 922: struct servtab *sep; ! 923: { ! 924: char buffer[256]; ! 925: time_t time(), clock; ! 926: struct sockaddr sa; ! 927: int size; ! 928: char *ctime(); ! 929: ! 930: clock = time((time_t *) 0); ! 931: ! 932: size = sizeof(sa); ! 933: if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) ! 934: return; ! 935: (void) sprintf(buffer, "%.24s\r\n", ctime(&clock)); ! 936: (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa)); ! 937: } ! 938: ! 939: /* ! 940: * print_service: ! 941: * Dump relevant information to stderr ! 942: */ ! 943: print_service(action, sep) ! 944: char *action; ! 945: struct servtab *sep; ! 946: { ! 947: fprintf(stderr, ! 948: "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n", ! 949: action, sep->se_service, sep->se_proto, ! 950: sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server); ! 951: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.