Annotation of 43BSDReno/usr.sbin/inetd/inetd.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.