home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / lpr / lpd / lpd.c,v < prev    next >
Encoding:
Text File  |  1994-05-23  |  11.4 KB  |  493 lines

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