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