[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.48

1.48    ! itojun      1: /*     $NetBSD: lpd.c,v 1.47 2003/09/01 00:21:08 itojun Exp $  */
1.7       mrg         2:
1.1       cgd         3: /*
1.4       cgd         4:  * Copyright (c) 1983, 1993, 1994
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
1.1       cgd         7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.46      agc        16:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
1.11      mikel      33: #include <sys/cdefs.h>
                     34:
1.1       cgd        35: #ifndef lint
1.11      mikel      36: __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\
                     37:        The Regents of the University of California.  All rights reserved.\n");
1.1       cgd        38: #endif /* not lint */
                     39:
                     40: #ifndef lint
1.10      mikel      41: #if 0
1.12      mrg        42: static char sccsid[] = "@(#)lpd.c      8.7 (Berkeley) 5/10/95";
1.10      mikel      43: #else
1.48    ! itojun     44: __RCSID("$NetBSD: lpd.c,v 1.47 2003/09/01 00:21:08 itojun Exp $");
1.10      mikel      45: #endif
1.1       cgd        46: #endif /* not lint */
                     47:
                     48: /*
                     49:  * lpd -- line printer daemon.
                     50:  *
                     51:  * Listen for a connection and perform the requested operation.
                     52:  * Operations are:
                     53:  *     \1printer\n
                     54:  *             check the queue for jobs and print any found.
                     55:  *     \2printer\n
                     56:  *             receive a job from another machine and queue it.
                     57:  *     \3printer [users ...] [jobs ...]\n
                     58:  *             return the current state of the queue (short form).
                     59:  *     \4printer [users ...] [jobs ...]\n
                     60:  *             return the current state of the queue (long form).
                     61:  *     \5printer person [users ...] [jobs ...]\n
                     62:  *             remove jobs from the queue.
                     63:  *
                     64:  * Strategy to maintain protected spooling area:
                     65:  *     1. Spooling area is writable only by daemon and spooling group
                     66:  *     2. lpr runs setuid root and setgrp spooling group; it uses
                     67:  *        root to access any file it wants (verifying things before
                     68:  *        with an access call) and group id to know how it should
                     69:  *        set up ownership of files in the spooling area.
                     70:  *     3. Files in spooling area are owned by root, group spooling
                     71:  *        group, with mode 660.
                     72:  *     4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
                     73:  *        access files and printer.  Users can't get to anything
                     74:  *        w/o help of lpq and lprm programs.
                     75:  */
                     76:
1.4       cgd        77: #include <sys/param.h>
                     78: #include <sys/wait.h>
                     79: #include <sys/types.h>
                     80: #include <sys/socket.h>
                     81: #include <sys/un.h>
                     82: #include <sys/stat.h>
1.12      mrg        83: #include <sys/file.h>
1.39      mycroft    84: #include <sys/poll.h>
1.4       cgd        85: #include <netinet/in.h>
                     86:
1.18      mrg        87: #include <err.h>
1.4       cgd        88: #include <netdb.h>
                     89: #include <unistd.h>
                     90: #include <syslog.h>
                     91: #include <signal.h>
                     92: #include <errno.h>
                     93: #include <fcntl.h>
                     94: #include <dirent.h>
1.30      mjl        95: #include <stdarg.h>
1.4       cgd        96: #include <stdio.h>
                     97: #include <stdlib.h>
                     98: #include <string.h>
                     99: #include <ctype.h>
1.11      mikel     100: #include <arpa/inet.h>
                    101:
1.38      itojun    102: #ifdef LIBWRAP
                    103: #include <tcpd.h>
                    104: #endif
                    105:
1.1       cgd       106: #include "lp.h"
1.4       cgd       107: #include "lp.local.h"
1.1       cgd       108: #include "pathnames.h"
1.4       cgd       109: #include "extern.h"
1.1       cgd       110:
1.21      itojun    111: /* XXX from libc/net/rcmd.c */
1.35      wiz       112: extern int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t,
                    113:                           const char *, const char *);
1.21      itojun    114:
1.38      itojun    115: #ifdef LIBWRAP
                    116: int allow_severity = LOG_AUTH|LOG_INFO;
                    117: int deny_severity = LOG_AUTH|LOG_WARNING;
                    118: #endif
                    119:
1.1       cgd       120: int    lflag;                          /* log requests flag */
1.18      mrg       121: int    rflag;                          /* allow of for remote printers */
1.8       perry     122: int    sflag;                          /* secure (no inet) flag */
1.1       cgd       123: int    from_remote;                    /* from remote socket */
1.23      scw       124: char   **blist;                        /* list of addresses to bind(2) to */
                    125: int    blist_size;
                    126: int    blist_addrs;
1.1       cgd       127:
1.39      mycroft   128: int                    main(int, char **);
                    129: static void            reapchild(int);
                    130: static void            mcleanup(int);
                    131: static void            doit(void);
                    132: static void            startup(void);
                    133: static void            chkhost(struct sockaddr *, int);
                    134: static int             ckqueue(char *);
                    135: static void            usage(void);
                    136: static struct pollfd   *socksetup(int, int, const char *, int *);
1.1       cgd       137:
1.5       hpeyerl   138: uid_t  uid, euid;
1.18      mrg       139: int child_count;
1.5       hpeyerl   140:
1.30      mjl       141: #define LPD_NOPORTCHK  0001            /* skip reserved-port check */
                    142:
1.4       cgd       143: int
1.30      mjl       144: main(int argc, char **argv)
1.1       cgd       145: {
1.41      mycroft   146:        struct sockaddr_storage from;
                    147:        socklen_t fromlen;
1.22      mrg       148:        sigset_t nmask, omask;
1.39      mycroft   149:        int lfd, errs, i, f, nfds;
                    150:        struct pollfd *socks;
1.32      wiz       151:        int child_max = 32;     /* more than enough to hose the system */
1.30      mjl       152:        int options = 0, check_options = 0;
1.26      itojun    153:        struct servent *sp;
                    154:        const char *port = "printer";
1.48    ! itojun    155:        char **newblist;
1.1       cgd       156:
1.5       hpeyerl   157:        euid = geteuid();       /* these shouldn't be different */
                    158:        uid = getuid();
1.1       cgd       159:        gethostname(host, sizeof(host));
1.16      mrg       160:        host[sizeof(host) - 1] = '\0';
1.1       cgd       161:        name = argv[0];
                    162:
1.13      mrg       163:        errs = 0;
1.34      hubertf   164:        while ((i = getopt(argc, argv, "b:dln:srw:W")) != -1)
1.13      mrg       165:                switch (i) {
1.23      scw       166:                case 'b':
                    167:                        if (blist_addrs >= blist_size) {
1.48    ! itojun    168:                                newblist = realloc(blist,
        !           169:                                    blist_size + sizeof(char *) * 4);
        !           170:                                if (newblist == NULL)
        !           171:                                        err(1, "cant allocate bind addr list");
        !           172:                                blist = newblist;
1.23      scw       173:                                blist_size += sizeof(char *) * 4;
                    174:                        }
                    175:                        blist[blist_addrs++] = strdup(optarg);
                    176:                        break;
1.13      mrg       177:                case 'd':
                    178:                        options |= SO_DEBUG;
                    179:                        break;
                    180:                case 'l':
                    181:                        lflag++;
1.14      mrg       182:                        break;
1.18      mrg       183:                case 'n':
                    184:                        child_max = atoi(optarg);
                    185:                        if (child_max < 0 || child_max > 1024)
                    186:                                errx(1, "invalid number of children: %s",
                    187:                                    optarg);
                    188:                        break;
                    189:                case 'r':
                    190:                        rflag++;
                    191:                        break;
1.14      mrg       192:                case 's':
                    193:                        sflag++;
1.13      mrg       194:                        break;
1.18      mrg       195:                case 'w':
                    196:                        wait_time = atoi(optarg);
                    197:                        if (wait_time < 0)
                    198:                                errx(1, "wait time must be postive: %s",
                    199:                                    optarg);
                    200:                        if (wait_time < 30)
                    201:                            warnx("warning: wait time less than 30 seconds");
                    202:                        break;
1.30      mjl       203:                case 'W':/* allow connections coming from a non-reserved port */
                    204:                         /* (done by some lpr-implementations for MS-Windows) */
                    205:                        check_options |= LPD_NOPORTCHK;
                    206:                        break;
1.13      mrg       207:                default:
                    208:                        errs++;
                    209:                }
                    210:        argc -= optind;
                    211:        argv += optind;
1.22      mrg       212:        if (errs)
1.13      mrg       213:                usage();
1.1       cgd       214:
1.22      mrg       215:        switch (argc) {
                    216:        case 1:
                    217:                if ((i = atoi(argv[0])) == 0)
                    218:                        usage();
                    219:                if (i < 0 || i > USHRT_MAX)
                    220:                        errx(1, "port # %d is invalid", i);
                    221:
1.26      itojun    222:                port = argv[0];
1.22      mrg       223:                break;
                    224:        case 0:
1.26      itojun    225:                sp = getservbyname(port, "tcp");
1.22      mrg       226:                if (sp == NULL)
1.26      itojun    227:                        errx(1, "%s/tcp: unknown service", port);
1.22      mrg       228:                break;
                    229:        default:
                    230:                usage();
                    231:        }
                    232:
1.1       cgd       233: #ifndef DEBUG
                    234:        /*
                    235:         * Set up standard environment by detaching from the parent.
                    236:         */
                    237:        daemon(0, 0);
                    238: #endif
                    239:
                    240:        openlog("lpd", LOG_PID, LOG_LPR);
1.4       cgd       241:        syslog(LOG_INFO, "restarted");
1.9       mrg       242:        (void)umask(0);
1.1       cgd       243:        lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
                    244:        if (lfd < 0) {
                    245:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
                    246:                exit(1);
                    247:        }
                    248:        if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
1.40      mycroft   249:                if (errno == EWOULDBLOCK) {     /* active daemon present */
                    250:                        syslog(LOG_ERR, "%s is locked; another lpd is running",
                    251:                            _PATH_MASTERLOCK);
1.1       cgd       252:                        exit(0);
1.40      mycroft   253:                }
1.1       cgd       254:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
                    255:                exit(1);
                    256:        }
                    257:        ftruncate(lfd, 0);
                    258:        /*
                    259:         * write process id for others to know
                    260:         */
1.9       mrg       261:        (void)snprintf(line, sizeof(line), "%u\n", getpid());
1.1       cgd       262:        f = strlen(line);
                    263:        if (write(lfd, line, f) != f) {
                    264:                syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
                    265:                exit(1);
                    266:        }
                    267:        signal(SIGCHLD, reapchild);
                    268:        /*
                    269:         * Restart all the printers.
                    270:         */
                    271:        startup();
1.22      mrg       272:
                    273:        sigemptyset(&nmask);
                    274:        sigaddset(&nmask, SIGHUP);
                    275:        sigaddset(&nmask, SIGINT);
                    276:        sigaddset(&nmask, SIGQUIT);
                    277:        sigaddset(&nmask, SIGTERM);
                    278:        sigprocmask(SIG_BLOCK, &nmask, &omask);
                    279:
1.1       cgd       280:        signal(SIGHUP, mcleanup);
                    281:        signal(SIGINT, mcleanup);
                    282:        signal(SIGQUIT, mcleanup);
                    283:        signal(SIGTERM, mcleanup);
1.39      mycroft   284:
                    285:        socks = socksetup(PF_UNSPEC, options, port, &nfds);
                    286:
1.22      mrg       287:        sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
1.1       cgd       288:
1.24      scw       289:        if (blist != NULL) {
                    290:                for (i = 0; i < blist_addrs; i++)
                    291:                        free(blist[i]);
1.23      scw       292:                free(blist);
1.24      scw       293:        }
1.23      scw       294:
1.1       cgd       295:        /*
                    296:         * Main loop: accept, do a request, continue.
                    297:         */
1.41      mycroft   298:        memset(&from, 0, sizeof(from));
1.1       cgd       299:        for (;;) {
1.41      mycroft   300:                int rv, s;
1.18      mrg       301:                /* "short" so it overflows in about 2 hours */
1.39      mycroft   302:                struct timespec sleeptime = {10, 0};
1.18      mrg       303:
                    304:                while (child_max < child_count) {
                    305:                        syslog(LOG_WARNING,
1.39      mycroft   306:                            "too many children, sleeping for %ld seconds",
1.42      lukem     307:                                (long)sleeptime.tv_sec);
1.39      mycroft   308:                        nanosleep(&sleeptime, NULL);
                    309:                        sleeptime.tv_sec <<= 1;
                    310:                        if (sleeptime.tv_sec <= 0) {
1.18      mrg       311:                                syslog(LOG_CRIT, "sleeptime overflowed! help!");
1.39      mycroft   312:                                sleeptime.tv_sec = 10;
1.18      mrg       313:                        }
                    314:                }
1.1       cgd       315:
1.39      mycroft   316:                rv = poll(socks, nfds, INFTIM);
                    317:                if (rv <= 0) {
                    318:                        if (rv < 0 && errno != EINTR)
                    319:                                syslog(LOG_WARNING, "poll: %m");
1.1       cgd       320:                        continue;
                    321:                }
1.39      mycroft   322:                 for (i = 0; i < nfds; i++)
                    323:                        if (socks[i].revents & POLLIN) {
1.41      mycroft   324:                                fromlen = sizeof(from);
                    325:                                s = accept(socks[i].fd,
                    326:                                    (struct sockaddr *)&from, &fromlen);
1.39      mycroft   327:                                break;
                    328:                        }
1.1       cgd       329:                if (s < 0) {
                    330:                        if (errno != EINTR)
                    331:                                syslog(LOG_WARNING, "accept: %m");
                    332:                        continue;
                    333:                }
1.18      mrg       334:
                    335:                switch (fork()) {
                    336:                case 0:
1.1       cgd       337:                        signal(SIGCHLD, SIG_IGN);
                    338:                        signal(SIGHUP, SIG_IGN);
                    339:                        signal(SIGINT, SIG_IGN);
                    340:                        signal(SIGQUIT, SIG_IGN);
                    341:                        signal(SIGTERM, SIG_IGN);
1.39      mycroft   342:                                for (i = 0; i < nfds; i++)
                    343:                                (void)close(socks[i].fd);
1.44      thorpej   344:                        dup2(s, STDOUT_FILENO);
1.9       mrg       345:                        (void)close(s);
1.41      mycroft   346:                        if (from.ss_family != AF_LOCAL) {
1.20      itojun    347:                                /* for both AF_INET and AF_INET6 */
1.1       cgd       348:                                from_remote = 1;
1.41      mycroft   349:                                chkhost((struct sockaddr *)&from, check_options);
1.1       cgd       350:                        } else
                    351:                                from_remote = 0;
                    352:                        doit();
                    353:                        exit(0);
1.18      mrg       354:                case -1:
                    355:                        syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds...");
                    356:                        sleep(10);
                    357:                        continue;
                    358:                default:
                    359:                        child_count++;
1.1       cgd       360:                }
1.9       mrg       361:                (void)close(s);
1.1       cgd       362:        }
                    363: }
                    364:
1.4       cgd       365: static void
1.30      mjl       366: reapchild(int signo)
1.1       cgd       367: {
                    368:        union wait status;
                    369:
                    370:        while (wait3((int *)&status, WNOHANG, 0) > 0)
1.18      mrg       371:                child_count--;
1.1       cgd       372: }
                    373:
1.4       cgd       374: static void
1.30      mjl       375: mcleanup(int signo)
1.1       cgd       376: {
                    377:        if (lflag)
                    378:                syslog(LOG_INFO, "exiting");
                    379:        unlink(_PATH_SOCKETNAME);
                    380:        exit(0);
                    381: }
                    382:
                    383: /*
                    384:  * Stuff for handling job specifications
                    385:  */
                    386: char   *user[MAXUSERS];        /* users to process */
                    387: int    users;                  /* # of users in user array */
                    388: int    requ[MAXREQUESTS];      /* job number of spool entries */
                    389: int    requests;               /* # of spool requests */
                    390: char   *person;                /* name of person doing lprm */
                    391:
1.20      itojun    392: char   fromb[NI_MAXHOST];      /* buffer for client's machine name */
1.4       cgd       393: char   cbuf[BUFSIZ];           /* command line buffer */
1.1       cgd       394: char   *cmdnames[] = {
                    395:        "null",
                    396:        "printjob",
                    397:        "recvjob",
                    398:        "displayq short",
                    399:        "displayq long",
                    400:        "rmjob"
                    401: };
                    402:
1.4       cgd       403: static void
1.30      mjl       404: doit(void)
1.1       cgd       405: {
1.13      mrg       406:        char *cp;
                    407:        int n;
1.1       cgd       408:
                    409:        for (;;) {
                    410:                cp = cbuf;
                    411:                do {
                    412:                        if (cp >= &cbuf[sizeof(cbuf) - 1])
                    413:                                fatal("Command line too long");
1.31      mjl       414:                        if ((n = read(STDOUT_FILENO, cp, 1)) != 1) {
1.1       cgd       415:                                if (n < 0)
                    416:                                        fatal("Lost connection");
                    417:                                return;
                    418:                        }
                    419:                } while (*cp++ != '\n');
                    420:                *--cp = '\0';
                    421:                cp = cbuf;
                    422:                if (lflag) {
1.18      mrg       423:                        if (*cp >= '\1' && *cp <= '\5') {
1.1       cgd       424:                                syslog(LOG_INFO, "%s requests %s %s",
1.10      mikel     425:                                        from, cmdnames[(int)*cp], cp+1);
1.18      mrg       426:                                setproctitle("serving %s: %s %s", from,
                    427:                                    cmdnames[(int)*cp], cp+1);
                    428:                        }
1.1       cgd       429:                        else
                    430:                                syslog(LOG_INFO, "bad request (%d) from %s",
                    431:                                        *cp, from);
                    432:                }
                    433:                switch (*cp++) {
                    434:                case '\1':      /* check the queue and print any jobs there */
                    435:                        printer = cp;
1.29      mrg       436:                        if (*printer == '\0')
                    437:                                printer = DEFLP;
1.1       cgd       438:                        printjob();
                    439:                        break;
                    440:                case '\2':      /* receive files to be queued */
                    441:                        if (!from_remote) {
                    442:                                syslog(LOG_INFO, "illegal request (%d)", *cp);
                    443:                                exit(1);
                    444:                        }
                    445:                        printer = cp;
1.29      mrg       446:                        if (*printer == '\0')
                    447:                                printer = DEFLP;
1.1       cgd       448:                        recvjob();
                    449:                        break;
                    450:                case '\3':      /* display the queue (short form) */
                    451:                case '\4':      /* display the queue (long form) */
                    452:                        printer = cp;
1.29      mrg       453:                        if (*printer == '\0')
                    454:                                printer = DEFLP;
1.1       cgd       455:                        while (*cp) {
                    456:                                if (*cp != ' ') {
                    457:                                        cp++;
                    458:                                        continue;
                    459:                                }
                    460:                                *cp++ = '\0';
                    461:                                while (isspace(*cp))
                    462:                                        cp++;
                    463:                                if (*cp == '\0')
                    464:                                        break;
                    465:                                if (isdigit(*cp)) {
                    466:                                        if (requests >= MAXREQUESTS)
                    467:                                                fatal("Too many requests");
                    468:                                        requ[requests++] = atoi(cp);
                    469:                                } else {
                    470:                                        if (users >= MAXUSERS)
                    471:                                                fatal("Too many users");
                    472:                                        user[users++] = cp;
                    473:                                }
                    474:                        }
                    475:                        displayq(cbuf[0] - '\3');
                    476:                        exit(0);
                    477:                case '\5':      /* remove a job from the queue */
                    478:                        if (!from_remote) {
                    479:                                syslog(LOG_INFO, "illegal request (%d)", *cp);
                    480:                                exit(1);
                    481:                        }
                    482:                        printer = cp;
1.29      mrg       483:                        if (*printer == '\0')
                    484:                                printer = DEFLP;
1.1       cgd       485:                        while (*cp && *cp != ' ')
                    486:                                cp++;
                    487:                        if (!*cp)
                    488:                                break;
                    489:                        *cp++ = '\0';
                    490:                        person = cp;
                    491:                        while (*cp) {
                    492:                                if (*cp != ' ') {
                    493:                                        cp++;
                    494:                                        continue;
                    495:                                }
                    496:                                *cp++ = '\0';
                    497:                                while (isspace(*cp))
                    498:                                        cp++;
                    499:                                if (*cp == '\0')
                    500:                                        break;
                    501:                                if (isdigit(*cp)) {
                    502:                                        if (requests >= MAXREQUESTS)
                    503:                                                fatal("Too many requests");
                    504:                                        requ[requests++] = atoi(cp);
                    505:                                } else {
                    506:                                        if (users >= MAXUSERS)
                    507:                                                fatal("Too many users");
                    508:                                        user[users++] = cp;
                    509:                                }
                    510:                        }
                    511:                        rmjob();
                    512:                        break;
                    513:                }
                    514:                fatal("Illegal service request");
                    515:        }
                    516: }
                    517:
                    518: /*
                    519:  * Make a pass through the printcap database and start printing any
                    520:  * files left from the last time the machine went down.
                    521:  */
1.4       cgd       522: static void
1.30      mjl       523: startup(void)
1.1       cgd       524: {
1.4       cgd       525:        char *buf;
1.13      mrg       526:        char *cp;
1.1       cgd       527:
                    528:        /*
                    529:         * Restart the daemons.
                    530:         */
1.4       cgd       531:        while (cgetnext(&buf, printcapdb) > 0) {
1.12      mrg       532:                if (ckqueue(buf) <= 0) {
                    533:                        free(buf);
                    534:                        continue;       /* no work to do for this printer */
                    535:                }
1.1       cgd       536:                for (cp = buf; *cp; cp++)
                    537:                        if (*cp == '|' || *cp == ':') {
                    538:                                *cp = '\0';
                    539:                                break;
                    540:                        }
1.12      mrg       541:                if (lflag)
                    542:                        syslog(LOG_INFO, "work for %s", buf);
1.18      mrg       543:                switch (fork()) {
                    544:                case -1:
1.1       cgd       545:                        syslog(LOG_WARNING, "startup: cannot fork");
1.4       cgd       546:                        mcleanup(0);
1.18      mrg       547:                case 0:
1.4       cgd       548:                        printer = buf;
1.18      mrg       549:                        setproctitle("working on printer %s", printer);
1.4       cgd       550:                        cgetclose();
1.1       cgd       551:                        printjob();
1.12      mrg       552:                        /* NOTREACHED */
1.18      mrg       553:                default:
                    554:                        child_count++;
                    555:                        free(buf);
1.1       cgd       556:                }
1.12      mrg       557:        }
                    558: }
                    559:
                    560: /*
                    561:  * Make sure there's some work to do before forking off a child
                    562:  */
                    563: static int
1.30      mjl       564: ckqueue(char *cap)
1.12      mrg       565: {
1.13      mrg       566:        struct dirent *d;
1.12      mrg       567:        DIR *dirp;
                    568:        char *spooldir;
                    569:
                    570:        if (cgetstr(cap, "sd", &spooldir) == -1)
                    571:                spooldir = _PATH_DEFSPOOL;
1.47      itojun    572:        if ((dirp = opendir(spooldir)) == NULL) {
                    573:                if (spooldir != _PATH_DEFSPOOL)
                    574:                        free(spooldir);
1.12      mrg       575:                return (-1);
1.47      itojun    576:        }
1.12      mrg       577:        while ((d = readdir(dirp)) != NULL) {
                    578:                if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
                    579:                        continue;       /* daemon control files only */
                    580:                closedir(dirp);
1.47      itojun    581:                if (spooldir != _PATH_DEFSPOOL)
                    582:                        free(spooldir);
1.12      mrg       583:                return (1);             /* found something */
1.1       cgd       584:        }
1.12      mrg       585:        closedir(dirp);
1.47      itojun    586:        if (spooldir != _PATH_DEFSPOOL)
                    587:                free(spooldir);
1.12      mrg       588:        return (0);
1.1       cgd       589: }
                    590:
                    591: #define DUMMY ":nobody::"
                    592:
                    593: /*
                    594:  * Check to see if the from host has access to the line printer.
                    595:  */
1.4       cgd       596: static void
1.30      mjl       597: chkhost(struct sockaddr *f, int check_opts)
1.1       cgd       598: {
1.20      itojun    599:        struct addrinfo hints, *res, *r;
1.13      mrg       600:        FILE *hostf;
1.38      itojun    601:        int good = 0;
1.20      itojun    602:        char host[NI_MAXHOST], ip[NI_MAXHOST];
                    603:        char serv[NI_MAXSERV];
                    604:        int error;
1.38      itojun    605: #ifdef LIBWRAP
                    606:        struct request_info req;
                    607: #endif
1.20      itojun    608:
                    609:        error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
                    610:                            NI_NUMERICSERV);
1.30      mjl       611:        if (error)
1.37      grant     612:                fatal("Malformed from address: %s", gai_strerror(error));
1.4       cgd       613:
1.30      mjl       614:          if (!(check_opts & LPD_NOPORTCHK) &&
                    615:               atoi(serv) >= IPPORT_RESERVED)
                    616:                fatal("Connect from invalid port (%s)", serv);
                    617:
1.4       cgd       618:        /* Need real hostname for temporary filenames */
1.20      itojun    619:        error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
                    620:                            NI_NAMEREQD);
                    621:        if (error) {
                    622:                error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
                    623:                                    NI_NUMERICHOST);
                    624:                if (error)
                    625:                        fatal("Host name for your address unknown");
                    626:                else
                    627:                        fatal("Host name for your address (%s) unknown", host);
                    628:        }
1.1       cgd       629:
1.45      itojun    630:        (void)strlcpy(fromb, host, sizeof(fromb));
1.1       cgd       631:        from = fromb;
                    632:
1.20      itojun    633:        /* need address in stringform for comparison (no DNS lookup here) */
                    634:        error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
                    635:                            NI_NUMERICHOST);
                    636:        if (error)
                    637:                fatal("Cannot print address");
                    638:
1.13      mrg       639:        /* Check for spoof, ala rlogind */
1.20      itojun    640:        memset(&hints, 0, sizeof(hints));
                    641:        hints.ai_family = PF_UNSPEC;
                    642:        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
                    643:        error = getaddrinfo(fromb, NULL, &hints, &res);
                    644:        if (error) {
                    645:                fatal("hostname for your address (%s) unknown: %s", host,
                    646:                    gai_strerror(error));
                    647:        }
                    648:        good = 0;
                    649:        for (r = res; good == 0 && r; r = r->ai_next) {
                    650:                error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip),
                    651:                                    NULL, 0, NI_NUMERICHOST);
                    652:                if (!error && !strcmp(host, ip))
1.13      mrg       653:                        good = 1;
                    654:        }
1.20      itojun    655:        if (res)
                    656:                freeaddrinfo(res);
1.13      mrg       657:        if (good == 0)
1.20      itojun    658:                fatal("address for your hostname (%s) not matched", host);
1.38      itojun    659:
1.18      mrg       660:        setproctitle("serving %s", from);
1.38      itojun    661:
                    662: #ifdef LIBWRAP
1.44      thorpej   663:        request_init(&req, RQ_DAEMON, "lpd", RQ_CLIENT_SIN, f,
                    664:            RQ_FILE, STDOUT_FILENO, NULL);
1.38      itojun    665:        fromhost(&req);
                    666:        if (!hosts_access(&req))
                    667:                goto denied;
                    668: #endif
                    669:
1.1       cgd       670:        hostf = fopen(_PATH_HOSTSEQUIV, "r");
                    671:        if (hostf) {
1.21      itojun    672:                if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
1.9       mrg       673:                        (void)fclose(hostf);
1.1       cgd       674:                        return;
                    675:                }
1.9       mrg       676:                (void)fclose(hostf);
1.1       cgd       677:        }
1.38      itojun    678:        hostf = fopen(_PATH_HOSTSLPD, "r");
                    679:        if (hostf) {
                    680:                if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
                    681:                        (void)fclose(hostf);
                    682:                        return;
                    683:                }
                    684:                (void)fclose(hostf);
1.1       cgd       685:        }
1.38      itojun    686: #ifdef LIBWRAP
                    687:   denied:
                    688: #endif
1.1       cgd       689:        fatal("Your host does not have line printer access");
1.4       cgd       690:        /*NOTREACHED*/
1.13      mrg       691: }
                    692:
1.30      mjl       693:
1.13      mrg       694: static void
1.30      mjl       695: usage(void)
1.13      mrg       696: {
                    697:
1.30      mjl       698:        fprintf(stderr, "usage: %s [-dlrsW] [-b bind-address] [-n maxchild] "
1.28      simonb    699:            "[-w maxwait] [port]\n", getprogname());
1.13      mrg       700:        exit(1);
1.20      itojun    701: }
                    702:
                    703: /* setup server socket for specified address family */
                    704: /* if af is PF_UNSPEC more than one socket may be returned */
                    705: /* the returned list is dynamically allocated, so caller needs to free it */
1.39      mycroft   706: struct pollfd *
                    707: socksetup(int af, int options, const char *port, int *nfds)
1.20      itojun    708: {
1.39      mycroft   709:        struct sockaddr_un un;
1.20      itojun    710:        struct addrinfo hints, *res, *r;
1.39      mycroft   711:        int error, s, blidx = 0, n;
1.48    ! itojun    712:        struct pollfd *socks, *newsocks;
1.20      itojun    713:        const int on = 1;
                    714:
1.39      mycroft   715:        *nfds = 0;
                    716:
1.48    ! itojun    717:        socks = malloc(1 * sizeof(socks[0]));
1.39      mycroft   718:        if (!socks) {
                    719:                syslog(LOG_ERR, "couldn't allocate memory for sockets");
                    720:                mcleanup(0);
                    721:        }
                    722:
                    723:        s = socket(AF_LOCAL, SOCK_STREAM, 0);
                    724:        if (s < 0) {
                    725:                syslog(LOG_ERR, "socket(): %m");
                    726:                exit(1);
                    727:        }
                    728:        memset(&un, 0, sizeof(un));
                    729:        un.sun_family = AF_LOCAL;
                    730:        strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1);
                    731:        un.sun_len = SUN_LEN(&un);
                    732:        (void)umask(07);
                    733:        (void)unlink(_PATH_SOCKETNAME);
                    734:        if (bind(s, (struct sockaddr *)&un, un.sun_len) < 0) {
                    735:                syslog(LOG_ERR, "bind(): %m");
                    736:                exit(1);
                    737:        }
                    738:        (void)umask(0);
                    739:        listen(s, 5);
                    740:        socks[*nfds].fd = s;
                    741:        socks[*nfds].events = POLLIN;
                    742:        (*nfds)++;
                    743:
                    744:        if (sflag && !blist_addrs)
                    745:                return (socks);
                    746:
1.23      scw       747:        do {
                    748:                memset(&hints, 0, sizeof(hints));
                    749:                hints.ai_flags = AI_PASSIVE;
                    750:                hints.ai_family = af;
                    751:                hints.ai_socktype = SOCK_STREAM;
                    752:                error = getaddrinfo((blist_addrs == 0) ? NULL : blist[blidx],
1.26      itojun    753:                    port ? port : "printer", &hints, &res);
1.23      scw       754:                if (error) {
                    755:                        if (blist_addrs)
                    756:                                syslog(LOG_ERR, "%s: %s", blist[blidx],
1.25      itojun    757:                                    gai_strerror(error));
1.23      scw       758:                        else
1.25      itojun    759:                                syslog(LOG_ERR, "%s", gai_strerror(error));
1.23      scw       760:                        mcleanup(0);
                    761:                }
1.20      itojun    762:
1.23      scw       763:                /* Count max number of sockets we may open */
1.39      mycroft   764:                for (r = res, n = 0; r; r = r->ai_next, n++)
1.23      scw       765:                        ;
1.48    ! itojun    766:                newsocks= realloc(socks, (*nfds + n) * sizeof(socks[0]));
        !           767:                if (!newsocks) {
1.23      scw       768:                        syslog(LOG_ERR, "couldn't allocate memory for sockets");
                    769:                        mcleanup(0);
1.20      itojun    770:                }
1.48    ! itojun    771:                socks = newsocks;
1.23      scw       772:
                    773:                for (r = res; r; r = r->ai_next) {
1.39      mycroft   774:                        s = socket(r->ai_family, r->ai_socktype,
                    775:                            r->ai_protocol);
                    776:                        if (s < 0) {
1.23      scw       777:                                syslog(LOG_DEBUG, "socket(): %m");
                    778:                                continue;
                    779:                        }
                    780:                        if (options & SO_DEBUG)
1.39      mycroft   781:                                if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
1.23      scw       782:                                               &on, sizeof(on)) < 0) {
                    783:                                        syslog(LOG_ERR,
                    784:                                               "setsockopt (SO_DEBUG): %m");
1.39      mycroft   785:                                        close(s);
1.23      scw       786:                                        continue;
                    787:                                }
1.39      mycroft   788:                        if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on,
1.38      itojun    789:                            sizeof(on)) < 0) {
                    790:                                syslog(LOG_ERR,
                    791:                                    "setsockopt (SO_REUSEPORT): %m");
1.43      itojun    792:                                close(s);
                    793:                                continue;
                    794:                        }
                    795:                        if (r->ai_family == AF_INET6 && setsockopt(s,
                    796:                            IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
                    797:                                syslog(LOG_ERR,
                    798:                                    "setsockopt (IPV6_V6ONLY): %m");
1.39      mycroft   799:                                close(s);
1.38      itojun    800:                                continue;
                    801:                        }
1.39      mycroft   802:                        if (bind(s, r->ai_addr, r->ai_addrlen) < 0) {
1.23      scw       803:                                syslog(LOG_DEBUG, "bind(): %m");
1.39      mycroft   804:                                close(s);
1.20      itojun    805:                                continue;
                    806:                        }
1.39      mycroft   807:                        listen(s, 5);
                    808:                        socks[*nfds].fd = s;
                    809:                        socks[*nfds].events = POLLIN;
                    810:                        (*nfds)++;
1.20      itojun    811:                }
                    812:
1.23      scw       813:                if (res)
                    814:                        freeaddrinfo(res);
                    815:        } while (++blidx < blist_addrs);
1.20      itojun    816:
1.39      mycroft   817:        return (socks);
1.1       cgd       818: }

CVSweb <webmaster@jp.NetBSD.org>