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