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