1/*	$NetBSD: lpd.c,v 1.56 2011/08/30 19:27:37 joerg 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. 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.
19 *
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
30 * SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34
35#ifndef lint
36__COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\
37 The Regents of the University of California.  All rights reserved.");
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)lpd.c	8.7 (Berkeley) 5/10/95";
43#else
44__RCSID("$NetBSD: lpd.c,v 1.56 2011/08/30 19:27:37 joerg Exp $");
45#endif
46#endif /* not lint */
47
48/*
49 * lpd -- line printer daemon.
50 *
51 * Listen for a connection and perform the requested operation.
52 * Operations are:
53 *	\1printer\n
54 *		check the queue for jobs and print any found.
55 *	\2printer\n
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.
63 *
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.
75 */
76
77#include <sys/param.h>
78#include <sys/wait.h>
79#include <sys/types.h>
80#include <sys/socket.h>
81#include <sys/un.h>
82#include <sys/stat.h>
83#include <sys/file.h>
84#include <sys/poll.h>
85#include <netinet/in.h>
86
87#include <err.h>
88#include <netdb.h>
89#include <unistd.h>
90#include <syslog.h>
91#include <signal.h>
92#include <errno.h>
93#include <fcntl.h>
94#include <dirent.h>
95#include <stdarg.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include <string.h>
99#include <ctype.h>
100#include <arpa/inet.h>
101
102#ifdef LIBWRAP
103#include <tcpd.h>
104#endif
105
106#include "lp.h"
107#include "lp.local.h"
108#include "pathnames.h"
109#include "extern.h"
110
111/* XXX from libc/net/rcmd.c */
112extern int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t,
113			   const char *, const char *);
114
115#ifdef LIBWRAP
116int allow_severity = LOG_AUTH|LOG_INFO;
117int deny_severity = LOG_AUTH|LOG_WARNING;
118#endif
119
120int	lflag;				/* log requests flag */
121int	rflag;				/* allow of for remote printers */
122int	sflag;				/* secure (no inet) flag */
123int	from_remote;			/* from remote socket */
124char	**blist;			/* list of addresses to bind(2) to */
125int	blist_size;
126int	blist_addrs;
127
128int			main(int, char **);
129static void		reapchild(int);
130__dead static void	mcleanup(int);
131static void		doit(void);
132static void		startup(void);
133static void		chkhost(struct sockaddr *, int);
134__dead static void	usage(void);
135static struct pollfd	*socksetup(int, int, const char *, int *);
136static void		chkplushost(int, FILE *, char*);
137
138uid_t	uid, euid;
139int child_count;
140
141#define LPD_NOPORTCHK	0001		/* skip reserved-port check */
142
143int
144main(int argc, char **argv)
145{
146	struct sockaddr_storage frm;
147	socklen_t frmlen;
148	sigset_t nmask, omask;
149	int lfd, errs, i, f, nfds;
150	struct pollfd *socks;
151	int child_max = 32;	/* more than enough to hose the system */
152	int options = 0, check_options = 0;
153	struct servent *sp;
154	const char *port = "printer";
155	char **newblist;
156
157	euid = geteuid();	/* these shouldn't be different */
158	uid = getuid();
159	gethostname(host, sizeof(host));
160	host[sizeof(host) - 1] = '\0';
161	setprogname(*argv);
162
163	errs = 0;
164	while ((i = getopt(argc, argv, "b:dln:srw:W")) != -1)
165		switch (i) {
166		case 'b':
167			if (blist_addrs >= blist_size) {
168				newblist = realloc(blist,
169				    blist_size + sizeof(char *) * 4);
170				if (newblist == NULL)
171					err(1, "cant allocate bind addr list");
172				blist = newblist;
173				blist_size += sizeof(char *) * 4;
174			}
175			blist[blist_addrs++] = strdup(optarg);
176			break;
177		case 'd':
178			options |= SO_DEBUG;
179			break;
180		case 'l':
181			lflag++;
182			break;
183		case 'n':
184			child_max = atoi(optarg);
185			if (child_max < 0 || child_max > 1024)
186				errx(1, "invalid number of children: %s",
187				    optarg);
188			break;
189		case 'r':
190			rflag++;
191			break;
192		case 's':
193			sflag++;
194			break;
195		case 'w':
196			wait_time = atoi(optarg);
197			if (wait_time < 0)
198				errx(1, "wait time must be postive: %s",
199				    optarg);
200			if (wait_time < 30)
201			    warnx("warning: wait time less than 30 seconds");
202			break;
203		case 'W':/* allow connections coming from a non-reserved port */
204			 /* (done by some lpr-implementations for MS-Windows) */
205			check_options |= LPD_NOPORTCHK;
206			break;
207		default:
208			errs++;
209		}
210	argc -= optind;
211	argv += optind;
212	if (errs)
213		usage();
214
215	switch (argc) {
216	case 1:
217		if ((i = atoi(argv[0])) == 0)
218			usage();
219		if (i < 0 || i > USHRT_MAX)
220			errx(1, "port # %d is invalid", i);
221
222		port = argv[0];
223		break;
224	case 0:
225		sp = getservbyname(port, "tcp");
226		if (sp == NULL)
227			errx(1, "%s/tcp: unknown service", port);
228		break;
229	default:
230		usage();
231	}
232
233#ifndef DEBUG
234	/*
235	 * Set up standard environment by detaching from the parent.
236	 */
237	daemon(0, 0);
238#endif
239
240	openlog("lpd", LOG_PID, LOG_LPR);
241	syslog(LOG_INFO, "restarted");
242	(void)umask(0);
243	lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
244	if (lfd < 0) {
245		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
246		exit(1);
247	}
248	if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
249		if (errno == EWOULDBLOCK) {	/* active daemon present */
250			syslog(LOG_ERR, "%s is locked; another lpd is running",
251			    _PATH_MASTERLOCK);
252			exit(0);
253		}
254		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
255		exit(1);
256	}
257	ftruncate(lfd, 0);
258	/*
259	 * write process id for others to know
260	 */
261	(void)snprintf(line, sizeof(line), "%u\n", getpid());
262	f = strlen(line);
263	if (write(lfd, line, f) != f) {
264		syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
265		exit(1);
266	}
267	signal(SIGCHLD, reapchild);
268	/*
269	 * Restart all the printers.
270	 */
271	startup();
272
273	sigemptyset(&nmask);
274	sigaddset(&nmask, SIGHUP);
275	sigaddset(&nmask, SIGINT);
276	sigaddset(&nmask, SIGQUIT);
277	sigaddset(&nmask, SIGTERM);
278	sigprocmask(SIG_BLOCK, &nmask, &omask);
279
280	signal(SIGHUP, mcleanup);
281	signal(SIGINT, mcleanup);
282	signal(SIGQUIT, mcleanup);
283	signal(SIGTERM, mcleanup);
284
285	socks = socksetup(PF_UNSPEC, options, port, &nfds);
286
287	sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
288
289	if (blist != NULL) {
290		for (i = 0; i < blist_addrs; i++)
291			free(blist[i]);
292		free(blist);
293	}
294
295	/*
296	 * Main loop: accept, do a request, continue.
297	 */
298	memset(&frm, 0, sizeof(frm));
299	for (;;) {
300		int rv, s;
301		/* "short" so it overflows in about 2 hours */
302		struct timespec sleeptime = {10, 0};
303
304		while (child_max < child_count) {
305			syslog(LOG_WARNING,
306			    "too many children, sleeping for %ld seconds",
307				(long)sleeptime.tv_sec);
308			nanosleep(&sleeptime, NULL);
309			sleeptime.tv_sec <<= 1;
310			if (sleeptime.tv_sec <= 0) {
311				syslog(LOG_CRIT, "sleeptime overflowed! help!");
312				sleeptime.tv_sec = 10;
313			}
314		}
315
316		rv = poll(socks, nfds, INFTIM);
317		if (rv <= 0) {
318			if (rv < 0 && errno != EINTR)
319				syslog(LOG_WARNING, "poll: %m");
320			continue;
321		}
322		s = -1;
323                for (i = 0; i < nfds; i++)
324			if (socks[i].revents & POLLIN) {
325				frmlen = sizeof(frm);
326				s = accept(socks[i].fd,
327				    (struct sockaddr *)&frm, &frmlen);
328				break;
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_DFL);
339			signal(SIGHUP, SIG_IGN);
340			signal(SIGINT, SIG_IGN);
341			signal(SIGQUIT, SIG_IGN);
342			signal(SIGTERM, SIG_IGN);
343                       	for (i = 0; i < nfds; i++)
344				(void)close(socks[i].fd);
345			dup2(s, STDOUT_FILENO);
346			(void)close(s);
347			if (frm.ss_family != AF_LOCAL) {
348				/* for both AF_INET and AF_INET6 */
349				from_remote = 1;
350				chkhost((struct sockaddr *)&frm, check_options);
351			} else
352				from_remote = 0;
353			doit();
354			exit(0);
355		case -1:
356			syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds...");
357			sleep(10);
358			continue;
359		default:
360			child_count++;
361		}
362		(void)close(s);
363	}
364}
365
366/*
367 * If there was a forward/backward name resolution mismatch, check
368 * that there's a '+' entry in fhost.
369 */
370
371void
372chkplushost(int good, FILE *fhost, char *hst)
373{
374	int c1, c2, c3;
375
376	if (good) {
377		return;
378	}
379
380	rewind(fhost);
381	while (EOF != (c1 = fgetc(fhost))) {
382		if (c1 == '+') {
383			c2 = fgetc(fhost);
384			if (c2 == ' ' || c2 == '\t' || c2 == '\n') {
385				return;
386			}
387		}
388		do {
389			c3 = fgetc(fhost);
390		} while (c3 != EOF && c3 != '\n');
391	}
392	fatal("address for your hostname (%s) not matched", hst);
393}
394
395static void
396reapchild(int signo)
397{
398	union wait status;
399
400	while (wait3((int *)&status, WNOHANG, 0) > 0)
401		child_count--;
402}
403
404static void
405mcleanup(int signo)
406{
407	if (lflag)
408		syslog(LOG_INFO, "exiting");
409	unlink(_PATH_SOCKETNAME);
410	exit(0);
411}
412
413/*
414 * Stuff for handling job specifications
415 */
416char	*user[MAXUSERS];	/* users to process */
417int	users;			/* # of users in user array */
418int	requ[MAXREQUESTS];	/* job number of spool entries */
419int	requests;		/* # of spool requests */
420char	*person;		/* name of person doing lprm */
421
422char	fromb[NI_MAXHOST];	/* buffer for client's machine name */
423char	cbuf[BUFSIZ];		/* command line buffer */
424const char *cmdnames[] = {
425	"null",
426	"printjob",
427	"recvjob",
428	"displayq short",
429	"displayq long",
430	"rmjob"
431};
432
433static void
434doit(void)
435{
436	char *cp;
437	int n;
438
439	for (;;) {
440		cp = cbuf;
441		do {
442			if (cp >= &cbuf[sizeof(cbuf) - 1])
443				fatal("Command line too long");
444			if ((n = read(STDOUT_FILENO, cp, 1)) != 1) {
445				if (n < 0)
446					fatal("Lost connection");
447				return;
448			}
449		} while (*cp++ != '\n');
450		*--cp = '\0';
451		cp = cbuf;
452		if (lflag) {
453			if (*cp >= '\1' && *cp <= '\5') {
454				syslog(LOG_INFO, "%s requests %s %s",
455					from, cmdnames[(int)*cp], cp+1);
456				setproctitle("serving %s: %s %s", from,
457				    cmdnames[(int)*cp], cp+1);
458			}
459			else
460				syslog(LOG_INFO, "bad request (%d) from %s",
461					*cp, from);
462		}
463		switch (*cp++) {
464		case '\1':	/* check the queue and print any jobs there */
465			printer = cp;
466			if (*printer == '\0')
467				printer = DEFLP;
468			printjob();
469			break;
470		case '\2':	/* receive files to be queued */
471			if (!from_remote) {
472				syslog(LOG_INFO, "illegal request (%d)", *cp);
473				exit(1);
474			}
475			printer = cp;
476			if (*printer == '\0')
477				printer = DEFLP;
478			recvjob();
479			break;
480		case '\3':	/* display the queue (short form) */
481		case '\4':	/* display the queue (long form) */
482			printer = cp;
483			if (*printer == '\0')
484				printer = DEFLP;
485			while (*cp) {
486				if (*cp != ' ') {
487					cp++;
488					continue;
489				}
490				*cp++ = '\0';
491				while (isspace((unsigned char)*cp))
492					cp++;
493				if (*cp == '\0')
494					break;
495				if (isdigit((unsigned char)*cp)) {
496					if (requests >= MAXREQUESTS)
497						fatal("Too many requests");
498					requ[requests++] = atoi(cp);
499				} else {
500					if (users >= MAXUSERS)
501						fatal("Too many users");
502					user[users++] = cp;
503				}
504			}
505			displayq(cbuf[0] - '\3');
506			exit(0);
507		case '\5':	/* remove a job from the queue */
508			if (!from_remote) {
509				syslog(LOG_INFO, "illegal request (%d)", *cp);
510				exit(1);
511			}
512			printer = cp;
513			if (*printer == '\0')
514				printer = DEFLP;
515			while (*cp && *cp != ' ')
516				cp++;
517			if (!*cp)
518				break;
519			*cp++ = '\0';
520			person = cp;
521			while (*cp) {
522				if (*cp != ' ') {
523					cp++;
524					continue;
525				}
526				*cp++ = '\0';
527				while (isspace((unsigned char)*cp))
528					cp++;
529				if (*cp == '\0')
530					break;
531				if (isdigit((unsigned char)*cp)) {
532					if (requests >= MAXREQUESTS)
533						fatal("Too many requests");
534					requ[requests++] = atoi(cp);
535				} else {
536					if (users >= MAXUSERS)
537						fatal("Too many users");
538					user[users++] = cp;
539				}
540			}
541			rmjob();
542			break;
543		}
544		fatal("Illegal service request");
545	}
546}
547
548/*
549 * Make a pass through the printcap database and start printing any
550 * files left from the last time the machine went down.
551 */
552static void
553startup(void)
554{
555	char *buf;
556	char *cp;
557
558	/*
559	 * Restart the daemons.
560	 */
561	while (cgetnext(&buf, printcapdb) > 0) {
562		if (ckqueue(buf) <= 0) {
563			free(buf);
564			continue;	/* no work to do for this printer */
565		}
566		for (cp = buf; *cp; cp++)
567			if (*cp == '|' || *cp == ':') {
568				*cp = '\0';
569				break;
570			}
571		if (lflag)
572			syslog(LOG_INFO, "work for %s", buf);
573		switch (fork()) {
574		case -1:
575			syslog(LOG_WARNING, "startup: cannot fork");
576			mcleanup(0);
577		case 0:
578			printer = buf;
579			setproctitle("working on printer %s", printer);
580			cgetclose();
581			printjob();
582			/* NOTREACHED */
583		default:
584			child_count++;
585			free(buf);
586		}
587	}
588}
589
590#define DUMMY ":nobody::"
591
592/*
593 * Check to see if the from host has access to the line printer.
594 */
595static void
596chkhost(struct sockaddr *f, int check_opts)
597{
598	struct addrinfo hints, *res, *r;
599	FILE *hostf;
600	int good = 0;
601	char hst[NI_MAXHOST], ip[NI_MAXHOST];
602	char serv[NI_MAXSERV];
603	int error;
604#ifdef LIBWRAP
605	struct request_info req;
606#endif
607
608	error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv),
609			    NI_NUMERICSERV);
610	if (error)
611		fatal("Malformed from address: %s", gai_strerror(error));
612
613         if (!(check_opts & LPD_NOPORTCHK) &&
614	       atoi(serv) >= IPPORT_RESERVED)
615		fatal("Connect from invalid port (%s)", serv);
616
617	/* Need real hostname for temporary filenames */
618	error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0,
619			    NI_NAMEREQD);
620	if (error) {
621		error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0,
622				    NI_NUMERICHOST);
623		if (error)
624			fatal("Host name for your address unknown");
625		else
626			fatal("Host name for your address (%s) unknown", hst);
627	}
628
629	(void)strlcpy(fromb, hst, sizeof(fromb));
630	from = fromb;
631
632	/* need address in stringform for comparison (no DNS lookup here) */
633	error = getnameinfo(f, f->sa_len, hst, sizeof(hst), NULL, 0,
634			    NI_NUMERICHOST);
635	if (error)
636		fatal("Cannot print address");
637
638	/* Check for spoof, ala rlogind */
639	good = 0;
640	memset(&hints, 0, sizeof(hints));
641	hints.ai_family = PF_UNSPEC;
642	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
643	error = getaddrinfo(fromb, NULL, &hints, &res);
644	if (!error) {
645		for (r = res; good == 0 && r; r = r->ai_next) {
646			error = getnameinfo(r->ai_addr, r->ai_addrlen,
647				    ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
648			if (!error && !strcmp(hst, ip))
649				good = 1;
650		}
651		if (res)
652			freeaddrinfo(res);
653	}
654
655	/* complain about !good later in chkplushost if needed. */
656
657	setproctitle("serving %s", from);
658
659#ifdef LIBWRAP
660	request_init(&req, RQ_DAEMON, "lpd", RQ_CLIENT_SIN, f,
661	    RQ_FILE, STDOUT_FILENO, NULL);
662	fromhost(&req);
663	if (!hosts_access(&req))
664		goto denied;
665#endif
666
667	hostf = fopen(_PATH_HOSTSEQUIV, "r");
668	if (hostf) {
669		if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
670			chkplushost(good, hostf, hst);
671			(void)fclose(hostf);
672			return;
673		}
674		(void)fclose(hostf);
675	}
676	hostf = fopen(_PATH_HOSTSLPD, "r");
677	if (hostf) {
678		if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) {
679			chkplushost(good, hostf, hst);
680			(void)fclose(hostf);
681			return;
682		}
683		(void)fclose(hostf);
684	}
685#ifdef LIBWRAP
686  denied:
687#endif
688	fatal("Your host does not have line printer access");
689	/*NOTREACHED*/
690}
691
692
693static void
694usage(void)
695{
696
697	(void)fprintf(stderr,
698	    "Usage: %s [-dlrsW] [-b bind-address] [-n maxchild] "
699	    "[-w maxwait] [port]\n", getprogname());
700	exit(1);
701}
702
703/* setup server socket for specified address family */
704/* if af is PF_UNSPEC more than one socket may be returned */
705/* the returned list is dynamically allocated, so caller needs to free it */
706struct pollfd *
707socksetup(int af, int options, const char *port, int *nfds)
708{
709	struct sockaddr_un un;
710	struct addrinfo hints, *res, *r;
711	int error, s, blidx = 0, n;
712	struct pollfd *socks, *newsocks;
713	const int on = 1;
714
715	*nfds = 0;
716
717	socks = malloc(1 * sizeof(socks[0]));
718	if (!socks) {
719		syslog(LOG_ERR, "couldn't allocate memory for sockets");
720		mcleanup(0);
721	}
722
723	s = socket(AF_LOCAL, SOCK_STREAM, 0);
724	if (s < 0) {
725		syslog(LOG_ERR, "socket(): %m");
726		exit(1);
727	}
728	memset(&un, 0, sizeof(un));
729	un.sun_family = AF_LOCAL;
730	strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1);
731	un.sun_len = SUN_LEN(&un);
732	(void)umask(07);
733	(void)unlink(_PATH_SOCKETNAME);
734	if (bind(s, (struct sockaddr *)&un, un.sun_len) < 0) {
735		syslog(LOG_ERR, "bind(): %m");
736		exit(1);
737	}
738	(void)umask(0);
739	listen(s, 5);
740	socks[*nfds].fd = s;
741	socks[*nfds].events = POLLIN;
742	(*nfds)++;
743
744	if (sflag && !blist_addrs)
745		return (socks);
746
747	do {
748		memset(&hints, 0, sizeof(hints));
749		hints.ai_flags = AI_PASSIVE;
750		hints.ai_family = af;
751		hints.ai_socktype = SOCK_STREAM;
752		error = getaddrinfo((blist_addrs == 0) ? NULL : blist[blidx],
753		    port ? port : "printer", &hints, &res);
754		if (error) {
755			if (blist_addrs)
756				syslog(LOG_ERR, "%s: %s", blist[blidx],
757				    gai_strerror(error));
758			else
759				syslog(LOG_ERR, "%s", gai_strerror(error));
760			mcleanup(0);
761		}
762
763		/* Count max number of sockets we may open */
764		for (r = res, n = 0; r; r = r->ai_next, n++)
765			;
766		newsocks = realloc(socks, (*nfds + n) * sizeof(socks[0]));
767		if (!newsocks) {
768			syslog(LOG_ERR, "couldn't allocate memory for sockets");
769			mcleanup(0);
770		}
771		socks = newsocks;
772
773		for (r = res; r; r = r->ai_next) {
774			s = socket(r->ai_family, r->ai_socktype,
775			    r->ai_protocol);
776			if (s < 0) {
777				syslog(LOG_DEBUG, "socket(): %m");
778				continue;
779			}
780			if (options & SO_DEBUG)
781				if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
782					       &on, sizeof(on)) < 0) {
783					syslog(LOG_ERR,
784					       "setsockopt (SO_DEBUG): %m");
785					close(s);
786					continue;
787				}
788			if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on,
789			    sizeof(on)) < 0) {
790				syslog(LOG_ERR,
791				    "setsockopt (SO_REUSEPORT): %m");
792				close(s);
793				continue;
794			}
795			if (r->ai_family == AF_INET6 && setsockopt(s,
796			    IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
797				syslog(LOG_ERR,
798				    "setsockopt (IPV6_V6ONLY): %m");
799				close(s);
800				continue;
801			}
802			if (bind(s, r->ai_addr, r->ai_addrlen) < 0) {
803				syslog(LOG_DEBUG, "bind(): %m");
804				close(s);
805				continue;
806			}
807			listen(s, 5);
808			socks[*nfds].fd = s;
809			socks[*nfds].events = POLLIN;
810			(*nfds)++;
811		}
812
813		if (res)
814			freeaddrinfo(res);
815	} while (++blidx < blist_addrs);
816
817	return (socks);
818}
819