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