lpd.c revision 1.22.4.2 1 /* $NetBSD: lpd.c,v 1.22.4.2 2001/10/26 18:04:35 jhawk Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38
39 #ifndef lint
40 __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\
41 The Regents of the University of California. All rights reserved.\n");
42 #endif /* not lint */
43
44 #ifndef lint
45 #if 0
46 static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
47 #else
48 __RCSID("$NetBSD: lpd.c,v 1.22.4.2 2001/10/26 18:04:35 jhawk Exp $");
49 #endif
50 #endif /* not lint */
51
52 /*
53 * lpd -- line printer daemon.
54 *
55 * Listen for a connection and perform the requested operation.
56 * Operations are:
57 * \1printer\n
58 * check the queue for jobs and print any found.
59 * \2printer\n
60 * receive a job from another machine and queue it.
61 * \3printer [users ...] [jobs ...]\n
62 * return the current state of the queue (short form).
63 * \4printer [users ...] [jobs ...]\n
64 * return the current state of the queue (long form).
65 * \5printer person [users ...] [jobs ...]\n
66 * remove jobs from the queue.
67 *
68 * Strategy to maintain protected spooling area:
69 * 1. Spooling area is writable only by daemon and spooling group
70 * 2. lpr runs setuid root and setgrp spooling group; it uses
71 * root to access any file it wants (verifying things before
72 * with an access call) and group id to know how it should
73 * set up ownership of files in the spooling area.
74 * 3. Files in spooling area are owned by root, group spooling
75 * group, with mode 660.
76 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
77 * access files and printer. Users can't get to anything
78 * w/o help of lpq and lprm programs.
79 */
80
81 #include <sys/param.h>
82 #include <sys/wait.h>
83 #include <sys/types.h>
84 #include <sys/socket.h>
85 #include <sys/un.h>
86 #include <sys/stat.h>
87 #include <sys/file.h>
88 #include <netinet/in.h>
89
90 #include <err.h>
91 #include <netdb.h>
92 #include <unistd.h>
93 #include <syslog.h>
94 #include <signal.h>
95 #include <errno.h>
96 #include <fcntl.h>
97 #include <dirent.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <ctype.h>
102 #include <arpa/inet.h>
103
104 #include "lp.h"
105 #include "lp.local.h"
106 #include "pathnames.h"
107 #include "extern.h"
108
109 /* XXX from libc/net/rcmd.c */
110 extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t,
111 const char *, const char *));
112
113 int lflag; /* log requests flag */
114 int rflag; /* allow of for remote printers */
115 int sflag; /* secure (no inet) flag */
116 int from_remote; /* from remote socket */
117
118 int main __P((int, char **));
119 static void reapchild __P((int));
120 static void mcleanup __P((int));
121 static void doit __P((void));
122 static void startup __P((void));
123 static void chkhost __P((struct sockaddr *));
124 static int ckqueue __P((char *));
125 static void usage __P((void));
126 static int *socksetup __P((int, int));
127
128 uid_t uid, euid;
129 int child_count;
130
131 int
132 main(argc, argv)
133 int argc;
134 char **argv;
135 {
136 fd_set defreadfds;
137 struct sockaddr_un un, fromunix;
138 struct sockaddr_storage frominet;
139 sigset_t nmask, omask;
140 int lfd, errs, i, f, funix, *finet;
141 int child_max = 32; /* more then enough to hose the system */
142 int options = 0;
143 struct servent *sp, serv;
144
145 euid = geteuid(); /* these shouldn't be different */
146 uid = getuid();
147 gethostname(host, sizeof(host));
148 host[sizeof(host) - 1] = '\0';
149 name = argv[0];
150
151 errs = 0;
152 while ((i = getopt(argc, argv, "dln:srw:")) != -1)
153 switch (i) {
154 case 'd':
155 options |= SO_DEBUG;
156 break;
157 case 'l':
158 lflag++;
159 break;
160 case 'n':
161 child_max = atoi(optarg);
162 if (child_max < 0 || child_max > 1024)
163 errx(1, "invalid number of children: %s",
164 optarg);
165 break;
166 case 'r':
167 rflag++;
168 break;
169 case 's':
170 sflag++;
171 break;
172 case 'w':
173 wait_time = atoi(optarg);
174 if (wait_time < 0)
175 errx(1, "wait time must be postive: %s",
176 optarg);
177 if (wait_time < 30)
178 warnx("warning: wait time less than 30 seconds");
179 break;
180 default:
181 errs++;
182 }
183 argc -= optind;
184 argv += optind;
185 if (errs)
186 usage();
187
188 switch (argc) {
189 case 1:
190 if ((i = atoi(argv[0])) == 0)
191 usage();
192 if (i < 0 || i > USHRT_MAX)
193 errx(1, "port # %d is invalid", i);
194
195 serv.s_port = htons(i);
196 sp = &serv;
197 break;
198 case 0:
199 sp = getservbyname("printer", "tcp");
200 if (sp == NULL)
201 errx(1, "printer/tcp: unknown service");
202 break;
203 default:
204 usage();
205 }
206
207 #ifndef DEBUG
208 /*
209 * Set up standard environment by detaching from the parent.
210 */
211 daemon(0, 0);
212 #endif
213
214 openlog("lpd", LOG_PID, LOG_LPR);
215 syslog(LOG_INFO, "restarted");
216 (void)umask(0);
217 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
218 if (lfd < 0) {
219 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
220 exit(1);
221 }
222 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
223 if (errno == EWOULDBLOCK) /* active deamon present */
224 exit(0);
225 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
226 exit(1);
227 }
228 ftruncate(lfd, 0);
229 /*
230 * write process id for others to know
231 */
232 (void)snprintf(line, sizeof(line), "%u\n", getpid());
233 f = strlen(line);
234 if (write(lfd, line, f) != f) {
235 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
236 exit(1);
237 }
238 signal(SIGCHLD, reapchild);
239 /*
240 * Restart all the printers.
241 */
242 startup();
243 (void)unlink(_PATH_SOCKETNAME);
244 funix = socket(AF_LOCAL, SOCK_STREAM, 0);
245 if (funix < 0) {
246 syslog(LOG_ERR, "socket: %m");
247 exit(1);
248 }
249
250 sigemptyset(&nmask);
251 sigaddset(&nmask, SIGHUP);
252 sigaddset(&nmask, SIGINT);
253 sigaddset(&nmask, SIGQUIT);
254 sigaddset(&nmask, SIGTERM);
255 sigprocmask(SIG_BLOCK, &nmask, &omask);
256
257 (void) umask(07);
258 signal(SIGHUP, mcleanup);
259 signal(SIGINT, mcleanup);
260 signal(SIGQUIT, mcleanup);
261 signal(SIGTERM, mcleanup);
262 memset(&un, 0, sizeof(un));
263 un.sun_family = AF_LOCAL;
264 strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1);
265 #ifndef SUN_LEN
266 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
267 #endif
268 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
269 syslog(LOG_ERR, "ubind: %m");
270 exit(1);
271 }
272 (void) umask(0);
273 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
274 FD_ZERO(&defreadfds);
275 FD_SET(funix, &defreadfds);
276 listen(funix, 5);
277 if (!sflag)
278 finet = socksetup(PF_UNSPEC, options);
279 else
280 finet = NULL; /* pretend we couldn't open TCP socket. */
281
282 if (finet) {
283 for (i = 1; i <= *finet; i++) {
284 FD_SET(finet[i], &defreadfds);
285 listen(finet[i], 5);
286 }
287 }
288 /*
289 * Main loop: accept, do a request, continue.
290 */
291 memset(&frominet, 0, sizeof(frominet));
292 memset(&fromunix, 0, sizeof(fromunix));
293 for (;;) {
294 int domain, nfds, s, fromlen;
295 fd_set readfds;
296 /* "short" so it overflows in about 2 hours */
297 short sleeptime = 10;
298
299 while (child_max < child_count) {
300 syslog(LOG_WARNING,
301 "too many children, sleeping for %d seconds",
302 sleeptime);
303 sleep(sleeptime);
304 sleeptime <<= 1;
305 if (sleeptime < 0) {
306 syslog(LOG_CRIT, "sleeptime overflowed! help!");
307 sleeptime = 10;
308 }
309 }
310
311 FD_COPY(&defreadfds, &readfds);
312 nfds = select(20, &readfds, 0, 0, 0);
313 if (nfds <= 0) {
314 if (nfds < 0 && errno != EINTR)
315 syslog(LOG_WARNING, "select: %m");
316 continue;
317 }
318 if (FD_ISSET(funix, &readfds)) {
319 domain = AF_LOCAL;
320 fromlen = sizeof(fromunix);
321 s = accept(funix,
322 (struct sockaddr *)&fromunix, &fromlen);
323 } else {
324 for (i = 1; i <= *finet; i++)
325 if (FD_ISSET(finet[i], &readfds)) {
326 domain = AF_INET, fromlen = sizeof(frominet);
327 s = accept(finet[i], (struct sockaddr *)&frominet, &fromlen);
328 }
329 }
330 if (s < 0) {
331 if (errno != EINTR)
332 syslog(LOG_WARNING, "accept: %m");
333 continue;
334 }
335
336 switch (fork()) {
337 case 0:
338 signal(SIGCHLD, SIG_IGN);
339 signal(SIGHUP, SIG_IGN);
340 signal(SIGINT, SIG_IGN);
341 signal(SIGQUIT, SIG_IGN);
342 signal(SIGTERM, SIG_IGN);
343 (void)close(funix);
344 if (!sflag && finet)
345 for (i = 1; i <= *finet; i++)
346 (void)close(finet[i]);
347 dup2(s, 1);
348 (void)close(s);
349 if (domain == AF_INET) {
350 /* for both AF_INET and AF_INET6 */
351 from_remote = 1;
352 chkhost((struct sockaddr *)&frominet);
353 } else
354 from_remote = 0;
355 doit();
356 exit(0);
357 case -1:
358 syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds...");
359 sleep(10);
360 continue;
361 default:
362 child_count++;
363 }
364 (void)close(s);
365 }
366 }
367
368 static void
369 reapchild(signo)
370 int signo;
371 {
372 union wait status;
373
374 while (wait3((int *)&status, WNOHANG, 0) > 0)
375 child_count--;
376 }
377
378 static void
379 mcleanup(signo)
380 int signo;
381 {
382 if (lflag)
383 syslog(LOG_INFO, "exiting");
384 unlink(_PATH_SOCKETNAME);
385 exit(0);
386 }
387
388 /*
389 * Stuff for handling job specifications
390 */
391 char *user[MAXUSERS]; /* users to process */
392 int users; /* # of users in user array */
393 int requ[MAXREQUESTS]; /* job number of spool entries */
394 int requests; /* # of spool requests */
395 char *person; /* name of person doing lprm */
396
397 char fromb[NI_MAXHOST]; /* buffer for client's machine name */
398 char cbuf[BUFSIZ]; /* command line buffer */
399 char *cmdnames[] = {
400 "null",
401 "printjob",
402 "recvjob",
403 "displayq short",
404 "displayq long",
405 "rmjob"
406 };
407
408 static void
409 doit()
410 {
411 char *cp;
412 int n;
413
414 for (;;) {
415 cp = cbuf;
416 do {
417 if (cp >= &cbuf[sizeof(cbuf) - 1])
418 fatal("Command line too long");
419 if ((n = read(1, cp, 1)) != 1) {
420 if (n < 0)
421 fatal("Lost connection");
422 return;
423 }
424 } while (*cp++ != '\n');
425 *--cp = '\0';
426 cp = cbuf;
427 if (lflag) {
428 if (*cp >= '\1' && *cp <= '\5') {
429 syslog(LOG_INFO, "%s requests %s %s",
430 from, cmdnames[(int)*cp], cp+1);
431 setproctitle("serving %s: %s %s", from,
432 cmdnames[(int)*cp], cp+1);
433 }
434 else
435 syslog(LOG_INFO, "bad request (%d) from %s",
436 *cp, from);
437 }
438 switch (*cp++) {
439 case '\1': /* check the queue and print any jobs there */
440 printer = cp;
441 if (*printer == '\0')
442 printer = DEFLP;
443 printjob();
444 break;
445 case '\2': /* receive files to be queued */
446 if (!from_remote) {
447 syslog(LOG_INFO, "illegal request (%d)", *cp);
448 exit(1);
449 }
450 printer = cp;
451 if (*printer == '\0')
452 printer = DEFLP;
453 recvjob();
454 break;
455 case '\3': /* display the queue (short form) */
456 case '\4': /* display the queue (long form) */
457 printer = cp;
458 if (*printer == '\0')
459 printer = DEFLP;
460 while (*cp) {
461 if (*cp != ' ') {
462 cp++;
463 continue;
464 }
465 *cp++ = '\0';
466 while (isspace(*cp))
467 cp++;
468 if (*cp == '\0')
469 break;
470 if (isdigit(*cp)) {
471 if (requests >= MAXREQUESTS)
472 fatal("Too many requests");
473 requ[requests++] = atoi(cp);
474 } else {
475 if (users >= MAXUSERS)
476 fatal("Too many users");
477 user[users++] = cp;
478 }
479 }
480 displayq(cbuf[0] - '\3');
481 exit(0);
482 case '\5': /* remove a job from the queue */
483 if (!from_remote) {
484 syslog(LOG_INFO, "illegal request (%d)", *cp);
485 exit(1);
486 }
487 printer = cp;
488 if (*printer == '\0')
489 printer = DEFLP;
490 while (*cp && *cp != ' ')
491 cp++;
492 if (!*cp)
493 break;
494 *cp++ = '\0';
495 person = cp;
496 while (*cp) {
497 if (*cp != ' ') {
498 cp++;
499 continue;
500 }
501 *cp++ = '\0';
502 while (isspace(*cp))
503 cp++;
504 if (*cp == '\0')
505 break;
506 if (isdigit(*cp)) {
507 if (requests >= MAXREQUESTS)
508 fatal("Too many requests");
509 requ[requests++] = atoi(cp);
510 } else {
511 if (users >= MAXUSERS)
512 fatal("Too many users");
513 user[users++] = cp;
514 }
515 }
516 rmjob();
517 break;
518 }
519 fatal("Illegal service request");
520 }
521 }
522
523 /*
524 * Make a pass through the printcap database and start printing any
525 * files left from the last time the machine went down.
526 */
527 static void
528 startup()
529 {
530 char *buf;
531 char *cp;
532
533 /*
534 * Restart the daemons.
535 */
536 while (cgetnext(&buf, printcapdb) > 0) {
537 if (ckqueue(buf) <= 0) {
538 free(buf);
539 continue; /* no work to do for this printer */
540 }
541 for (cp = buf; *cp; cp++)
542 if (*cp == '|' || *cp == ':') {
543 *cp = '\0';
544 break;
545 }
546 if (lflag)
547 syslog(LOG_INFO, "work for %s", buf);
548 switch (fork()) {
549 case -1:
550 syslog(LOG_WARNING, "startup: cannot fork");
551 mcleanup(0);
552 case 0:
553 printer = buf;
554 setproctitle("working on printer %s", printer);
555 cgetclose();
556 printjob();
557 /* NOTREACHED */
558 default:
559 child_count++;
560 free(buf);
561 }
562 }
563 }
564
565 /*
566 * Make sure there's some work to do before forking off a child
567 */
568 static int
569 ckqueue(cap)
570 char *cap;
571 {
572 struct dirent *d;
573 DIR *dirp;
574 char *spooldir;
575
576 if (cgetstr(cap, "sd", &spooldir) == -1)
577 spooldir = _PATH_DEFSPOOL;
578 if ((dirp = opendir(spooldir)) == NULL)
579 return (-1);
580 while ((d = readdir(dirp)) != NULL) {
581 if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
582 continue; /* daemon control files only */
583 closedir(dirp);
584 return (1); /* found something */
585 }
586 closedir(dirp);
587 return (0);
588 }
589
590 #define DUMMY ":nobody::"
591
592 /*
593 * Check to see if the from host has access to the line printer.
594 */
595 static void
596 chkhost(f)
597 struct sockaddr *f;
598 {
599 struct addrinfo hints, *res, *r;
600 FILE *hostf;
601 int first = 1, good = 0;
602 char host[NI_MAXHOST], ip[NI_MAXHOST];
603 char serv[NI_MAXSERV];
604 int error;
605
606 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
607 NI_NUMERICSERV);
608 if (error || atoi(serv) >= IPPORT_RESERVED)
609 fatal("Malformed from address");
610
611 /* Need real hostname for temporary filenames */
612 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
613 NI_NAMEREQD);
614 if (error) {
615 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
616 NI_NUMERICHOST);
617 if (error)
618 fatal("Host name for your address unknown");
619 else
620 fatal("Host name for your address (%s) unknown", host);
621 }
622
623 (void)strncpy(fromb, host, sizeof(fromb) - 1);
624 fromb[sizeof(fromb) - 1] = '\0';
625 from = fromb;
626
627 /* need address in stringform for comparison (no DNS lookup here) */
628 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0,
629 NI_NUMERICHOST);
630 if (error)
631 fatal("Cannot print address");
632
633 /* Check for spoof, ala rlogind */
634 memset(&hints, 0, sizeof(hints));
635 hints.ai_family = PF_UNSPEC;
636 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
637 error = getaddrinfo(fromb, NULL, &hints, &res);
638 if (error) {
639 fatal("hostname for your address (%s) unknown: %s", host,
640 gai_strerror(error));
641 }
642 good = 0;
643 for (r = res; good == 0 && r; r = r->ai_next) {
644 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip),
645 NULL, 0, NI_NUMERICHOST);
646 if (!error && !strcmp(host, ip))
647 good = 1;
648 }
649 if (res)
650 freeaddrinfo(res);
651 if (good == 0)
652 fatal("address for your hostname (%s) not matched", host);
653 setproctitle("serving %s", from);
654 hostf = fopen(_PATH_HOSTSEQUIV, "r");
655 again:
656 if (hostf) {
657 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
658 (void)fclose(hostf);
659 return;
660 }
661 (void)fclose(hostf);
662 }
663 if (first == 1) {
664 first = 0;
665 hostf = fopen(_PATH_HOSTSLPD, "r");
666 goto again;
667 }
668 fatal("Your host does not have line printer access");
669 /*NOTREACHED*/
670 }
671
672 static void
673 usage()
674 {
675 extern char *__progname; /* XXX */
676
677 fprintf(stderr, "usage: %s [-dlrs] [-n maxchild] [-w maxwait] [port]\n",
678 __progname);
679 exit(1);
680 }
681
682 /* setup server socket for specified address family */
683 /* if af is PF_UNSPEC more than one socket may be returned */
684 /* the returned list is dynamically allocated, so caller needs to free it */
685 int *
686 socksetup(af, options)
687 int af, options;
688 {
689 struct addrinfo hints, *res, *r;
690 int error, maxs, *s, *socks;
691 const int on = 1;
692
693 memset(&hints, 0, sizeof(hints));
694 hints.ai_flags = AI_PASSIVE;
695 hints.ai_family = af;
696 hints.ai_socktype = SOCK_STREAM;
697 error = getaddrinfo(NULL, "printer", &hints, &res);
698 if (error) {
699 syslog(LOG_ERR, "%s", gai_strerror(error));
700 mcleanup(0);
701 }
702
703 /* Count max number of sockets we may open */
704 for (maxs = 0, r = res; r; r = r->ai_next, maxs++)
705 ;
706 socks = malloc((maxs + 1) * sizeof(int));
707 if (!socks) {
708 syslog(LOG_ERR, "couldn't allocate memory for sockets");
709 mcleanup(0);
710 }
711
712 *socks = 0; /* num of sockets counter at start of array */
713 s = socks + 1;
714 for (r = res; r; r = r->ai_next) {
715 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
716 if (*s < 0) {
717 syslog(LOG_DEBUG, "socket(): %m");
718 continue;
719 }
720 if (options & SO_DEBUG)
721 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG,
722 &on, sizeof(on)) < 0) {
723 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
724 close (*s);
725 continue;
726 }
727 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
728 syslog(LOG_DEBUG, "bind(): %m");
729 close (*s);
730 continue;
731 }
732 *socks = *socks + 1;
733 s++;
734 }
735
736 if (res)
737 freeaddrinfo(res);
738
739 if (*socks == 0) {
740 syslog(LOG_ERR, "Couldn't bind to any socket");
741 free(socks);
742 mcleanup(0);
743 }
744 return(socks);
745 }
746