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