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

Defined functions

chargen_dg defined in line 805; used 2 times
chargen_stream defined in line 766; used 2 times
config defined in line 365; used 2 times
daytime_dg defined in line 903; used 2 times
daytime_stream defined in line 888; used 2 times
discard_dg defined in line 740; used 2 times
discard_stream defined in line 723; used 2 times
echo_dg defined in line 708; used 2 times
echo_stream defined in line 693; used 2 times
endconfig defined in line 524; used 1 times
enter defined in line 486; used 2 times
freeconfig defined in line 588; used 2 times
getconfigent defined in line 533; used 2 times
initring defined in line 754; used 2 times
machtime defined in line 848; used 2 times
machtime_dg defined in line 872; used 2 times
machtime_stream defined in line 861; used 2 times
main defined in line 146; never used
nextline defined in line 636; used 3 times
reapchild defined in line 337; used 2 times
retry defined in line 438; used 2 times
setconfig defined in line 513; used 1 times
setproctitle defined in line 667; used 3 times
setup defined in line 448; used 2 times
skip defined in line 606; used 9 times
strdup defined in line 650; used 6 times

Defined variables

Argv defined in line 143; used 2 times
CONFIG defined in line 142; used 3 times
LastArg defined in line 144; used 3 times
biltins defined in line 118; used 1 times
copyright defined in line 8; never used
debug defined in line 83; used 6 times
endring defined in line 752; used 12 times
line defined in line 510; used 4 times
maxsock defined in line 84; used 3 times
nsock defined in line 84; used 6 times
options defined in line 86; used 2 times
ring defined in line 751; used 9 times
sccsid defined in line 14; never used
serv defined in line 509; used 1 times
servtab defined in line 106; used 8 times
sp defined in line 88; used 4 times
timingout defined in line 87; used 5 times

Defined struct's

biltin defined in line 112; used 3 times
servtab defined in line 90; used 54 times

Defined macros

CNT_INTVL defined in line 72; used 1 times
LINESIZ defined in line 750; used 9 times
MAXARGV defined in line 99; used 5 times
NUMINT defined in line 141; never used
RETRYTIME defined in line 73; used 2 times
SIGBLOCK defined in line 75; used 5 times
SWAP defined in line 388; used 3 times
TOOMANY defined in line 71; used 1 times
turnon defined in line 458; used 3 times
Last modified: 1986-04-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2379
Valid CSS Valid XHTML 1.0 Strict