|
|
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.