|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.