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