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