lpd.c revision 1.65
1/*	$OpenBSD: lpd.c,v 1.65 2018/04/26 12:42:51 guenther 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
95int	lflag;				/* log requests flag */
96int	rflag;				/* allow 'of' for remote printers */
97int	sflag;				/* secure (no inet) flag */
98int	from_remote;			/* from remote socket */
99char	**blist;			/* list of addresses to bind(2) to */
100int	blist_size;
101int	blist_addrs;
102
103volatile sig_atomic_t child_count;	/* number of kids forked */
104
105static void		reapchild(int);
106static void		mcleanup(int);
107static void		doit(void);
108static void		startup(void);
109static void		chkhost(struct sockaddr *);
110static __dead void	usage(void);
111static int		*socksetup(int, int, const char *);
112
113/* unused, needed for lpc */
114volatile sig_atomic_t gotintr;
115
116int
117main(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 postive 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
398static void
399reapchild(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
409static void
410mcleanup(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 */
424char	*user[MAXUSERS];	/* users to process */
425int	users;			/* # of users in user array */
426int	requ[MAXREQUESTS];	/* job number of spool entries */
427int	requests;		/* # of spool requests */
428char	*person;		/* name of person doing lprm */
429
430char	fromb[NI_MAXHOST];	/* buffer for client's machine name */
431char	cbuf[BUFSIZ];		/* command line buffer */
432char	*cmdnames[] = {
433	"null",
434	"printjob",
435	"recvjob",
436	"displayq short",
437	"displayq long",
438	"rmjob"
439};
440
441static void
442doit(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 */
559static void
560startup(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 */
600static void
601chkhost(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
670static __dead void
671usage(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 */
685int *
686socksetup(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