# 2.11BSD#431 - /usr/src/usr.sbin/lpr/lpd.c

##### Functions

    chkhost           X
    doit              X
    main              X
    mcleanup          X
    reapchild         X
    startup           X
    unpause           X

##### Variables

    cbuf              X
    cmdnames          X
    copyright         X
    fromb             X
    lflag             X
    person            X
    requ              X
    requests          X
    unblock           X
    user              X
    users             X

##### Macros

    DUMMY             X

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

#### Defined functions

chkhost defined in line 398; used 1 times

- in line 216

doit defined in line 265; used 1 times

- in line 217

main defined in line 52; never used
mcleanup defined in line 232; used 9 times

- in line 49, 144-147(4), 164-169(2), 175, 383

reapchild defined in line 224; used 2 times

- in line 48, 120

startup defined in line 364; used 2 times

- in line 124, 134

unpause defined in line 240; used 2 times

- in line 50, 130

#### Defined variables

cbuf defined in line 255; used 5 times

- in line 271-273(3), 282, 323

cmdnames defined in line 256; used 1 times

- in line 286

copyright defined in line 8; never used
fromb defined in line 254; used 4 times

- in line 417-427(4)

lflag defined in line 46; used 3 times

- in line 74, 234, 283

person defined in line 252; used 1 times

- in line 332

requ defined in line 250; used 2 times

- in line 316, 346

requests defined in line 251; used 4 times

- in line 314-316(2), 344-346(2)

sccsid defined in line 12; never used
unblock defined in line 50; used 3 times

- in line 133-135(2), 242

user defined in line 248; used 2 times

- in line 320, 350

users defined in line 249; used 4 times

- in line 318-320(2), 348-350(2)

#### Defined macros

DUMMY defined in line 393; used 2 times

- in line 437(2)

Last modified: 1994-01-11 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2065 |