1 /* $NetBSD: lpd.c,v 1.54 2006/01/18 23:17:38 garbled Exp $ */
4 * Copyright (c) 1983, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
36 __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\
37 The Regents of the University of California. All rights reserved.");
42 static char sccsid
[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
44 __RCSID("$NetBSD: lpd.c,v 1.54 2006/01/18 23:17:38 garbled Exp $");
49 * lpd -- line printer daemon.
51 * Listen for a connection and perform the requested operation.
54 * check the queue for jobs and print any found.
56 * receive a job from another machine and queue it.
57 * \3printer [users ...] [jobs ...]\n
58 * return the current state of the queue (short form).
59 * \4printer [users ...] [jobs ...]\n
60 * return the current state of the queue (long form).
61 * \5printer person [users ...] [jobs ...]\n
62 * remove jobs from the queue.
64 * Strategy to maintain protected spooling area:
65 * 1. Spooling area is writable only by daemon and spooling group
66 * 2. lpr runs setuid root and setgrp spooling group; it uses
67 * root to access any file it wants (verifying things before
68 * with an access call) and group id to know how it should
69 * set up ownership of files in the spooling area.
70 * 3. Files in spooling area are owned by root, group spooling
71 * group, with mode 660.
72 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to
73 * access files and printer. Users can't get to anything
74 * w/o help of lpq and lprm programs.
77 #include <sys/param.h>
79 #include <sys/types.h>
80 #include <sys/socket.h>
85 #include <netinet/in.h>
100 #include <arpa/inet.h>
107 #include "lp.local.h"
108 #include "pathnames.h"
111 /* XXX from libc/net/rcmd.c */
112 extern int __ivaliduser_sa(FILE *, const struct sockaddr
*, socklen_t
,
113 const char *, const char *);
116 int allow_severity
= LOG_AUTH
|LOG_INFO
;
117 int deny_severity
= LOG_AUTH
|LOG_WARNING
;
120 int lflag
; /* log requests flag */
121 int rflag
; /* allow of for remote printers */
122 int sflag
; /* secure (no inet) flag */
123 int from_remote
; /* from remote socket */
124 char **blist
; /* list of addresses to bind(2) to */
128 int main(int, char **);
129 static void reapchild(int);
130 static void mcleanup(int);
131 static void doit(void);
132 static void startup(void);
133 static void chkhost(struct sockaddr
*, int);
134 static void usage(void);
135 static struct pollfd
*socksetup(int, int, const char *, int *);
140 #define LPD_NOPORTCHK 0001 /* skip reserved-port check */
143 main(int argc
, char **argv
)
145 struct sockaddr_storage frm
;
147 sigset_t nmask
, omask
;
148 int lfd
, errs
, i
, f
, nfds
;
149 struct pollfd
*socks
;
150 int child_max
= 32; /* more than enough to hose the system */
151 int options
= 0, check_options
= 0;
153 const char *port
= "printer";
156 euid
= geteuid(); /* these shouldn't be different */
158 gethostname(host
, sizeof(host
));
159 host
[sizeof(host
) - 1] = '\0';
163 while ((i
= getopt(argc
, argv
, "b:dln:srw:W")) != -1)
166 if (blist_addrs
>= blist_size
) {
167 newblist
= realloc(blist
,
168 blist_size
+ sizeof(char *) * 4);
169 if (newblist
== NULL
)
170 err(1, "cant allocate bind addr list");
172 blist_size
+= sizeof(char *) * 4;
174 blist
[blist_addrs
++] = strdup(optarg
);
183 child_max
= atoi(optarg
);
184 if (child_max
< 0 || child_max
> 1024)
185 errx(1, "invalid number of children: %s",
195 wait_time
= atoi(optarg
);
197 errx(1, "wait time must be postive: %s",
200 warnx("warning: wait time less than 30 seconds");
202 case 'W':/* allow connections coming from a non-reserved port */
203 /* (done by some lpr-implementations for MS-Windows) */
204 check_options
|= LPD_NOPORTCHK
;
216 if ((i
= atoi(argv
[0])) == 0)
218 if (i
< 0 || i
> USHRT_MAX
)
219 errx(1, "port # %d is invalid", i
);
224 sp
= getservbyname(port
, "tcp");
226 errx(1, "%s/tcp: unknown service", port
);
234 * Set up standard environment by detaching from the parent.
239 openlog("lpd", LOG_PID
, LOG_LPR
);
240 syslog(LOG_INFO
, "restarted");
242 lfd
= open(_PATH_MASTERLOCK
, O_WRONLY
|O_CREAT
, 0644);
244 syslog(LOG_ERR
, "%s: %m", _PATH_MASTERLOCK
);
247 if (flock(lfd
, LOCK_EX
|LOCK_NB
) < 0) {
248 if (errno
== EWOULDBLOCK
) { /* active daemon present */
249 syslog(LOG_ERR
, "%s is locked; another lpd is running",
253 syslog(LOG_ERR
, "%s: %m", _PATH_MASTERLOCK
);
258 * write process id for others to know
260 (void)snprintf(line
, sizeof(line
), "%u\n", getpid());
262 if (write(lfd
, line
, f
) != f
) {
263 syslog(LOG_ERR
, "%s: %m", _PATH_MASTERLOCK
);
266 signal(SIGCHLD
, reapchild
);
268 * Restart all the printers.
273 sigaddset(&nmask
, SIGHUP
);
274 sigaddset(&nmask
, SIGINT
);
275 sigaddset(&nmask
, SIGQUIT
);
276 sigaddset(&nmask
, SIGTERM
);
277 sigprocmask(SIG_BLOCK
, &nmask
, &omask
);
279 signal(SIGHUP
, mcleanup
);
280 signal(SIGINT
, mcleanup
);
281 signal(SIGQUIT
, mcleanup
);
282 signal(SIGTERM
, mcleanup
);
284 socks
= socksetup(PF_UNSPEC
, options
, port
, &nfds
);
286 sigprocmask(SIG_SETMASK
, &omask
, (sigset_t
*)0);
289 for (i
= 0; i
< blist_addrs
; i
++)
295 * Main loop: accept, do a request, continue.
297 memset(&frm
, 0, sizeof(frm
));
300 /* "short" so it overflows in about 2 hours */
301 struct timespec sleeptime
= {10, 0};
303 while (child_max
< child_count
) {
305 "too many children, sleeping for %ld seconds",
306 (long)sleeptime
.tv_sec
);
307 nanosleep(&sleeptime
, NULL
);
308 sleeptime
.tv_sec
<<= 1;
309 if (sleeptime
.tv_sec
<= 0) {
310 syslog(LOG_CRIT
, "sleeptime overflowed! help!");
311 sleeptime
.tv_sec
= 10;
315 rv
= poll(socks
, nfds
, INFTIM
);
317 if (rv
< 0 && errno
!= EINTR
)
318 syslog(LOG_WARNING
, "poll: %m");
322 for (i
= 0; i
< nfds
; i
++)
323 if (socks
[i
].revents
& POLLIN
) {
324 frmlen
= sizeof(frm
);
325 s
= accept(socks
[i
].fd
,
326 (struct sockaddr
*)&frm
, &frmlen
);
331 syslog(LOG_WARNING
, "accept: %m");
337 signal(SIGCHLD
, SIG_DFL
);
338 signal(SIGHUP
, SIG_IGN
);
339 signal(SIGINT
, SIG_IGN
);
340 signal(SIGQUIT
, SIG_IGN
);
341 signal(SIGTERM
, SIG_IGN
);
342 for (i
= 0; i
< nfds
; i
++)
343 (void)close(socks
[i
].fd
);
344 dup2(s
, STDOUT_FILENO
);
346 if (frm
.ss_family
!= AF_LOCAL
) {
347 /* for both AF_INET and AF_INET6 */
349 chkhost((struct sockaddr
*)&frm
, check_options
);
355 syslog(LOG_WARNING
, "fork: %m, sleeping for 10 seconds...");
370 while (wait3((int *)&status
, WNOHANG
, 0) > 0)
378 syslog(LOG_INFO
, "exiting");
379 unlink(_PATH_SOCKETNAME
);
384 * Stuff for handling job specifications
386 char *user
[MAXUSERS
]; /* users to process */
387 int users
; /* # of users in user array */
388 int requ
[MAXREQUESTS
]; /* job number of spool entries */
389 int requests
; /* # of spool requests */
390 char *person
; /* name of person doing lprm */
392 char fromb
[NI_MAXHOST
]; /* buffer for client's machine name */
393 char cbuf
[BUFSIZ
]; /* command line buffer */
394 const char *cmdnames
[] = {
412 if (cp
>= &cbuf
[sizeof(cbuf
) - 1])
413 fatal("Command line too long");
414 if ((n
= read(STDOUT_FILENO
, cp
, 1)) != 1) {
416 fatal("Lost connection");
419 } while (*cp
++ != '\n');
423 if (*cp
>= '\1' && *cp
<= '\5') {
424 syslog(LOG_INFO
, "%s requests %s %s",
425 from
, cmdnames
[(int)*cp
], cp
+1);
426 setproctitle("serving %s: %s %s", from
,
427 cmdnames
[(int)*cp
], cp
+1);
430 syslog(LOG_INFO
, "bad request (%d) from %s",
434 case '\1': /* check the queue and print any jobs there */
436 if (*printer
== '\0')
440 case '\2': /* receive files to be queued */
442 syslog(LOG_INFO
, "illegal request (%d)", *cp
);
446 if (*printer
== '\0')
450 case '\3': /* display the queue (short form) */
451 case '\4': /* display the queue (long form) */
453 if (*printer
== '\0')
461 while (isspace((unsigned char)*cp
))
465 if (isdigit((unsigned char)*cp
)) {
466 if (requests
>= MAXREQUESTS
)
467 fatal("Too many requests");
468 requ
[requests
++] = atoi(cp
);
470 if (users
>= MAXUSERS
)
471 fatal("Too many users");
475 displayq(cbuf
[0] - '\3');
477 case '\5': /* remove a job from the queue */
479 syslog(LOG_INFO
, "illegal request (%d)", *cp
);
483 if (*printer
== '\0')
485 while (*cp
&& *cp
!= ' ')
497 while (isspace((unsigned char)*cp
))
501 if (isdigit((unsigned char)*cp
)) {
502 if (requests
>= MAXREQUESTS
)
503 fatal("Too many requests");
504 requ
[requests
++] = atoi(cp
);
506 if (users
>= MAXUSERS
)
507 fatal("Too many users");
514 fatal("Illegal service request");
519 * Make a pass through the printcap database and start printing any
520 * files left from the last time the machine went down.
529 * Restart the daemons.
531 while (cgetnext(&buf
, printcapdb
) > 0) {
532 if (ckqueue(buf
) <= 0) {
534 continue; /* no work to do for this printer */
536 for (cp
= buf
; *cp
; cp
++)
537 if (*cp
== '|' || *cp
== ':') {
542 syslog(LOG_INFO
, "work for %s", buf
);
545 syslog(LOG_WARNING
, "startup: cannot fork");
549 setproctitle("working on printer %s", printer
);
560 #define DUMMY ":nobody::"
563 * Check to see if the from host has access to the line printer.
566 chkhost(struct sockaddr
*f
, int check_opts
)
568 struct addrinfo hints
, *res
, *r
;
571 char hst
[NI_MAXHOST
], ip
[NI_MAXHOST
];
572 char serv
[NI_MAXSERV
];
575 struct request_info req
;
578 error
= getnameinfo(f
, f
->sa_len
, NULL
, 0, serv
, sizeof(serv
),
581 fatal("Malformed from address: %s", gai_strerror(error
));
583 if (!(check_opts
& LPD_NOPORTCHK
) &&
584 atoi(serv
) >= IPPORT_RESERVED
)
585 fatal("Connect from invalid port (%s)", serv
);
587 /* Need real hostname for temporary filenames */
588 error
= getnameinfo(f
, f
->sa_len
, hst
, sizeof(hst
), NULL
, 0,
591 error
= getnameinfo(f
, f
->sa_len
, hst
, sizeof(hst
), NULL
, 0,
594 fatal("Host name for your address unknown");
596 fatal("Host name for your address (%s) unknown", hst
);
599 (void)strlcpy(fromb
, hst
, sizeof(fromb
));
602 /* need address in stringform for comparison (no DNS lookup here) */
603 error
= getnameinfo(f
, f
->sa_len
, hst
, sizeof(hst
), NULL
, 0,
606 fatal("Cannot print address");
608 /* Check for spoof, ala rlogind */
609 memset(&hints
, 0, sizeof(hints
));
610 hints
.ai_family
= PF_UNSPEC
;
611 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
612 error
= getaddrinfo(fromb
, NULL
, &hints
, &res
);
614 fatal("hostname for your address (%s) unknown: %s", hst
,
615 gai_strerror(error
));
618 for (r
= res
; good
== 0 && r
; r
= r
->ai_next
) {
619 error
= getnameinfo(r
->ai_addr
, r
->ai_addrlen
, ip
, sizeof(ip
),
620 NULL
, 0, NI_NUMERICHOST
);
621 if (!error
&& !strcmp(hst
, ip
))
627 fatal("address for your hostname (%s) not matched", hst
);
629 setproctitle("serving %s", from
);
632 request_init(&req
, RQ_DAEMON
, "lpd", RQ_CLIENT_SIN
, f
,
633 RQ_FILE
, STDOUT_FILENO
, NULL
);
635 if (!hosts_access(&req
))
639 hostf
= fopen(_PATH_HOSTSEQUIV
, "r");
641 if (__ivaliduser_sa(hostf
, f
, f
->sa_len
, DUMMY
, DUMMY
) == 0) {
647 hostf
= fopen(_PATH_HOSTSLPD
, "r");
649 if (__ivaliduser_sa(hostf
, f
, f
->sa_len
, DUMMY
, DUMMY
) == 0) {
658 fatal("Your host does not have line printer access");
667 (void)fprintf(stderr
,
668 "Usage: %s [-dlrsW] [-b bind-address] [-n maxchild] "
669 "[-w maxwait] [port]\n", getprogname());
673 /* setup server socket for specified address family */
674 /* if af is PF_UNSPEC more than one socket may be returned */
675 /* the returned list is dynamically allocated, so caller needs to free it */
677 socksetup(int af
, int options
, const char *port
, int *nfds
)
679 struct sockaddr_un un
;
680 struct addrinfo hints
, *res
, *r
;
681 int error
, s
, blidx
= 0, n
;
682 struct pollfd
*socks
, *newsocks
;
687 socks
= malloc(1 * sizeof(socks
[0]));
689 syslog(LOG_ERR
, "couldn't allocate memory for sockets");
693 s
= socket(AF_LOCAL
, SOCK_STREAM
, 0);
695 syslog(LOG_ERR
, "socket(): %m");
698 memset(&un
, 0, sizeof(un
));
699 un
.sun_family
= AF_LOCAL
;
700 strncpy(un
.sun_path
, _PATH_SOCKETNAME
, sizeof(un
.sun_path
) - 1);
701 un
.sun_len
= SUN_LEN(&un
);
703 (void)unlink(_PATH_SOCKETNAME
);
704 if (bind(s
, (struct sockaddr
*)&un
, un
.sun_len
) < 0) {
705 syslog(LOG_ERR
, "bind(): %m");
711 socks
[*nfds
].events
= POLLIN
;
714 if (sflag
&& !blist_addrs
)
718 memset(&hints
, 0, sizeof(hints
));
719 hints
.ai_flags
= AI_PASSIVE
;
720 hints
.ai_family
= af
;
721 hints
.ai_socktype
= SOCK_STREAM
;
722 error
= getaddrinfo((blist_addrs
== 0) ? NULL
: blist
[blidx
],
723 port
? port
: "printer", &hints
, &res
);
726 syslog(LOG_ERR
, "%s: %s", blist
[blidx
],
727 gai_strerror(error
));
729 syslog(LOG_ERR
, "%s", gai_strerror(error
));
733 /* Count max number of sockets we may open */
734 for (r
= res
, n
= 0; r
; r
= r
->ai_next
, n
++)
736 newsocks
= realloc(socks
, (*nfds
+ n
) * sizeof(socks
[0]));
738 syslog(LOG_ERR
, "couldn't allocate memory for sockets");
743 for (r
= res
; r
; r
= r
->ai_next
) {
744 s
= socket(r
->ai_family
, r
->ai_socktype
,
747 syslog(LOG_DEBUG
, "socket(): %m");
750 if (options
& SO_DEBUG
)
751 if (setsockopt(s
, SOL_SOCKET
, SO_DEBUG
,
752 &on
, sizeof(on
)) < 0) {
754 "setsockopt (SO_DEBUG): %m");
758 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEPORT
, &on
,
761 "setsockopt (SO_REUSEPORT): %m");
765 if (r
->ai_family
== AF_INET6
&& setsockopt(s
,
766 IPPROTO_IPV6
, IPV6_V6ONLY
, &on
, sizeof(on
)) < 0) {
768 "setsockopt (IPV6_V6ONLY): %m");
772 if (bind(s
, r
->ai_addr
, r
->ai_addrlen
) < 0) {
773 syslog(LOG_DEBUG
, "bind(): %m");
779 socks
[*nfds
].events
= POLLIN
;
785 } while (++blidx
< blist_addrs
);