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

unix.superglobalmegacorp.com

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