lpd.c revision 1.47
1/* $OpenBSD: lpd.c,v 1.47 2007/09/02 15:19:38 deraadt 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#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static const char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 43#else 44static const char rcsid[] = "$OpenBSD: lpd.c,v 1.47 2007/09/02 15:19:38 deraadt 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 root and the group daemon. 66 * 2. Files in spooling area are owned by user daemon, group daemon, 67 * and are mode 660. 68 * 3. lpd runs as root but spends most of its time with its effective 69 * uid and gid set to the uid/gid specified in the passwd entry for 70 * DEFUID (1, aka daemon). 71 * 4. lpr and lprm run setuid daemon and setgrp daemon. lpr opens 72 * files to be printed with its real uid/gid and writes to 73 * the spool dir with its effective uid/gid (i.e. daemon). 74 * lprm need to run as user daemon so it can kill lpd. 75 * 5. lpc and lpq run setgrp daemon. 76 * 77 * Users can't touch the spool w/o the help of one of the lp* programs. 78 */ 79 80#include <sys/param.h> 81#include <sys/wait.h> 82#include <sys/types.h> 83#include <sys/socket.h> 84#include <sys/un.h> 85#include <sys/stat.h> 86#include <sys/file.h> 87#include <netinet/in.h> 88#include <arpa/inet.h> 89 90#include <ctype.h> 91#include <dirent.h> 92#include <err.h> 93#include <errno.h> 94#include <fcntl.h> 95#include <netdb.h> 96#include <pwd.h> 97#include <signal.h> 98#include <stdio.h> 99#include <stdlib.h> 100#include <string.h> 101#include <syslog.h> 102#include <unistd.h> 103 104#include "lp.h" 105#include "lp.local.h" 106#include "pathnames.h" 107#include "extern.h" 108 109int lflag; /* log requests flag */ 110int rflag; /* allow 'of' for remote printers */ 111int sflag; /* secure (no inet) flag */ 112int from_remote; /* from remote socket */ 113char **blist; /* list of addresses to bind(2) to */ 114int blist_size; 115int blist_addrs; 116 117volatile sig_atomic_t child_count; /* number of kids forked */ 118 119static void reapchild(int); 120static void mcleanup(int); 121static void doit(void); 122static void startup(void); 123static void chkhost(struct sockaddr *); 124static int ckqueue(char *); 125static __dead void usage(void); 126static int *socksetup(int, int, const char *); 127 128extern int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t, 129 const char *, const char *); 130 131/* unused, needed for lpc */ 132volatile sig_atomic_t gotintr; 133 134int 135main(int argc, char **argv) 136{ 137 fd_set defreadfds; 138 struct passwd *pw; 139 struct sockaddr_un un, fromunix; 140 struct sockaddr_storage frominet; 141 sigset_t mask, omask; 142 int lfd, i, f, funix, *finet; 143 int options, maxfd; 144 long l; 145 long child_max = 32; /* more than enough to hose the system */ 146 struct servent *sp; 147 const char *port = "printer"; 148 char *cp; 149 150 if (geteuid() != 0) 151 errx(1, "must run as root"); 152 153 /* 154 * We want to run with euid of daemon most of the time. 155 */ 156 if ((pw = getpwuid(DEFUID)) == NULL) 157 errx(1, "daemon uid (%u) not in password file", DEFUID); 158 real_uid = pw->pw_uid; 159 real_gid = pw->pw_gid; 160 effective_uid = 0; 161 effective_gid = getegid(); 162 PRIV_END; /* run as daemon for most things */ 163 164 options = 0; 165 gethostname(host, sizeof(host)); 166 167 while ((i = getopt(argc, argv, "b:dln:rsw:W")) != -1) { 168 switch (i) { 169 case 'b': 170 if (blist_addrs >= blist_size) { 171 if (blist == NULL) { 172 blist_size += sizeof(char *) * 4; 173 blist = malloc(blist_size); 174 } 175 else { 176 char **newblist; 177 int newblist_size = blist_size + 178 sizeof(char *) * 4; 179 newblist = realloc(blist, newblist_size); 180 if (newblist == NULL) { 181 free(blist); 182 blist_size = 0; 183 blist = NULL; 184 } 185 blist = newblist; 186 blist_size = newblist_size; 187 } 188 if (blist == NULL) 189 err(1, "cant allocate bind addr list"); 190 } 191 blist[blist_addrs] = strdup(optarg); 192 if (blist[blist_addrs++] == NULL) 193 err(1, NULL); 194 break; 195 case 'd': 196 options |= SO_DEBUG; 197 break; 198 case 'l': 199 lflag++; 200 break; 201 case 'n': 202 child_max = strtol(optarg, &cp, 10); 203 if (*cp != '\0' || child_max < 0 || child_max > 1024) 204 errx(1, "invalid number of children: %s", 205 optarg); 206 break; 207 case 'r': 208 rflag++; 209 break; 210 case 's': 211 sflag++; 212 break; 213 case 'w': 214 l = strtol(optarg, &cp, 10); 215 if (*cp != '\0' || l < 0 || l >= INT_MAX) 216 errx(1, "wait time must be postive integer: %s", 217 optarg); 218 wait_time = (u_int)l; 219 if (wait_time < 30) 220 warnx("warning: wait time less than 30 seconds"); 221 break; 222 case 'W': /* XXX deprecate */ 223 break; 224 default: 225 usage(); 226 break; 227 } 228 } 229 argc -= optind; 230 argv += optind; 231 232 switch (argc) { 233 case 1: 234 port = argv[0]; 235 l = strtol(port, &cp, 10); 236 if (*cp != '\0' || l <= 0 || l > USHRT_MAX) 237 errx(1, "port # %s is invalid", port); 238 break; 239 case 0: 240 sp = getservbyname(port, "tcp"); 241 if (sp == NULL) 242 errx(1, "%s/tcp: unknown service", port); 243 break; 244 default: 245 usage(); 246 } 247 248#ifndef DEBUG 249 /* 250 * Set up standard environment by detaching from the parent. 251 */ 252 daemon(0, 0); 253#endif 254 255 openlog("lpd", LOG_PID, LOG_LPR); 256 syslog(LOG_INFO, "restarted"); 257 (void)umask(0); 258 PRIV_START; 259 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644); 260 PRIV_END; 261 if (lfd < 0) { 262 if (errno == EWOULDBLOCK) /* active daemon present */ 263 exit(0); 264 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 265 exit(1); 266 } 267 ftruncate(lfd, 0); 268 /* 269 * write process id for others to know 270 */ 271 (void)snprintf(line, sizeof(line), "%u\n", getpid()); 272 f = strlen(line); 273 if (write(lfd, line, f) != f) { 274 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 275 exit(1); 276 } 277 signal(SIGCHLD, reapchild); 278 /* 279 * Restart all the printers. 280 */ 281 startup(); 282 PRIV_START; 283 (void)unlink(_PATH_SOCKETNAME); 284 PRIV_END; 285 funix = socket(AF_LOCAL, SOCK_STREAM, 0); 286 if (funix < 0) { 287 syslog(LOG_ERR, "socket: %m"); 288 exit(1); 289 } 290 291 sigemptyset(&mask); 292 sigaddset(&mask, SIGHUP); 293 sigaddset(&mask, SIGINT); 294 sigaddset(&mask, SIGQUIT); 295 sigaddset(&mask, SIGTERM); 296 sigprocmask(SIG_BLOCK, &mask, &omask); 297 298 signal(SIGHUP, mcleanup); 299 signal(SIGINT, mcleanup); 300 signal(SIGQUIT, mcleanup); 301 signal(SIGTERM, mcleanup); 302 memset(&un, 0, sizeof(un)); 303 un.sun_family = AF_LOCAL; 304 strlcpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path)); 305 PRIV_START; 306 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 307 syslog(LOG_ERR, "ubind: %m"); 308 exit(1); 309 } 310 chmod(_PATH_SOCKETNAME, 0660); 311 chown(_PATH_SOCKETNAME, -1, real_gid); 312 PRIV_END; 313 (void)umask(0); /* XXX */ 314 sigprocmask(SIG_SETMASK, &omask, NULL); 315 FD_ZERO(&defreadfds); 316 FD_SET(funix, &defreadfds); 317 listen(funix, 5); 318 if (!sflag || blist_addrs) 319 finet = socksetup(PF_UNSPEC, options, port); 320 else 321 finet = NULL; /* pretend we couldn't open TCP socket. */ 322 323 if (blist != NULL) { 324 for (i = 0; i < blist_addrs; i++) 325 free(blist[i]); 326 free(blist); 327 } 328 329 maxfd = funix; 330 if (finet) { 331 for (i = 1; i <= *finet; i++) { 332 FD_SET(finet[i], &defreadfds); 333 listen(finet[i], 5); 334 if (finet[i] > maxfd) 335 maxfd = finet[i]; 336 } 337 } 338 /* 339 * Main loop: accept, do a request, continue. 340 */ 341 memset(&frominet, 0, sizeof(frominet)); 342 memset(&fromunix, 0, sizeof(fromunix)); 343 for (;;) { 344 int domain, nfds, s; 345 socklen_t fromlen; 346 fd_set readfds; 347 short sleeptime = 10; /* overflows in about 2 hours */ 348 349 while (child_max < child_count) { 350 syslog(LOG_WARNING, 351 "too many children, sleeping for %d seconds", 352 sleeptime); 353 sleep(sleeptime); 354 sleeptime <<= 1; 355 if (sleeptime < 0) { 356 syslog(LOG_CRIT, "sleeptime overflowed! help!"); 357 sleeptime = 10; 358 } 359 } 360 361 FD_COPY(&defreadfds, &readfds); 362 nfds = select(maxfd + 1, &readfds, NULL, NULL, NULL); 363 if (nfds <= 0) { 364 if (nfds < 0 && errno != EINTR) 365 syslog(LOG_WARNING, "select: %m"); 366 continue; 367 } 368 if (FD_ISSET(funix, &readfds)) { 369 domain = AF_LOCAL; 370 fromlen = sizeof(fromunix); 371 s = accept(funix, 372 (struct sockaddr *)&fromunix, &fromlen); 373 } else { 374 domain = AF_INET; 375 s = -1; 376 for (i = 1; i <= *finet; i++) 377 if (FD_ISSET(finet[i], &readfds)) { 378 in_port_t port; 379 380 fromlen = sizeof(frominet); 381 s = accept(finet[i], 382 (struct sockaddr *)&frominet, 383 &fromlen); 384 switch (frominet.ss_family) { 385 case AF_INET: 386 port = ((struct sockaddr_in *) 387 &frominet)->sin_port; 388 break; 389 case AF_INET6: 390 port = ((struct sockaddr_in6 *) 391 &frominet)->sin6_port; 392 break; 393 default: 394 port = 0; 395 } 396 /* check for ftp bounce attack */ 397 if (port == htons(20)) { 398 close(s); 399 continue; 400 } 401 } 402 } 403 if (s < 0) { 404 if (errno != EINTR) 405 syslog(LOG_WARNING, "accept: %m"); 406 continue; 407 } 408 409 switch (fork()) { 410 case 0: 411 signal(SIGCHLD, SIG_DFL); 412 signal(SIGHUP, SIG_IGN); 413 signal(SIGINT, SIG_IGN); 414 signal(SIGQUIT, SIG_IGN); 415 signal(SIGTERM, SIG_IGN); 416 (void)close(funix); 417 if (!sflag && finet) 418 for (i = 1; i <= *finet; i++) 419 (void)close(finet[i]); 420 if (s != STDOUT_FILENO) { 421 dup2(s, STDOUT_FILENO); 422 (void)close(s); 423 } 424 if (domain == AF_INET) { 425 /* for both AF_INET and AF_INET6 */ 426 from_remote = 1; 427 chkhost((struct sockaddr *)&frominet); 428 } else 429 from_remote = 0; 430 doit(); 431 exit(0); 432 case -1: 433 syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds..."); 434 sleep(10); 435 continue; 436 default: 437 child_count++; 438 } 439 (void)close(s); 440 } 441} 442 443static void 444reapchild(int signo) 445{ 446 int save_errno = errno; 447 int status; 448 449 while (waitpid((pid_t)-1, &status, WNOHANG) > 0) 450 child_count--; 451 errno = save_errno; 452} 453 454static void 455mcleanup(int signo) 456{ 457 struct syslog_data sdata = SYSLOG_DATA_INIT; 458 459 if (lflag) 460 syslog_r(LOG_INFO, &sdata, "exiting"); 461 PRIV_START; 462 unlink(_PATH_SOCKETNAME); 463 unlink(_PATH_MASTERLOCK); 464 _exit(0); 465} 466 467/* 468 * Stuff for handling job specifications 469 */ 470char *user[MAXUSERS]; /* users to process */ 471int users; /* # of users in user array */ 472int requ[MAXREQUESTS]; /* job number of spool entries */ 473int requests; /* # of spool requests */ 474char *person; /* name of person doing lprm */ 475 476char fromb[NI_MAXHOST]; /* buffer for client's machine name */ 477char cbuf[BUFSIZ]; /* command line buffer */ 478char *cmdnames[] = { 479 "null", 480 "printjob", 481 "recvjob", 482 "displayq short", 483 "displayq long", 484 "rmjob" 485}; 486 487static void 488doit(void) 489{ 490 char *cp; 491 int n; 492 493 for (;;) { 494 cp = cbuf; 495 do { 496 if (cp >= &cbuf[sizeof(cbuf) - 1]) 497 fatal("Command line too long"); 498 if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { 499 if (n < 0) 500 fatal("Lost connection"); 501 return; 502 } 503 } while (*cp++ != '\n'); 504 *--cp = '\0'; 505 cp = cbuf; 506 if (lflag) { 507 if (*cp >= '\1' && *cp <= '\5') { 508 syslog(LOG_INFO, "%s requests %s %s", 509 from, cmdnames[(int)*cp], cp+1); 510 setproctitle("serving %s: %s %s", from, 511 cmdnames[(int)*cp], cp+1); 512 } else 513 syslog(LOG_INFO, "bad request (%d) from %s", 514 *cp, from); 515 } 516 switch (*cp++) { 517 case '\1': /* check the queue and print any jobs there */ 518 printer = cp; 519 if (*printer == '\0') 520 printer = DEFLP; 521 printjob(); 522 break; 523 case '\2': /* receive files to be queued */ 524 if (!from_remote) { 525 syslog(LOG_INFO, "illegal request (%d)", *cp); 526 exit(1); 527 } 528 printer = cp; 529 if (*printer == '\0') 530 printer = DEFLP; 531 recvjob(); 532 break; 533 case '\3': /* display the queue (short form) */ 534 case '\4': /* display the queue (long form) */ 535 printer = cp; 536 if (*printer == '\0') 537 printer = DEFLP; 538 while (*cp) { 539 if (*cp != ' ') { 540 cp++; 541 continue; 542 } 543 *cp++ = '\0'; 544 while (isspace(*cp)) 545 cp++; 546 if (*cp == '\0') 547 break; 548 if (isdigit(*cp)) { 549 if (requests >= MAXREQUESTS) 550 fatal("Too many requests"); 551 requ[requests++] = atoi(cp); 552 } else { 553 if (users >= MAXUSERS) 554 fatal("Too many users"); 555 user[users++] = cp; 556 } 557 } 558 displayq(cbuf[0] - '\3'); 559 exit(0); 560 case '\5': /* remove a job from the queue */ 561 if (!from_remote) { 562 syslog(LOG_INFO, "illegal request (%d)", *cp); 563 exit(1); 564 } 565 printer = cp; 566 if (*printer == '\0') 567 printer = DEFLP; 568 while (*cp && *cp != ' ') 569 cp++; 570 if (!*cp) 571 break; 572 *cp++ = '\0'; 573 person = cp; 574 while (*cp) { 575 if (*cp != ' ') { 576 cp++; 577 continue; 578 } 579 *cp++ = '\0'; 580 while (isspace(*cp)) 581 cp++; 582 if (*cp == '\0') 583 break; 584 if (isdigit(*cp)) { 585 if (requests >= MAXREQUESTS) 586 fatal("Too many requests"); 587 requ[requests++] = atoi(cp); 588 } else { 589 if (users >= MAXUSERS) 590 fatal("Too many users"); 591 user[users++] = cp; 592 } 593 } 594 rmjob(); 595 break; 596 } 597 fatal("Illegal service request"); 598 } 599} 600 601/* 602 * Make a pass through the printcap database and start printing any 603 * files left from the last time the machine went down. 604 */ 605static void 606startup(void) 607{ 608 char *buf, *cp; 609 610 /* 611 * Restart the daemons. 612 */ 613 while (cgetnext(&buf, printcapdb) > 0) { 614 if (ckqueue(buf) <= 0) { 615 free(buf); 616 continue; /* no work to do for this printer */ 617 } 618 for (cp = buf; *cp; cp++) 619 if (*cp == '|' || *cp == ':') { 620 *cp = '\0'; 621 break; 622 } 623 if (lflag) 624 syslog(LOG_INFO, "work for %s", buf); 625 switch (fork()) { 626 case -1: 627 syslog(LOG_WARNING, "startup: cannot fork"); 628 mcleanup(0); 629 /* NOTREACHED */ 630 case 0: 631 printer = buf; 632 setproctitle("working on printer %s", printer); 633 cgetclose(); 634 printjob(); 635 /* NOTREACHED */ 636 default: 637 child_count++; 638 free(buf); 639 } 640 } 641} 642 643/* 644 * Make sure there's some work to do before forking off a child 645 * XXX - could be common w/ lpq 646 */ 647static int 648ckqueue(char *cap) 649{ 650 struct dirent *d; 651 DIR *dirp; 652 char *spooldir; 653 654 if (cgetstr(cap, "sd", &spooldir) == -1) 655 spooldir = _PATH_DEFSPOOL; 656 dirp = opendir(spooldir); 657 if (spooldir != _PATH_DEFSPOOL) 658 free(spooldir); 659 if (dirp == NULL) 660 return (-1); 661 while ((d = readdir(dirp)) != NULL) { 662 if (d->d_name[0] == 'c' && d->d_name[1] == 'f') { 663 closedir(dirp); 664 return (1); /* found a cf file */ 665 } 666 } 667 closedir(dirp); 668 return (0); 669} 670 671#define DUMMY ":nobody::" 672 673/* 674 * Check to see if the from host has access to the line printer. 675 */ 676static void 677chkhost(struct sockaddr *f) 678{ 679 struct addrinfo hints, *res, *r; 680 FILE *hostf; 681 int first = 1; 682 int good = 0; 683 char host[NI_MAXHOST], ip[NI_MAXHOST]; 684 char serv[NI_MAXSERV]; 685 int error; 686 687 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 688 NI_NUMERICSERV); 689 if (error) 690 fatal("Malformed from address"); 691 692 /* Need real hostname for temporary filenames */ 693 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 694 NI_NAMEREQD); 695 if (error) { 696 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 697 NI_NUMERICHOST); 698 if (error) 699 fatal("Host name for your address unknown"); 700 else 701 fatal("Host name for your address (%s) unknown", host); 702 } 703 704 (void)strlcpy(fromb, host, sizeof(fromb)); 705 from = fromb; 706 707 /* need address in stringform for comparison (no DNS lookup here) */ 708 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 709 NI_NUMERICHOST); 710 if (error) 711 fatal("Cannot print address"); 712 713 /* Check for spoof, ala rlogind */ 714 memset(&hints, 0, sizeof(hints)); 715 hints.ai_family = PF_UNSPEC; 716 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 717 error = getaddrinfo(fromb, NULL, &hints, &res); 718 if (error) { 719 fatal("hostname for your address (%s) unknown: %s", host, 720 gai_strerror(error)); 721 } 722 for (good = 0, r = res; good == 0 && r; r = r->ai_next) { 723 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 724 NULL, 0, NI_NUMERICHOST); 725 if (!error && !strcmp(host, ip)) 726 good = 1; 727 } 728 if (res) 729 freeaddrinfo(res); 730 if (good == 0) 731 fatal("address for your hostname (%s) not matched", host); 732 setproctitle("serving %s", from); 733 PRIV_START; 734 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 735 PRIV_END; 736again: 737 if (hostf) { 738 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 739 (void)fclose(hostf); 740 return; 741 } 742 (void)fclose(hostf); 743 } 744 if (first == 1) { 745 first = 0; 746 PRIV_START; 747 hostf = fopen(_PATH_HOSTSLPD, "r"); 748 PRIV_END; 749 goto again; 750 } 751 fatal("Your host does not have line printer access"); 752 /*NOTREACHED*/ 753} 754 755static __dead void 756usage(void) 757{ 758 extern char *__progname; 759 760 fprintf(stderr, "usage: %s [-dlrs] [-b bind-address] [-n maxchild] " 761 "[-w maxwait] [port]\n", __progname); 762 exit(1); 763} 764 765/* 766 * Setup server socket for specified address family. 767 * If af is PF_UNSPEC more than one socket may be returned. 768 * The returned list is dynamically allocated, so the caller needs to free it. 769 */ 770int * 771socksetup(int af, int options, const char *port) 772{ 773 struct addrinfo hints, *res, *r; 774 int error, maxs = 0, *s, *socks = NULL, *newsocks, blidx = 0; 775 const int on = 1; 776 777 do { 778 memset(&hints, 0, sizeof(hints)); 779 hints.ai_flags = AI_PASSIVE; 780 hints.ai_family = af; 781 hints.ai_socktype = SOCK_STREAM; 782 error = getaddrinfo((blist_addrs == 0) ? NULL : blist[blidx], 783 port ? port : "printer", &hints, &res); 784 if (error) { 785 if (blist_addrs) 786 syslog(LOG_ERR, "%s: %s", blist[blidx], 787 gai_strerror(error)); 788 else 789 syslog(LOG_ERR, "%s", gai_strerror(error)); 790 mcleanup(0); 791 } 792 793 /* Count max number of sockets we may open */ 794 for (r = res; r; r = r->ai_next, maxs++) 795 ; 796 if (socks == NULL) { 797 socks = calloc(maxs + 1, sizeof(int)); 798 if (socks) 799 *socks = 0; /* num of sockets ctr at start */ 800 } else { 801 newsocks = realloc(socks, (maxs + 1) * sizeof(int)); 802 if (newsocks) 803 socks = newsocks; 804 else { 805 free(socks); 806 socks = NULL; 807 } 808 } 809 if (!socks) { 810 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 811 mcleanup(0); 812 } 813 814 s = socks + *socks + 1; 815 for (r = res; r; r = r->ai_next) { 816 *s = socket(r->ai_family, r->ai_socktype, 817 r->ai_protocol); 818 if (*s < 0) { 819 syslog(LOG_DEBUG, "socket(): %m"); 820 continue; 821 } 822 if (options & SO_DEBUG) 823 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, 824 &on, sizeof(on)) < 0) { 825 syslog(LOG_ERR, 826 "setsockopt (SO_DEBUG): %m"); 827 close (*s); 828 continue; 829 } 830 PRIV_START; 831 error = bind(*s, r->ai_addr, r->ai_addrlen); 832 PRIV_END; 833 if (error < 0) { 834 syslog(LOG_DEBUG, "bind(): %m"); 835 close (*s); 836 continue; 837 } 838 *socks = *socks + 1; 839 s++; 840 } 841 842 if (res) 843 freeaddrinfo(res); 844 } while (++blidx < blist_addrs); 845 846 if (socks == NULL || *socks == 0) { 847 syslog(LOG_ERR, "Couldn't bind to any socket"); 848 if (socks != NULL) 849 free(socks); 850 mcleanup(0); 851 } 852 return(socks); 853} 854