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