1 /* $NetBSD: lpd.c,v 1.33 2002/01/21 14:42:29 wiz 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 39 #ifndef lint 40 __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\ 41 The Regents of the University of California. All rights reserved.\n"); 42 #endif /* not lint */ 43 44 #ifndef lint 45 #if 0 46 static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 47 #else 48 __RCSID("$NetBSD: lpd.c,v 1.33 2002/01/21 14:42:29 wiz Exp $"); 49 #endif 50 #endif /* not lint */ 51 52 /* 53 * lpd -- line printer daemon. 54 * 55 * Listen for a connection and perform the requested operation. 56 * Operations are: 57 * \1printer\n 58 * check the queue for jobs and print any found. 59 * \2printer\n 60 * receive a job from another machine and queue it. 61 * \3printer [users ...] [jobs ...]\n 62 * return the current state of the queue (short form). 63 * \4printer [users ...] [jobs ...]\n 64 * return the current state of the queue (long form). 65 * \5printer person [users ...] [jobs ...]\n 66 * remove jobs from the queue. 67 * 68 * Strategy to maintain protected spooling area: 69 * 1. Spooling area is writable only by daemon and spooling group 70 * 2. lpr runs setuid root and setgrp spooling group; it uses 71 * root to access any file it wants (verifying things before 72 * with an access call) and group id to know how it should 73 * set up ownership of files in the spooling area. 74 * 3. Files in spooling area are owned by root, group spooling 75 * group, with mode 660. 76 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 77 * access files and printer. Users can't get to anything 78 * w/o help of lpq and lprm programs. 79 */ 80 81 #include <sys/param.h> 82 #include <sys/wait.h> 83 #include <sys/types.h> 84 #include <sys/socket.h> 85 #include <sys/un.h> 86 #include <sys/stat.h> 87 #include <sys/file.h> 88 #include <netinet/in.h> 89 90 #include <err.h> 91 #include <netdb.h> 92 #include <unistd.h> 93 #include <syslog.h> 94 #include <signal.h> 95 #include <errno.h> 96 #include <fcntl.h> 97 #include <dirent.h> 98 #include <stdarg.h> 99 #include <stdio.h> 100 #include <stdlib.h> 101 #include <string.h> 102 #include <ctype.h> 103 #include <arpa/inet.h> 104 105 #include "lp.h" 106 #include "lp.local.h" 107 #include "pathnames.h" 108 #include "extern.h" 109 110 /* XXX from libc/net/rcmd.c */ 111 extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t, 112 const char *, const char *)); 113 114 int lflag; /* log requests flag */ 115 int rflag; /* allow of for remote printers */ 116 int sflag; /* secure (no inet) flag */ 117 int from_remote; /* from remote socket */ 118 char **blist; /* list of addresses to bind(2) to */ 119 int blist_size; 120 int blist_addrs; 121 122 int main __P((int, char **)); 123 static void reapchild __P((int)); 124 static void mcleanup __P((int)); 125 static void doit __P((void)); 126 static void startup __P((void)); 127 static void chkhost __P((struct sockaddr *, int)); 128 static int ckqueue __P((char *)); 129 static void usage __P((void)); 130 static int *socksetup __P((int, int, const char *)); 131 132 uid_t uid, euid; 133 int child_count; 134 135 #define LPD_NOPORTCHK 0001 /* skip reserved-port check */ 136 137 int 138 main(int argc, char **argv) 139 { 140 fd_set defreadfds; 141 struct sockaddr_un un, fromunix; 142 struct sockaddr_storage frominet; 143 sigset_t nmask, omask; 144 int lfd, errs, i, f, funix, *finet; 145 int child_max = 32; /* more than enough to hose the system */ 146 int options = 0, check_options = 0; 147 struct servent *sp; 148 const char *port = "printer"; 149 150 euid = geteuid(); /* these shouldn't be different */ 151 uid = getuid(); 152 gethostname(host, sizeof(host)); 153 host[sizeof(host) - 1] = '\0'; 154 name = argv[0]; 155 156 errs = 0; 157 while ((i = getopt(argc, argv, "b:cdln:srw:W")) != -1) 158 switch (i) { 159 case 'b': 160 if (blist_addrs >= blist_size) { 161 blist_size += sizeof(char *) * 4; 162 if (blist == NULL) 163 blist = malloc(blist_size); 164 else 165 blist = realloc(blist, blist_size); 166 if (blist == NULL) 167 err(1, "cant allocate bind addr list"); 168 } 169 blist[blist_addrs++] = strdup(optarg); 170 break; 171 case 'd': 172 options |= SO_DEBUG; 173 break; 174 case 'l': 175 lflag++; 176 break; 177 case 'n': 178 child_max = atoi(optarg); 179 if (child_max < 0 || child_max > 1024) 180 errx(1, "invalid number of children: %s", 181 optarg); 182 break; 183 case 'r': 184 rflag++; 185 break; 186 case 's': 187 sflag++; 188 break; 189 case 'w': 190 wait_time = atoi(optarg); 191 if (wait_time < 0) 192 errx(1, "wait time must be postive: %s", 193 optarg); 194 if (wait_time < 30) 195 warnx("warning: wait time less than 30 seconds"); 196 break; 197 case 'W':/* allow connections coming from a non-reserved port */ 198 /* (done by some lpr-implementations for MS-Windows) */ 199 check_options |= LPD_NOPORTCHK; 200 break; 201 default: 202 errs++; 203 } 204 argc -= optind; 205 argv += optind; 206 if (errs) 207 usage(); 208 209 switch (argc) { 210 case 1: 211 if ((i = atoi(argv[0])) == 0) 212 usage(); 213 if (i < 0 || i > USHRT_MAX) 214 errx(1, "port # %d is invalid", i); 215 216 port = argv[0]; 217 break; 218 case 0: 219 sp = getservbyname(port, "tcp"); 220 if (sp == NULL) 221 errx(1, "%s/tcp: unknown service", port); 222 break; 223 default: 224 usage(); 225 } 226 227 #ifndef DEBUG 228 /* 229 * Set up standard environment by detaching from the parent. 230 */ 231 daemon(0, 0); 232 #endif 233 234 openlog("lpd", LOG_PID, LOG_LPR); 235 syslog(LOG_INFO, "restarted"); 236 (void)umask(0); 237 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); 238 if (lfd < 0) { 239 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 240 exit(1); 241 } 242 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 243 if (errno == EWOULDBLOCK) /* active daemon present */ 244 exit(0); 245 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 246 exit(1); 247 } 248 ftruncate(lfd, 0); 249 /* 250 * write process id for others to know 251 */ 252 (void)snprintf(line, sizeof(line), "%u\n", getpid()); 253 f = strlen(line); 254 if (write(lfd, line, f) != f) { 255 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 256 exit(1); 257 } 258 signal(SIGCHLD, reapchild); 259 /* 260 * Restart all the printers. 261 */ 262 startup(); 263 (void)unlink(_PATH_SOCKETNAME); 264 funix = socket(AF_LOCAL, SOCK_STREAM, 0); 265 if (funix < 0) { 266 syslog(LOG_ERR, "socket: %m"); 267 exit(1); 268 } 269 270 sigemptyset(&nmask); 271 sigaddset(&nmask, SIGHUP); 272 sigaddset(&nmask, SIGINT); 273 sigaddset(&nmask, SIGQUIT); 274 sigaddset(&nmask, SIGTERM); 275 sigprocmask(SIG_BLOCK, &nmask, &omask); 276 277 (void) umask(07); 278 signal(SIGHUP, mcleanup); 279 signal(SIGINT, mcleanup); 280 signal(SIGQUIT, mcleanup); 281 signal(SIGTERM, mcleanup); 282 memset(&un, 0, sizeof(un)); 283 un.sun_family = AF_LOCAL; 284 strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1); 285 #ifndef SUN_LEN 286 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 287 #endif 288 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 289 syslog(LOG_ERR, "ubind: %m"); 290 exit(1); 291 } 292 (void) umask(0); 293 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 294 FD_ZERO(&defreadfds); 295 FD_SET(funix, &defreadfds); 296 listen(funix, 5); 297 if (!sflag || blist_addrs) 298 finet = socksetup(PF_UNSPEC, options, port); 299 else 300 finet = NULL; /* pretend we couldn't open TCP socket. */ 301 302 if (blist != NULL) { 303 for (i = 0; i < blist_addrs; i++) 304 free(blist[i]); 305 free(blist); 306 } 307 308 if (finet) { 309 for (i = 1; i <= *finet; i++) { 310 FD_SET(finet[i], &defreadfds); 311 listen(finet[i], 5); 312 } 313 } 314 /* 315 * Main loop: accept, do a request, continue. 316 */ 317 memset(&frominet, 0, sizeof(frominet)); 318 memset(&fromunix, 0, sizeof(fromunix)); 319 for (;;) { 320 int domain, nfds, s, fromlen; 321 fd_set readfds; 322 /* "short" so it overflows in about 2 hours */ 323 short sleeptime = 10; 324 325 while (child_max < child_count) { 326 syslog(LOG_WARNING, 327 "too many children, sleeping for %d seconds", 328 sleeptime); 329 sleep(sleeptime); 330 sleeptime <<= 1; 331 if (sleeptime < 0) { 332 syslog(LOG_CRIT, "sleeptime overflowed! help!"); 333 sleeptime = 10; 334 } 335 } 336 337 FD_COPY(&defreadfds, &readfds); 338 nfds = select(20, &readfds, 0, 0, 0); 339 if (nfds <= 0) { 340 if (nfds < 0 && errno != EINTR) 341 syslog(LOG_WARNING, "select: %m"); 342 continue; 343 } 344 if (FD_ISSET(funix, &readfds)) { 345 domain = AF_LOCAL; 346 fromlen = sizeof(fromunix); 347 s = accept(funix, 348 (struct sockaddr *)&fromunix, &fromlen); 349 } else { 350 for (i = 1; i <= *finet; i++) 351 if (FD_ISSET(finet[i], &readfds)) { 352 domain = AF_INET, fromlen = sizeof(frominet); 353 s = accept(finet[i], (struct sockaddr *)&frominet, &fromlen); 354 } 355 } 356 if (s < 0) { 357 if (errno != EINTR) 358 syslog(LOG_WARNING, "accept: %m"); 359 continue; 360 } 361 362 switch (fork()) { 363 case 0: 364 signal(SIGCHLD, SIG_IGN); 365 signal(SIGHUP, SIG_IGN); 366 signal(SIGINT, SIG_IGN); 367 signal(SIGQUIT, SIG_IGN); 368 signal(SIGTERM, SIG_IGN); 369 (void)close(funix); 370 if (!sflag && finet) 371 for (i = 1; i <= *finet; i++) 372 (void)close(finet[i]); 373 dup2(s, 1); 374 (void)close(s); 375 if (domain == AF_INET) { 376 /* for both AF_INET and AF_INET6 */ 377 from_remote = 1; 378 chkhost((struct sockaddr *)&frominet, check_options); 379 } else 380 from_remote = 0; 381 doit(); 382 exit(0); 383 case -1: 384 syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds..."); 385 sleep(10); 386 continue; 387 default: 388 child_count++; 389 } 390 (void)close(s); 391 } 392 } 393 394 static void 395 reapchild(int signo) 396 { 397 union wait status; 398 399 while (wait3((int *)&status, WNOHANG, 0) > 0) 400 child_count--; 401 } 402 403 static void 404 mcleanup(int signo) 405 { 406 if (lflag) 407 syslog(LOG_INFO, "exiting"); 408 unlink(_PATH_SOCKETNAME); 409 exit(0); 410 } 411 412 /* 413 * Stuff for handling job specifications 414 */ 415 char *user[MAXUSERS]; /* users to process */ 416 int users; /* # of users in user array */ 417 int requ[MAXREQUESTS]; /* job number of spool entries */ 418 int requests; /* # of spool requests */ 419 char *person; /* name of person doing lprm */ 420 421 char fromb[NI_MAXHOST]; /* buffer for client's machine name */ 422 char cbuf[BUFSIZ]; /* command line buffer */ 423 char *cmdnames[] = { 424 "null", 425 "printjob", 426 "recvjob", 427 "displayq short", 428 "displayq long", 429 "rmjob" 430 }; 431 432 static void 433 doit(void) 434 { 435 char *cp; 436 int n; 437 438 for (;;) { 439 cp = cbuf; 440 do { 441 if (cp >= &cbuf[sizeof(cbuf) - 1]) 442 fatal("Command line too long"); 443 if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { 444 if (n < 0) 445 fatal("Lost connection"); 446 return; 447 } 448 } while (*cp++ != '\n'); 449 *--cp = '\0'; 450 cp = cbuf; 451 if (lflag) { 452 if (*cp >= '\1' && *cp <= '\5') { 453 syslog(LOG_INFO, "%s requests %s %s", 454 from, cmdnames[(int)*cp], cp+1); 455 setproctitle("serving %s: %s %s", from, 456 cmdnames[(int)*cp], cp+1); 457 } 458 else 459 syslog(LOG_INFO, "bad request (%d) from %s", 460 *cp, from); 461 } 462 switch (*cp++) { 463 case '\1': /* check the queue and print any jobs there */ 464 printer = cp; 465 if (*printer == '\0') 466 printer = DEFLP; 467 printjob(); 468 break; 469 case '\2': /* receive files to be queued */ 470 if (!from_remote) { 471 syslog(LOG_INFO, "illegal request (%d)", *cp); 472 exit(1); 473 } 474 printer = cp; 475 if (*printer == '\0') 476 printer = DEFLP; 477 recvjob(); 478 break; 479 case '\3': /* display the queue (short form) */ 480 case '\4': /* display the queue (long form) */ 481 printer = cp; 482 if (*printer == '\0') 483 printer = DEFLP; 484 while (*cp) { 485 if (*cp != ' ') { 486 cp++; 487 continue; 488 } 489 *cp++ = '\0'; 490 while (isspace(*cp)) 491 cp++; 492 if (*cp == '\0') 493 break; 494 if (isdigit(*cp)) { 495 if (requests >= MAXREQUESTS) 496 fatal("Too many requests"); 497 requ[requests++] = atoi(cp); 498 } else { 499 if (users >= MAXUSERS) 500 fatal("Too many users"); 501 user[users++] = cp; 502 } 503 } 504 displayq(cbuf[0] - '\3'); 505 exit(0); 506 case '\5': /* remove a job from the queue */ 507 if (!from_remote) { 508 syslog(LOG_INFO, "illegal request (%d)", *cp); 509 exit(1); 510 } 511 printer = cp; 512 if (*printer == '\0') 513 printer = DEFLP; 514 while (*cp && *cp != ' ') 515 cp++; 516 if (!*cp) 517 break; 518 *cp++ = '\0'; 519 person = cp; 520 while (*cp) { 521 if (*cp != ' ') { 522 cp++; 523 continue; 524 } 525 *cp++ = '\0'; 526 while (isspace(*cp)) 527 cp++; 528 if (*cp == '\0') 529 break; 530 if (isdigit(*cp)) { 531 if (requests >= MAXREQUESTS) 532 fatal("Too many requests"); 533 requ[requests++] = atoi(cp); 534 } else { 535 if (users >= MAXUSERS) 536 fatal("Too many users"); 537 user[users++] = cp; 538 } 539 } 540 rmjob(); 541 break; 542 } 543 fatal("Illegal service request"); 544 } 545 } 546 547 /* 548 * Make a pass through the printcap database and start printing any 549 * files left from the last time the machine went down. 550 */ 551 static void 552 startup(void) 553 { 554 char *buf; 555 char *cp; 556 557 /* 558 * Restart the daemons. 559 */ 560 while (cgetnext(&buf, printcapdb) > 0) { 561 if (ckqueue(buf) <= 0) { 562 free(buf); 563 continue; /* no work to do for this printer */ 564 } 565 for (cp = buf; *cp; cp++) 566 if (*cp == '|' || *cp == ':') { 567 *cp = '\0'; 568 break; 569 } 570 if (lflag) 571 syslog(LOG_INFO, "work for %s", buf); 572 switch (fork()) { 573 case -1: 574 syslog(LOG_WARNING, "startup: cannot fork"); 575 mcleanup(0); 576 case 0: 577 printer = buf; 578 setproctitle("working on printer %s", printer); 579 cgetclose(); 580 printjob(); 581 /* NOTREACHED */ 582 default: 583 child_count++; 584 free(buf); 585 } 586 } 587 } 588 589 /* 590 * Make sure there's some work to do before forking off a child 591 */ 592 static int 593 ckqueue(char *cap) 594 { 595 struct dirent *d; 596 DIR *dirp; 597 char *spooldir; 598 599 if (cgetstr(cap, "sd", &spooldir) == -1) 600 spooldir = _PATH_DEFSPOOL; 601 if ((dirp = opendir(spooldir)) == NULL) 602 return (-1); 603 while ((d = readdir(dirp)) != NULL) { 604 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 605 continue; /* daemon control files only */ 606 closedir(dirp); 607 return (1); /* found something */ 608 } 609 closedir(dirp); 610 return (0); 611 } 612 613 #define DUMMY ":nobody::" 614 615 /* 616 * Check to see if the from host has access to the line printer. 617 */ 618 static void 619 chkhost(struct sockaddr *f, int check_opts) 620 { 621 struct addrinfo hints, *res, *r; 622 FILE *hostf; 623 int first = 1, good = 0; 624 char host[NI_MAXHOST], ip[NI_MAXHOST]; 625 char serv[NI_MAXSERV]; 626 int error; 627 628 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 629 NI_NUMERICSERV); 630 if (error) 631 fatal("Malformed from address"); 632 633 if (!(check_opts & LPD_NOPORTCHK) && 634 atoi(serv) >= IPPORT_RESERVED) 635 fatal("Connect from invalid port (%s)", serv); 636 637 /* Need real hostname for temporary filenames */ 638 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 639 NI_NAMEREQD); 640 if (error) { 641 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 642 NI_NUMERICHOST); 643 if (error) 644 fatal("Host name for your address unknown"); 645 else 646 fatal("Host name for your address (%s) unknown", host); 647 } 648 649 (void)strncpy(fromb, host, sizeof(fromb) - 1); 650 fromb[sizeof(fromb) - 1] = '\0'; 651 from = fromb; 652 653 /* need address in stringform for comparison (no DNS lookup here) */ 654 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 655 NI_NUMERICHOST); 656 if (error) 657 fatal("Cannot print address"); 658 659 /* Check for spoof, ala rlogind */ 660 memset(&hints, 0, sizeof(hints)); 661 hints.ai_family = PF_UNSPEC; 662 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 663 error = getaddrinfo(fromb, NULL, &hints, &res); 664 if (error) { 665 fatal("hostname for your address (%s) unknown: %s", host, 666 gai_strerror(error)); 667 } 668 good = 0; 669 for (r = res; good == 0 && r; r = r->ai_next) { 670 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 671 NULL, 0, NI_NUMERICHOST); 672 if (!error && !strcmp(host, ip)) 673 good = 1; 674 } 675 if (res) 676 freeaddrinfo(res); 677 if (good == 0) 678 fatal("address for your hostname (%s) not matched", host); 679 setproctitle("serving %s", from); 680 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 681 again: 682 if (hostf) { 683 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 684 (void)fclose(hostf); 685 return; 686 } 687 (void)fclose(hostf); 688 } 689 if (first == 1) { 690 first = 0; 691 hostf = fopen(_PATH_HOSTSLPD, "r"); 692 goto again; 693 } 694 fatal("Your host does not have line printer access"); 695 /*NOTREACHED*/ 696 } 697 698 699 static void 700 usage(void) 701 { 702 703 fprintf(stderr, "usage: %s [-dlrsW] [-b bind-address] [-n maxchild] " 704 "[-w maxwait] [port]\n", getprogname()); 705 exit(1); 706 } 707 708 /* setup server socket for specified address family */ 709 /* if af is PF_UNSPEC more than one socket may be returned */ 710 /* the returned list is dynamically allocated, so caller needs to free it */ 711 int * 712 socksetup(int af, int options, const char *port) 713 { 714 struct addrinfo hints, *res, *r; 715 int error, maxs = 0, *s, *socks = NULL, blidx = 0; 716 const int on = 1; 717 718 do { 719 memset(&hints, 0, sizeof(hints)); 720 hints.ai_flags = AI_PASSIVE; 721 hints.ai_family = af; 722 hints.ai_socktype = SOCK_STREAM; 723 error = getaddrinfo((blist_addrs == 0) ? NULL : blist[blidx], 724 port ? port : "printer", &hints, &res); 725 if (error) { 726 if (blist_addrs) 727 syslog(LOG_ERR, "%s: %s", blist[blidx], 728 gai_strerror(error)); 729 else 730 syslog(LOG_ERR, "%s", gai_strerror(error)); 731 mcleanup(0); 732 } 733 734 /* Count max number of sockets we may open */ 735 for (r = res; r; r = r->ai_next, maxs++) 736 ; 737 if (socks == NULL) { 738 socks = malloc((maxs + 1) * sizeof(int)); 739 if (socks) 740 *socks = 0; /* num of sockets ctr at start */ 741 } else 742 socks = realloc(socks, (maxs + 1) * sizeof(int)); 743 if (!socks) { 744 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 745 mcleanup(0); 746 } 747 748 s = socks + *socks + 1; 749 for (r = res; r; r = r->ai_next) { 750 *s = socket(r->ai_family, r->ai_socktype, 751 r->ai_protocol); 752 if (*s < 0) { 753 syslog(LOG_DEBUG, "socket(): %m"); 754 continue; 755 } 756 if (options & SO_DEBUG) 757 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, 758 &on, sizeof(on)) < 0) { 759 syslog(LOG_ERR, 760 "setsockopt (SO_DEBUG): %m"); 761 close (*s); 762 continue; 763 } 764 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 765 syslog(LOG_DEBUG, "bind(): %m"); 766 close (*s); 767 continue; 768 } 769 *socks = *socks + 1; 770 s++; 771 } 772 773 if (res) 774 freeaddrinfo(res); 775 } while (++blidx < blist_addrs); 776 777 if (socks == NULL || *socks == 0) { 778 syslog(LOG_ERR, "Couldn't bind to any socket"); 779 if (socks != NULL) 780 free(socks); 781 mcleanup(0); 782 } 783 return(socks); 784 } 785