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