[BACK]Return to lpd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / lpr / lpd

Annotation of src/usr.sbin/lpr/lpd/lpd.c, Revision 1.1

1.1     ! cgd         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, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: #ifndef lint
        !            35: char copyright[] =
        !            36: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
        !            37:  All rights reserved.\n";
        !            38: #endif /* not lint */
        !            39:
        !            40: #ifndef lint
        !            41: static char sccsid[] = "@(#)lpd.c      5.12 (Berkeley) 3/7/91";
        !            42: #endif /* not lint */
        !            43:
        !            44: /*
        !            45:  * lpd -- line printer daemon.
        !            46:  *
        !            47:  * Listen for a connection and perform the requested operation.
        !            48:  * Operations are:
        !            49:  *     \1printer\n
        !            50:  *             check the queue for jobs and print any found.
        !            51:  *     \2printer\n
        !            52:  *             receive a job from another machine and queue it.
        !            53:  *     \3printer [users ...] [jobs ...]\n
        !            54:  *             return the current state of the queue (short form).
        !            55:  *     \4printer [users ...] [jobs ...]\n
        !            56:  *             return the current state of the queue (long form).
        !            57:  *     \5printer person [users ...] [jobs ...]\n
        !            58:  *             remove jobs from the queue.
        !            59:  *
        !            60:  * Strategy to maintain protected spooling area:
        !            61:  *     1. Spooling area is writable only by daemon and spooling group
        !            62:  *     2. lpr runs setuid root and setgrp spooling group; it uses
        !            63:  *        root to access any file it wants (verifying things before
        !            64:  *        with an access call) and group id to know how it should
        !            65:  *        set up ownership of files in the spooling area.
        !            66:  *     3. Files in spooling area are owned by root, group spooling
        !            67:  *        group, with mode 660.
        !            68:  *     4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
        !            69:  *        access files and printer.  Users can't get to anything
        !            70:  *        w/o help of lpq and lprm programs.
        !            71:  */
        !            72:
        !            73: #include "lp.h"
        !            74: #include "pathnames.h"
        !            75:
        !            76: int    lflag;                          /* log requests flag */
        !            77: int    from_remote;                    /* from remote socket */
        !            78:
        !            79: void mcleanup(), reapchild();
        !            80:
        !            81: main(argc, argv)
        !            82:        int argc;
        !            83:        char **argv;
        !            84: {
        !            85:        int f, funix, finet, options = 0, defreadfds, fromlen;
        !            86:        struct sockaddr_un sun, fromunix;
        !            87:        struct sockaddr_in sin, frominet;
        !            88:        int omask, lfd;
        !            89:
        !            90:        gethostname(host, sizeof(host));
        !            91:        name = argv[0];
        !            92:
        !            93:        while (--argc > 0) {
        !            94:                argv++;
        !            95:                if (argv[0][0] == '-')
        !            96:                        switch (argv[0][1]) {
        !            97:                        case 'd':
        !            98:                                options |= SO_DEBUG;
        !            99:                                break;
        !           100:                        case 'l':
        !           101:                                lflag++;
        !           102:                                break;
        !           103:                        }
        !           104:        }
        !           105:
        !           106: #ifndef DEBUG
        !           107:        /*
        !           108:         * Set up standard environment by detaching from the parent.
        !           109:         */
        !           110:        daemon(0, 0);
        !           111: #endif
        !           112:
        !           113:        openlog("lpd", LOG_PID, LOG_LPR);
        !           114:        (void) umask(0);
        !           115:        lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
        !           116:        if (lfd < 0) {
        !           117:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
        !           118:                exit(1);
        !           119:        }
        !           120:        if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
        !           121:                if (errno == EWOULDBLOCK)       /* active deamon present */
        !           122:                        exit(0);
        !           123:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
        !           124:                exit(1);
        !           125:        }
        !           126:        ftruncate(lfd, 0);
        !           127:        /*
        !           128:         * write process id for others to know
        !           129:         */
        !           130:        sprintf(line, "%u\n", getpid());
        !           131:        f = strlen(line);
        !           132:        if (write(lfd, line, f) != f) {
        !           133:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
        !           134:                exit(1);
        !           135:        }
        !           136:        signal(SIGCHLD, reapchild);
        !           137:        /*
        !           138:         * Restart all the printers.
        !           139:         */
        !           140:        startup();
        !           141:        (void) unlink(_PATH_SOCKETNAME);
        !           142:        funix = socket(AF_UNIX, SOCK_STREAM, 0);
        !           143:        if (funix < 0) {
        !           144:                syslog(LOG_ERR, "socket: %m");
        !           145:                exit(1);
        !           146:        }
        !           147: #define        mask(s) (1 << ((s) - 1))
        !           148:        omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
        !           149:        signal(SIGHUP, mcleanup);
        !           150:        signal(SIGINT, mcleanup);
        !           151:        signal(SIGQUIT, mcleanup);
        !           152:        signal(SIGTERM, mcleanup);
        !           153:        sun.sun_family = AF_UNIX;
        !           154:        strcpy(sun.sun_path, _PATH_SOCKETNAME);
        !           155:        if (bind(funix,
        !           156:             (struct sockaddr *)&sun, strlen(sun.sun_path) + 2) < 0) {
        !           157:                syslog(LOG_ERR, "ubind: %m");
        !           158:                exit(1);
        !           159:        }
        !           160:        sigsetmask(omask);
        !           161:        defreadfds = 1 << funix;
        !           162:        listen(funix, 5);
        !           163:        finet = socket(AF_INET, SOCK_STREAM, 0);
        !           164:        if (finet >= 0) {
        !           165:                struct servent *sp;
        !           166:
        !           167:                if (options & SO_DEBUG)
        !           168:                        if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
        !           169:                                syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
        !           170:                                mcleanup();
        !           171:                        }
        !           172:                sp = getservbyname("printer", "tcp");
        !           173:                if (sp == NULL) {
        !           174:                        syslog(LOG_ERR, "printer/tcp: unknown service");
        !           175:                        mcleanup();
        !           176:                }
        !           177:                sin.sin_family = AF_INET;
        !           178:                sin.sin_port = sp->s_port;
        !           179:                if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        !           180:                        syslog(LOG_ERR, "bind: %m");
        !           181:                        mcleanup();
        !           182:                }
        !           183:                defreadfds |= 1 << finet;
        !           184:                listen(finet, 5);
        !           185:        }
        !           186:        /*
        !           187:         * Main loop: accept, do a request, continue.
        !           188:         */
        !           189:        for (;;) {
        !           190:                int domain, nfds, s, readfds = defreadfds;
        !           191:
        !           192:                nfds = select(20, &readfds, 0, 0, 0);
        !           193:                if (nfds <= 0) {
        !           194:                        if (nfds < 0 && errno != EINTR)
        !           195:                                syslog(LOG_WARNING, "select: %m");
        !           196:                        continue;
        !           197:                }
        !           198:                if (readfds & (1 << funix)) {
        !           199:                        domain = AF_UNIX, fromlen = sizeof(fromunix);
        !           200:                        s = accept(funix,
        !           201:                            (struct sockaddr *)&fromunix, &fromlen);
        !           202:                } else if (readfds & (1 << finet)) {
        !           203:                        domain = AF_INET, fromlen = sizeof(frominet);
        !           204:                        s = accept(finet,
        !           205:                            (struct sockaddr *)&frominet, &fromlen);
        !           206:                }
        !           207:                if (s < 0) {
        !           208:                        if (errno != EINTR)
        !           209:                                syslog(LOG_WARNING, "accept: %m");
        !           210:                        continue;
        !           211:                }
        !           212:                if (fork() == 0) {
        !           213:                        signal(SIGCHLD, SIG_IGN);
        !           214:                        signal(SIGHUP, SIG_IGN);
        !           215:                        signal(SIGINT, SIG_IGN);
        !           216:                        signal(SIGQUIT, SIG_IGN);
        !           217:                        signal(SIGTERM, SIG_IGN);
        !           218:                        (void) close(funix);
        !           219:                        (void) close(finet);
        !           220:                        dup2(s, 1);
        !           221:                        (void) close(s);
        !           222:                        if (domain == AF_INET) {
        !           223:                                from_remote = 1;
        !           224:                                chkhost(&frominet);
        !           225:                        } else
        !           226:                                from_remote = 0;
        !           227:                        doit();
        !           228:                        exit(0);
        !           229:                }
        !           230:                (void) close(s);
        !           231:        }
        !           232: }
        !           233:
        !           234: void
        !           235: reapchild()
        !           236: {
        !           237:        union wait status;
        !           238:
        !           239:        while (wait3((int *)&status, WNOHANG, 0) > 0)
        !           240:                ;
        !           241: }
        !           242:
        !           243: void
        !           244: mcleanup()
        !           245: {
        !           246:        if (lflag)
        !           247:                syslog(LOG_INFO, "exiting");
        !           248:        unlink(_PATH_SOCKETNAME);
        !           249:        exit(0);
        !           250: }
        !           251:
        !           252: /*
        !           253:  * Stuff for handling job specifications
        !           254:  */
        !           255: char   *user[MAXUSERS];        /* users to process */
        !           256: int    users;                  /* # of users in user array */
        !           257: int    requ[MAXREQUESTS];      /* job number of spool entries */
        !           258: int    requests;               /* # of spool requests */
        !           259: char   *person;                /* name of person doing lprm */
        !           260:
        !           261: char   fromb[32];      /* buffer for client's machine name */
        !           262: char   cbuf[BUFSIZ];   /* command line buffer */
        !           263: char   *cmdnames[] = {
        !           264:        "null",
        !           265:        "printjob",
        !           266:        "recvjob",
        !           267:        "displayq short",
        !           268:        "displayq long",
        !           269:        "rmjob"
        !           270: };
        !           271:
        !           272: doit()
        !           273: {
        !           274:        register char *cp;
        !           275:        register int n;
        !           276:
        !           277:        for (;;) {
        !           278:                cp = cbuf;
        !           279:                do {
        !           280:                        if (cp >= &cbuf[sizeof(cbuf) - 1])
        !           281:                                fatal("Command line too long");
        !           282:                        if ((n = read(1, cp, 1)) != 1) {
        !           283:                                if (n < 0)
        !           284:                                        fatal("Lost connection");
        !           285:                                return;
        !           286:                        }
        !           287:                } while (*cp++ != '\n');
        !           288:                *--cp = '\0';
        !           289:                cp = cbuf;
        !           290:                if (lflag) {
        !           291:                        if (*cp >= '\1' && *cp <= '\5')
        !           292:                                syslog(LOG_INFO, "%s requests %s %s",
        !           293:                                        from, cmdnames[*cp], cp+1);
        !           294:                        else
        !           295:                                syslog(LOG_INFO, "bad request (%d) from %s",
        !           296:                                        *cp, from);
        !           297:                }
        !           298:                switch (*cp++) {
        !           299:                case '\1':      /* check the queue and print any jobs there */
        !           300:                        printer = cp;
        !           301:                        printjob();
        !           302:                        break;
        !           303:                case '\2':      /* receive files to be queued */
        !           304:                        if (!from_remote) {
        !           305:                                syslog(LOG_INFO, "illegal request (%d)", *cp);
        !           306:                                exit(1);
        !           307:                        }
        !           308:                        printer = cp;
        !           309:                        recvjob();
        !           310:                        break;
        !           311:                case '\3':      /* display the queue (short form) */
        !           312:                case '\4':      /* display the queue (long form) */
        !           313:                        printer = cp;
        !           314:                        while (*cp) {
        !           315:                                if (*cp != ' ') {
        !           316:                                        cp++;
        !           317:                                        continue;
        !           318:                                }
        !           319:                                *cp++ = '\0';
        !           320:                                while (isspace(*cp))
        !           321:                                        cp++;
        !           322:                                if (*cp == '\0')
        !           323:                                        break;
        !           324:                                if (isdigit(*cp)) {
        !           325:                                        if (requests >= MAXREQUESTS)
        !           326:                                                fatal("Too many requests");
        !           327:                                        requ[requests++] = atoi(cp);
        !           328:                                } else {
        !           329:                                        if (users >= MAXUSERS)
        !           330:                                                fatal("Too many users");
        !           331:                                        user[users++] = cp;
        !           332:                                }
        !           333:                        }
        !           334:                        displayq(cbuf[0] - '\3');
        !           335:                        exit(0);
        !           336:                case '\5':      /* remove a job from the queue */
        !           337:                        if (!from_remote) {
        !           338:                                syslog(LOG_INFO, "illegal request (%d)", *cp);
        !           339:                                exit(1);
        !           340:                        }
        !           341:                        printer = cp;
        !           342:                        while (*cp && *cp != ' ')
        !           343:                                cp++;
        !           344:                        if (!*cp)
        !           345:                                break;
        !           346:                        *cp++ = '\0';
        !           347:                        person = cp;
        !           348:                        while (*cp) {
        !           349:                                if (*cp != ' ') {
        !           350:                                        cp++;
        !           351:                                        continue;
        !           352:                                }
        !           353:                                *cp++ = '\0';
        !           354:                                while (isspace(*cp))
        !           355:                                        cp++;
        !           356:                                if (*cp == '\0')
        !           357:                                        break;
        !           358:                                if (isdigit(*cp)) {
        !           359:                                        if (requests >= MAXREQUESTS)
        !           360:                                                fatal("Too many requests");
        !           361:                                        requ[requests++] = atoi(cp);
        !           362:                                } else {
        !           363:                                        if (users >= MAXUSERS)
        !           364:                                                fatal("Too many users");
        !           365:                                        user[users++] = cp;
        !           366:                                }
        !           367:                        }
        !           368:                        rmjob();
        !           369:                        break;
        !           370:                }
        !           371:                fatal("Illegal service request");
        !           372:        }
        !           373: }
        !           374:
        !           375: /*
        !           376:  * Make a pass through the printcap database and start printing any
        !           377:  * files left from the last time the machine went down.
        !           378:  */
        !           379: startup()
        !           380: {
        !           381:        char buf[BUFSIZ];
        !           382:        register char *cp;
        !           383:        int pid;
        !           384:
        !           385:        printer = buf;
        !           386:
        !           387:        /*
        !           388:         * Restart the daemons.
        !           389:         */
        !           390:        while (getprent(buf) > 0) {
        !           391:                for (cp = buf; *cp; cp++)
        !           392:                        if (*cp == '|' || *cp == ':') {
        !           393:                                *cp = '\0';
        !           394:                                break;
        !           395:                        }
        !           396:                if ((pid = fork()) < 0) {
        !           397:                        syslog(LOG_WARNING, "startup: cannot fork");
        !           398:                        mcleanup();
        !           399:                }
        !           400:                if (!pid) {
        !           401:                        endprent();
        !           402:                        printjob();
        !           403:                }
        !           404:        }
        !           405: }
        !           406:
        !           407: #define DUMMY ":nobody::"
        !           408:
        !           409: /*
        !           410:  * Check to see if the from host has access to the line printer.
        !           411:  */
        !           412: chkhost(f)
        !           413:        struct sockaddr_in *f;
        !           414: {
        !           415:        register struct hostent *hp;
        !           416:        register FILE *hostf;
        !           417:        register char *cp, *sp;
        !           418:        char ahost[50];
        !           419:        int first = 1;
        !           420:        extern char *inet_ntoa();
        !           421:        int baselen = -1;
        !           422:
        !           423:        f->sin_port = ntohs(f->sin_port);
        !           424:        if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
        !           425:                fatal("Malformed from address");
        !           426:        hp = gethostbyaddr((char *)&f->sin_addr,
        !           427:            sizeof(struct in_addr), f->sin_family);
        !           428:        if (hp == 0)
        !           429:                fatal("Host name for your address (%s) unknown",
        !           430:                        inet_ntoa(f->sin_addr));
        !           431:
        !           432:        strcpy(fromb, hp->h_name);
        !           433:        from = fromb;
        !           434:        if (!strcmp(from, host))
        !           435:                return;
        !           436:
        !           437:        sp = fromb;
        !           438:        cp = ahost;
        !           439:        while (*sp) {
        !           440:                if (*sp == '.') {
        !           441:                        if (baselen == -1)
        !           442:                                baselen = sp - fromb;
        !           443:                        *cp++ = *sp++;
        !           444:                } else {
        !           445:                        *cp++ = isupper(*sp) ? tolower(*sp++) : *sp++;
        !           446:                }
        !           447:        }
        !           448:        *cp = '\0';
        !           449:        hostf = fopen(_PATH_HOSTSEQUIV, "r");
        !           450: again:
        !           451:        if (hostf) {
        !           452:                if (!_validuser(hostf, ahost, DUMMY, DUMMY, baselen)) {
        !           453:                        (void) fclose(hostf);
        !           454:                        return;
        !           455:                }
        !           456:                (void) fclose(hostf);
        !           457:        }
        !           458:        if (first == 1) {
        !           459:                first = 0;
        !           460:                hostf = fopen(_PATH_HOSTSLPD, "r");
        !           461:                goto again;
        !           462:        }
        !           463:        fatal("Your host does not have line printer access");
        !           464: }

CVSweb <webmaster@jp.NetBSD.org>