GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/lpr/lpd/lpd.c Lines: 0 386 0.0 %
Date: 2017-11-07 Branches: 0 233 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lpd.c,v 1.64 2016/02/29 17:26:01 jca 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/wait.h>
67
#include <sys/types.h>
68
#include <sys/socket.h>
69
#include <sys/un.h>
70
#include <sys/stat.h>
71
#include <sys/file.h>
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
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 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
398
static void
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
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
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
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
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
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 *
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
}