Annotation of 43BSDReno/usr.sbin/inetd/inetd.c, revision 1.1.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.