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