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 #ifdef INET6 168 family = PF_INET6; 169 inet6_flag++; 170 #else 171 errx(EX_USAGE, "lpd compiled sans INET6 (IPv6 support)"); 172 #endif 173 break; 174 default: 175 errs++; 176 } 177 if (inet_flag && inet6_flag) 178 family = PF_UNSPEC; 179 argc -= optind; 180 argv += optind; 181 if (errs) 182 usage(); 183 184 if (argc == 1) { 185 if ((i = atoi(argv[0])) == 0) 186 usage(); 187 if (i < 0 || i > USHRT_MAX) 188 errx(EX_USAGE, "port # %d is invalid", i); 189 190 serv.s_port = htons(i); 191 sp = &serv; 192 argc--; 193 } else { 194 sp = getservbyname("printer", "tcp"); 195 if (sp == NULL) 196 errx(EX_OSFILE, "printer/tcp: unknown service"); 197 } 198 199 if (argc != 0) 200 usage(); 201 202 /* 203 * We run chkprintcap right away to catch any errors and blat them 204 * to stderr while we still have it open, rather than sending them 205 * to syslog and leaving the user wondering why lpd started and 206 * then stopped. There should probably be a command-line flag to 207 * ignore errors from chkprintcap. 208 */ 209 { 210 pid_t pid; 211 int status; 212 pid = fork(); 213 if (pid < 0) { 214 err(EX_OSERR, "cannot fork"); 215 } else if (pid == 0) { /* child */ 216 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 217 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 218 } 219 if (waitpid(pid, &status, 0) < 0) { 220 err(EX_OSERR, "cannot wait"); 221 } 222 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 223 errx(EX_OSFILE, "%d errors in printcap file, exiting", 224 WEXITSTATUS(status)); 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, "lpd startup: logging=%d%s", lflag, 236 socket_debug ? " dbg" : ""); 237 (void) umask(0); 238 /* 239 * NB: This depends on O_NONBLOCK semantics doing the right thing; 240 * i.e., applying only to the O_EXLOCK and not to the rest of the 241 * open/creation. As of 1997-12-02, this is the case for commonly- 242 * used filesystems. There are other places in this code which 243 * make the same assumption. 244 */ 245 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 246 LOCK_FILE_MODE); 247 if (lfd < 0) { 248 if (errno == EWOULDBLOCK) /* active deamon present */ 249 exit(0); 250 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 251 exit(1); 252 } 253 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 254 ftruncate(lfd, 0); 255 /* 256 * write process id for others to know 257 */ 258 sprintf(line, "%u\n", getpid()); 259 f = strlen(line); 260 if (write(lfd, line, f) != f) { 261 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 262 exit(1); 263 } 264 signal(SIGCHLD, reapchild); 265 /* 266 * Restart all the printers. 267 */ 268 startup(); 269 (void) unlink(_PATH_SOCKETNAME); 270 funix = socket(AF_UNIX, SOCK_STREAM, 0); 271 if (funix < 0) { 272 syslog(LOG_ERR, "socket: %m"); 273 exit(1); 274 } 275 276 sigemptyset(&nmask); 277 sigaddset(&nmask, SIGHUP); 278 sigaddset(&nmask, SIGINT); 279 sigaddset(&nmask, SIGQUIT); 280 sigaddset(&nmask, SIGTERM); 281 sigprocmask(SIG_BLOCK, &nmask, &omask); 282 283 (void) umask(07); 284 signal(SIGHUP, mcleanup); 285 signal(SIGINT, mcleanup); 286 signal(SIGQUIT, mcleanup); 287 signal(SIGTERM, mcleanup); 288 memset(&un, 0, sizeof(un)); 289 un.sun_family = AF_UNIX; 290 strcpy(un.sun_path, _PATH_SOCKETNAME); 291 #ifndef SUN_LEN 292 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 293 #endif 294 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 295 syslog(LOG_ERR, "ubind: %m"); 296 exit(1); 297 } 298 (void) umask(0); 299 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 300 FD_ZERO(&defreadfds); 301 FD_SET(funix, &defreadfds); 302 listen(funix, 5); 303 if (pflag == 0) { 304 options = SO_REUSEADDR; 305 if (socket_debug) 306 options |= SO_DEBUG; 307 finet = socksetup(family, options); 308 } else 309 finet = NULL; /* pretend we couldn't open TCP socket. */ 310 if (finet) { 311 for (i = 1; i <= *finet; i++) { 312 FD_SET(finet[i], &defreadfds); 313 listen(finet[i], 5); 314 } 315 } 316 /* 317 * Main loop: accept, do a request, continue. 318 */ 319 memset(&frominet, 0, sizeof(frominet)); 320 memset(&fromunix, 0, sizeof(fromunix)); 321 if (lflag) 322 syslog(LOG_INFO, "lpd startup: ready to accept requests"); 323 /* 324 * XXX - should be redone for multi-protocol 325 */ 326 for (;;) { 327 int domain = -1, nfds, s = -1; 328 fd_set readfds; 329 330 FD_COPY(&defreadfds, &readfds); 331 nfds = select(20, &readfds, 0, 0, 0); 332 if (nfds <= 0) { 333 if (nfds < 0 && errno != EINTR) 334 syslog(LOG_WARNING, "select: %m"); 335 continue; 336 } 337 domain = 0; /* avoid compile-time warning */ 338 s = 0; /* avoid compile-time warning */ 339 if (FD_ISSET(funix, &readfds)) { 340 domain = AF_UNIX, fromlen = sizeof(fromunix); 341 s = accept(funix, 342 (struct sockaddr *)&fromunix, &fromlen); 343 } else { 344 for (i = 1; i <= *finet; i++) 345 if (FD_ISSET(finet[i], &readfds)) { 346 domain = AF_INET; 347 fromlen = sizeof(frominet); 348 s = accept(finet[i], 349 (struct sockaddr *)&frominet, 350 &fromlen); 351 } 352 } 353 if (s < 0) { 354 if (errno != EINTR) 355 syslog(LOG_WARNING, "accept: %m"); 356 continue; 357 } 358 if (fork() == 0) { 359 signal(SIGCHLD, SIG_IGN); 360 signal(SIGHUP, SIG_IGN); 361 signal(SIGINT, SIG_IGN); 362 signal(SIGQUIT, SIG_IGN); 363 signal(SIGTERM, SIG_IGN); 364 (void) close(funix); 365 if (pflag == 0 && finet) { 366 for (i = 1; i <= *finet; i++) 367 (void)close(finet[i]); 368 } 369 dup2(s, 1); 370 (void) close(s); 371 if (domain == AF_INET) { 372 /* for both AF_INET and AF_INET6 */ 373 from_remote = 1; 374 chkhost((struct sockaddr *)&frominet); 375 } else 376 from_remote = 0; 377 doit(); 378 exit(0); 379 } 380 (void) close(s); 381 } 382 } 383 384 static void 385 reapchild(signo) 386 int signo; 387 { 388 union wait status; 389 390 while (wait3((int *)&status, WNOHANG, 0) > 0) 391 ; 392 } 393 394 static void 395 mcleanup(signo) 396 int signo; 397 { 398 /* 399 * XXX syslog(3) is not signal-safe. 400 */ 401 if (lflag) { 402 if (signo) 403 syslog(LOG_INFO, "exiting on signal %d", signo); 404 else 405 syslog(LOG_INFO, "exiting"); 406 } 407 unlink(_PATH_SOCKETNAME); 408 exit(0); 409 } 410 411 /* 412 * Stuff for handling job specifications 413 */ 414 char *user[MAXUSERS]; /* users to process */ 415 int users; /* # of users in user array */ 416 int requ[MAXREQUESTS]; /* job number of spool entries */ 417 int requests; /* # of spool requests */ 418 char *person; /* name of person doing lprm */ 419 420 char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ 421 char cbuf[BUFSIZ]; /* command line buffer */ 422 char *cmdnames[] = { 423 "null", 424 "printjob", 425 "recvjob", 426 "displayq short", 427 "displayq long", 428 "rmjob" 429 }; 430 431 static void 432 doit() 433 { 434 char *cp, *printer; 435 int n; 436 int status; 437 struct printer myprinter, *pp = &myprinter; 438 439 init_printer(&myprinter); 440 441 for (;;) { 442 cp = cbuf; 443 do { 444 if (cp >= &cbuf[sizeof(cbuf) - 1]) 445 fatal(0, "Command line too long"); 446 if ((n = read(1, cp, 1)) != 1) { 447 if (n < 0) 448 fatal(0, "Lost connection"); 449 return; 450 } 451 } while (*cp++ != '\n'); 452 *--cp = '\0'; 453 cp = cbuf; 454 if (lflag) { 455 if (*cp >= '\1' && *cp <= '\5') 456 syslog(LOG_INFO, "%s requests %s %s", 457 from, cmdnames[(u_char)*cp], cp+1); 458 else 459 syslog(LOG_INFO, "bad request (%d) from %s", 460 *cp, from); 461 } 462 switch (*cp++) { 463 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 464 startprinting(cp); 465 break; 466 case CMD_TAKE_THIS: /* receive files to be queued */ 467 if (!from_remote) { 468 syslog(LOG_INFO, "illegal request (%d)", *cp); 469 exit(1); 470 } 471 recvjob(cp); 472 break; 473 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 474 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 475 /* XXX - this all needs to be redone. */ 476 printer = cp; 477 while (*cp) { 478 if (*cp != ' ') { 479 cp++; 480 continue; 481 } 482 *cp++ = '\0'; 483 while (isspace(*cp)) 484 cp++; 485 if (*cp == '\0') 486 break; 487 if (isdigit(*cp)) { 488 if (requests >= MAXREQUESTS) 489 fatal(0, "Too many requests"); 490 requ[requests++] = atoi(cp); 491 } else { 492 if (users >= MAXUSERS) 493 fatal(0, "Too many users"); 494 user[users++] = cp; 495 } 496 } 497 status = getprintcap(printer, pp); 498 if (status < 0) 499 fatal(pp, pcaperr(status)); 500 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 501 exit(0); 502 case CMD_RMJOB: /* remove a job from the queue */ 503 if (!from_remote) { 504 syslog(LOG_INFO, "illegal request (%d)", *cp); 505 exit(1); 506 } 507 printer = cp; 508 while (*cp && *cp != ' ') 509 cp++; 510 if (!*cp) 511 break; 512 *cp++ = '\0'; 513 person = cp; 514 while (*cp) { 515 if (*cp != ' ') { 516 cp++; 517 continue; 518 } 519 *cp++ = '\0'; 520 while (isspace(*cp)) 521 cp++; 522 if (*cp == '\0') 523 break; 524 if (isdigit(*cp)) { 525 if (requests >= MAXREQUESTS) 526 fatal(0, "Too many requests"); 527 requ[requests++] = atoi(cp); 528 } else { 529 if (users >= MAXUSERS) 530 fatal(0, "Too many users"); 531 user[users++] = cp; 532 } 533 } 534 rmjob(printer); 535 break; 536 } 537 fatal(0, "Illegal service request"); 538 } 539 } 540 541 /* 542 * Make a pass through the printcap database and start printing any 543 * files left from the last time the machine went down. 544 */ 545 static void 546 startup() 547 { 548 int pid, status, more; 549 struct printer myprinter, *pp = &myprinter; 550 551 more = firstprinter(pp, &status); 552 if (status) 553 goto errloop; 554 while (more) { 555 if (ckqueue(pp) <= 0) { 556 goto next; 557 } 558 if (lflag) 559 syslog(LOG_INFO, "lpd startup: work for %s", 560 pp->printer); 561 if ((pid = fork()) < 0) { 562 syslog(LOG_WARNING, "lpd startup: cannot fork for %s", 563 pp->printer); 564 mcleanup(0); 565 } 566 if (pid == 0) { 567 lastprinter(); 568 printjob(pp); 569 /* NOTREACHED */ 570 } 571 do { 572 next: 573 more = nextprinter(pp, &status); 574 errloop: 575 if (status) 576 syslog(LOG_WARNING, 577 "lpd startup: printcap entry for %s has errors, skipping", 578 pp->printer ? pp->printer : "<???>"); 579 } while (more && status); 580 } 581 } 582 583 /* 584 * Make sure there's some work to do before forking off a child 585 */ 586 static int 587 ckqueue(pp) 588 struct printer *pp; 589 { 590 register struct dirent *d; 591 DIR *dirp; 592 char *spooldir; 593 594 spooldir = pp->spool_dir; 595 if ((dirp = opendir(spooldir)) == NULL) 596 return (-1); 597 while ((d = readdir(dirp)) != NULL) { 598 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 599 continue; /* daemon control files only */ 600 closedir(dirp); 601 return (1); /* found something */ 602 } 603 closedir(dirp); 604 return (0); 605 } 606 607 #define DUMMY ":nobody::" 608 609 /* 610 * Check to see if the from host has access to the line printer. 611 */ 612 static void 613 chkhost(f) 614 struct sockaddr *f; 615 { 616 struct addrinfo hints, *res, *r; 617 register FILE *hostf; 618 int first = 1; 619 int good = 0; 620 char host[NI_MAXHOST], ip[NI_MAXHOST]; 621 char serv[NI_MAXSERV]; 622 int error, addrlen; 623 caddr_t addr; 624 625 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 626 NI_NUMERICSERV); 627 if (error || atoi(serv) >= IPPORT_RESERVED) 628 fatal(0, "Malformed from address"); 629 630 /* Need real hostname for temporary filenames */ 631 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 632 NI_NAMEREQD); 633 if (error) { 634 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 635 NI_NUMERICHOST | NI_WITHSCOPEID); 636 if (error) 637 fatal(0, "Host name for your address unknown"); 638 else 639 fatal(0, "Host name for your address (%s) unknown", 640 host); 641 } 642 643 (void)strncpy(fromb, host, sizeof(fromb) - 1); 644 fromb[sizeof(fromb) - 1] = '\0'; 645 from = fromb; 646 647 /* Need address in stringform for comparison (no DNS lookup here) */ 648 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 649 NI_NUMERICHOST | NI_WITHSCOPEID); 650 if (error) 651 fatal(0, "Cannot print address"); 652 strncpy(from_ip, host, NI_MAXHOST); 653 from_ip[sizeof(from_ip) - 1] = '\0'; 654 655 /* Reject numeric addresses */ 656 memset(&hints, 0, sizeof(hints)); 657 hints.ai_family = family; 658 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 659 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 660 if (getaddrinfo(fromb, NULL, &hints, &res) == 0) { 661 freeaddrinfo(res); 662 fatal(0, "reverse lookup results in non-FQDN %s", fromb); 663 } 664 665 /* Check for spoof, ala rlogind */ 666 memset(&hints, 0, sizeof(hints)); 667 hints.ai_family = family; 668 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 669 error = getaddrinfo(fromb, NULL, &hints, &res); 670 if (error) { 671 fatal(0, "hostname for your address (%s) unknown: %s", from_ip, 672 gai_strerror(error)); 673 } 674 good = 0; 675 for (r = res; good == 0 && r; r = r->ai_next) { 676 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 677 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); 678 if (!error && !strcmp(from_ip, ip)) 679 good = 1; 680 } 681 if (res) 682 freeaddrinfo(res); 683 if (good == 0) 684 fatal(0, "address for your hostname (%s) not matched", 685 from_ip); 686 687 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 688 again: 689 if (hostf) { 690 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 691 (void) fclose(hostf); 692 return; 693 } 694 (void) fclose(hostf); 695 } 696 if (first == 1) { 697 first = 0; 698 hostf = fopen(_PATH_HOSTSLPD, "r"); 699 goto again; 700 } 701 fatal(0, "Your host does not have line printer access"); 702 /*NOTREACHED*/ 703 } 704 705 /* setup server socket for specified address family */ 706 /* if af is PF_UNSPEC more than one socket may be returned */ 707 /* the returned list is dynamically allocated, so caller needs to free it */ 708 static int * 709 socksetup(af, options) 710 int af, options; 711 { 712 struct addrinfo hints, *res, *r; 713 int error, maxs, *s, *socks; 714 const int on = 1; 715 716 memset(&hints, 0, sizeof(hints)); 717 hints.ai_flags = AI_PASSIVE; 718 hints.ai_family = af; 719 hints.ai_socktype = SOCK_STREAM; 720 error = getaddrinfo(NULL, "printer", &hints, &res); 721 if (error) { 722 syslog(LOG_ERR, "%s", gai_strerror(error)); 723 mcleanup(0); 724 } 725 726 /* Count max number of sockets we may open */ 727 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 728 ; 729 socks = malloc((maxs + 1) * sizeof(int)); 730 if (!socks) { 731 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 732 mcleanup(0); 733 } 734 735 *socks = 0; /* num of sockets counter at start of array */ 736 s = socks + 1; 737 for (r = res; r; r = r->ai_next) { 738 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 739 if (*s < 0) { 740 syslog(LOG_DEBUG, "socket(): %m"); 741 continue; 742 } 743 if (options & SO_REUSEADDR) 744 if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, 745 sizeof(on)) < 0) { 746 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 747 close(*s); 748 continue; 749 } 750 if (options & SO_DEBUG) 751 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, 752 &on, sizeof(on)) < 0) { 753 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 754 close(*s); 755 continue; 756 } 757 #ifdef IPV6_BINDV6ONLY 758 if (r->ai_family == AF_INET6) { 759 if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY, 760 &on, sizeof(on)) < 0) { 761 syslog(LOG_ERR, 762 "setsockopt (IPV6_BINDV6ONLY): %m"); 763 close(*s); 764 continue; 765 } 766 } 767 #endif 768 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 769 syslog(LOG_DEBUG, "bind(): %m"); 770 close(*s); 771 continue; 772 } 773 (*socks)++; 774 s++; 775 } 776 777 if (res) 778 freeaddrinfo(res); 779 780 if (*socks == 0) { 781 syslog(LOG_ERR, "Couldn't bind to any socket"); 782 free(socks); 783 mcleanup(0); 784 } 785 return(socks); 786 } 787 788 static void 789 usage() 790 { 791 #ifdef INET6 792 fprintf(stderr, "usage: lpd [-dlp46] [port#]\n"); 793 #else 794 fprintf(stderr, "usage: lpd [-dlp] [port#]\n"); 795 #endif 796 exit(EX_USAGE); 797 } 798