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