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