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(int argc, char **_argv); 111 static void reapchild(int _signo); 112 static void mcleanup(int _signo); 113 static void doit(void); 114 static void startup(void); 115 static void chkhost(struct sockaddr *_f, int _ch_opts); 116 static int ckqueue(struct printer *_pp); 117 static void fhosterr(int _dosys, const char *_sysmsg, const char *_usermsg, 118 ...) __printf0like(3, 4); 119 static int *socksetup(int _af, int _debuglvl); 120 static void usage(void); 121 122 /* XXX from libc/net/rcmd.c */ 123 extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t, 124 const char *, const char *)); 125 126 uid_t uid, euid; 127 128 #define LPD_NOPORTCHK 0001 /* skip reserved-port check */ 129 #define LPD_LOGCONNERR 0002 /* (sys)log connection errors */ 130 131 int 132 main(int argc, char **argv) 133 { 134 int ch_options, errs, f, funix, *finet, i, lfd, socket_debug; 135 fd_set defreadfds; 136 struct sockaddr_un un, fromunix; 137 struct sockaddr_storage frominet; 138 socklen_t fromlen; 139 sigset_t omask, nmask; 140 struct servent *sp, serv; 141 int inet_flag = 0, inet6_flag = 0; 142 143 euid = geteuid(); /* these shouldn't be different */ 144 uid = getuid(); 145 146 ch_options = 0; 147 socket_debug = 0; 148 gethostname(local_host, sizeof(local_host)); 149 150 progname = "lpd"; 151 152 if (euid != 0) 153 errx(EX_NOPERM,"must run as root"); 154 155 errs = 0; 156 while ((i = getopt(argc, argv, "cdlpwW46")) != -1) 157 switch (i) { 158 case 'c': 159 /* log all kinds of connection-errors to syslog */ 160 ch_options |= LPD_LOGCONNERR; 161 break; 162 case 'd': 163 socket_debug++; 164 break; 165 case 'l': 166 lflag++; 167 break; 168 case 'p': 169 pflag++; 170 break; 171 case 'w': /* netbsd uses -w for maxwait */ 172 /* 173 * This will be removed after the release of 4.4, as 174 * it conflicts with -w in netbsd's lpd. For now it 175 * is just a warning, so we won't suddenly break lpd 176 * for anyone who is currently using the option. 177 */ 178 syslog(LOG_WARNING, 179 "NOTE: the -w option has been renamed -W"); 180 syslog(LOG_WARNING, 181 "NOTE: please change your lpd config to use -W"); 182 /* FALLTHROUGH */ 183 case 'W': 184 /* allow connections coming from a non-reserved port */ 185 /* (done by some lpr-implementations for MS-Windows) */ 186 ch_options |= LPD_NOPORTCHK; 187 break; 188 case '4': 189 family = PF_INET; 190 inet_flag++; 191 break; 192 case '6': 193 #ifdef INET6 194 family = PF_INET6; 195 inet6_flag++; 196 #else 197 errx(EX_USAGE, "lpd compiled sans INET6 (IPv6 support)"); 198 #endif 199 break; 200 /* 201 * The following options are not in FreeBSD (yet?), but are 202 * listed here to "reserve" them, because the option-letters 203 * are used by either NetBSD or OpenBSD (as of July 2001). 204 */ 205 case 'b': /* set bind-addr */ 206 case 'n': /* set max num of children */ 207 case 'r': /* allow 'of' for remote ptrs */ 208 /* ...[not needed in freebsd] */ 209 case 's': /* secure (no inet), same as -p */ 210 /* FALLTHROUGH */ 211 default: 212 errs++; 213 } 214 if (inet_flag && inet6_flag) 215 family = PF_UNSPEC; 216 argc -= optind; 217 argv += optind; 218 if (errs) 219 usage(); 220 221 if (argc == 1) { 222 if ((i = atoi(argv[0])) == 0) 223 usage(); 224 if (i < 0 || i > USHRT_MAX) 225 errx(EX_USAGE, "port # %d is invalid", i); 226 227 serv.s_port = htons(i); 228 sp = &serv; 229 argc--; 230 } else { 231 sp = getservbyname("printer", "tcp"); 232 if (sp == NULL) 233 errx(EX_OSFILE, "printer/tcp: unknown service"); 234 } 235 236 if (argc != 0) 237 usage(); 238 239 /* 240 * We run chkprintcap right away to catch any errors and blat them 241 * to stderr while we still have it open, rather than sending them 242 * to syslog and leaving the user wondering why lpd started and 243 * then stopped. There should probably be a command-line flag to 244 * ignore errors from chkprintcap. 245 */ 246 { 247 pid_t pid; 248 int status; 249 pid = fork(); 250 if (pid < 0) { 251 err(EX_OSERR, "cannot fork"); 252 } else if (pid == 0) { /* child */ 253 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 254 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 255 } 256 if (waitpid(pid, &status, 0) < 0) { 257 err(EX_OSERR, "cannot wait"); 258 } 259 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 260 errx(EX_OSFILE, "%d errors in printcap file, exiting", 261 WEXITSTATUS(status)); 262 } 263 264 #ifndef DEBUG 265 /* 266 * Set up standard environment by detaching from the parent. 267 */ 268 daemon(0, 0); 269 #endif 270 271 openlog("lpd", LOG_PID, LOG_LPR); 272 syslog(LOG_INFO, "lpd startup: logging=%d%s", lflag, 273 socket_debug ? " dbg" : ""); 274 (void) umask(0); 275 /* 276 * NB: This depends on O_NONBLOCK semantics doing the right thing; 277 * i.e., applying only to the O_EXLOCK and not to the rest of the 278 * open/creation. As of 1997-12-02, this is the case for commonly- 279 * used filesystems. There are other places in this code which 280 * make the same assumption. 281 */ 282 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 283 LOCK_FILE_MODE); 284 if (lfd < 0) { 285 if (errno == EWOULDBLOCK) /* active deamon present */ 286 exit(0); 287 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 288 exit(1); 289 } 290 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 291 ftruncate(lfd, 0); 292 /* 293 * write process id for others to know 294 */ 295 sprintf(line, "%u\n", getpid()); 296 f = strlen(line); 297 if (write(lfd, line, f) != f) { 298 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 299 exit(1); 300 } 301 signal(SIGCHLD, reapchild); 302 /* 303 * Restart all the printers. 304 */ 305 startup(); 306 (void) unlink(_PATH_SOCKETNAME); 307 funix = socket(AF_UNIX, SOCK_STREAM, 0); 308 if (funix < 0) { 309 syslog(LOG_ERR, "socket: %m"); 310 exit(1); 311 } 312 313 sigemptyset(&nmask); 314 sigaddset(&nmask, SIGHUP); 315 sigaddset(&nmask, SIGINT); 316 sigaddset(&nmask, SIGQUIT); 317 sigaddset(&nmask, SIGTERM); 318 sigprocmask(SIG_BLOCK, &nmask, &omask); 319 320 (void) umask(07); 321 signal(SIGHUP, mcleanup); 322 signal(SIGINT, mcleanup); 323 signal(SIGQUIT, mcleanup); 324 signal(SIGTERM, mcleanup); 325 memset(&un, 0, sizeof(un)); 326 un.sun_family = AF_UNIX; 327 strcpy(un.sun_path, _PATH_SOCKETNAME); 328 #ifndef SUN_LEN 329 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 330 #endif 331 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 332 syslog(LOG_ERR, "ubind: %m"); 333 exit(1); 334 } 335 (void) umask(0); 336 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 337 FD_ZERO(&defreadfds); 338 FD_SET(funix, &defreadfds); 339 listen(funix, 5); 340 if (pflag == 0) { 341 finet = socksetup(family, socket_debug); 342 } else 343 finet = NULL; /* pretend we couldn't open TCP socket. */ 344 if (finet) { 345 for (i = 1; i <= *finet; i++) { 346 FD_SET(finet[i], &defreadfds); 347 listen(finet[i], 5); 348 } 349 } 350 /* 351 * Main loop: accept, do a request, continue. 352 */ 353 memset(&frominet, 0, sizeof(frominet)); 354 memset(&fromunix, 0, sizeof(fromunix)); 355 if (lflag) 356 syslog(LOG_INFO, "lpd startup: ready to accept requests"); 357 /* 358 * XXX - should be redone for multi-protocol 359 */ 360 for (;;) { 361 int domain, nfds, s; 362 fd_set readfds; 363 364 FD_COPY(&defreadfds, &readfds); 365 nfds = select(20, &readfds, 0, 0, 0); 366 if (nfds <= 0) { 367 if (nfds < 0 && errno != EINTR) 368 syslog(LOG_WARNING, "select: %m"); 369 continue; 370 } 371 domain = -1; /* avoid compile-time warning */ 372 s = -1; /* avoid compile-time warning */ 373 if (FD_ISSET(funix, &readfds)) { 374 domain = AF_UNIX, fromlen = sizeof(fromunix); 375 s = accept(funix, 376 (struct sockaddr *)&fromunix, &fromlen); 377 } else { 378 for (i = 1; i <= *finet; i++) 379 if (FD_ISSET(finet[i], &readfds)) { 380 domain = AF_INET; 381 fromlen = sizeof(frominet); 382 s = accept(finet[i], 383 (struct sockaddr *)&frominet, 384 &fromlen); 385 } 386 } 387 if (s < 0) { 388 if (errno != EINTR) 389 syslog(LOG_WARNING, "accept: %m"); 390 continue; 391 } 392 if (fork() == 0) { 393 /* 394 * Note that printjob() also plays around with 395 * signal-handling routines, and may need to be 396 * changed when making changes to signal-handling. 397 */ 398 signal(SIGCHLD, SIG_DFL); 399 signal(SIGHUP, SIG_IGN); 400 signal(SIGINT, SIG_IGN); 401 signal(SIGQUIT, SIG_IGN); 402 signal(SIGTERM, SIG_IGN); 403 (void) close(funix); 404 if (pflag == 0 && finet) { 405 for (i = 1; i <= *finet; i++) 406 (void)close(finet[i]); 407 } 408 dup2(s, 1); 409 (void) close(s); 410 if (domain == AF_INET) { 411 /* for both AF_INET and AF_INET6 */ 412 from_remote = 1; 413 chkhost((struct sockaddr *)&frominet, 414 ch_options); 415 } else 416 from_remote = 0; 417 doit(); 418 exit(0); 419 } 420 (void) close(s); 421 } 422 } 423 424 static void 425 reapchild(int signo __unused) 426 { 427 union wait status; 428 429 while (wait3((int *)&status, WNOHANG, 0) > 0) 430 ; 431 } 432 433 static void 434 mcleanup(int signo) 435 { 436 /* 437 * XXX syslog(3) is not signal-safe. 438 */ 439 if (lflag) { 440 if (signo) 441 syslog(LOG_INFO, "exiting on signal %d", signo); 442 else 443 syslog(LOG_INFO, "exiting"); 444 } 445 unlink(_PATH_SOCKETNAME); 446 exit(0); 447 } 448 449 /* 450 * Stuff for handling job specifications 451 */ 452 char *user[MAXUSERS]; /* users to process */ 453 int users; /* # of users in user array */ 454 int requ[MAXREQUESTS]; /* job number of spool entries */ 455 int requests; /* # of spool requests */ 456 char *person; /* name of person doing lprm */ 457 458 /* buffer to hold the client's machine-name */ 459 static char frombuf[MAXHOSTNAMELEN]; 460 char cbuf[BUFSIZ]; /* command line buffer */ 461 const char *cmdnames[] = { 462 "null", 463 "printjob", 464 "recvjob", 465 "displayq short", 466 "displayq long", 467 "rmjob" 468 }; 469 470 static void 471 doit(void) 472 { 473 char *cp, *printer; 474 int n; 475 int status; 476 struct printer myprinter, *pp = &myprinter; 477 478 init_printer(&myprinter); 479 480 for (;;) { 481 cp = cbuf; 482 do { 483 if (cp >= &cbuf[sizeof(cbuf) - 1]) 484 fatal(0, "Command line too long"); 485 if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { 486 if (n < 0) 487 fatal(0, "Lost connection"); 488 return; 489 } 490 } while (*cp++ != '\n'); 491 *--cp = '\0'; 492 cp = cbuf; 493 if (lflag) { 494 if (*cp >= '\1' && *cp <= '\5') 495 syslog(LOG_INFO, "%s requests %s %s", 496 from_host, cmdnames[(u_char)*cp], cp+1); 497 else 498 syslog(LOG_INFO, "bad request (%d) from %s", 499 *cp, from_host); 500 } 501 switch (*cp++) { 502 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 503 startprinting(cp); 504 break; 505 case CMD_TAKE_THIS: /* receive files to be queued */ 506 if (!from_remote) { 507 syslog(LOG_INFO, "illegal request (%d)", *cp); 508 exit(1); 509 } 510 recvjob(cp); 511 break; 512 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 513 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 514 /* XXX - this all needs to be redone. */ 515 printer = cp; 516 while (*cp) { 517 if (*cp != ' ') { 518 cp++; 519 continue; 520 } 521 *cp++ = '\0'; 522 while (isspace(*cp)) 523 cp++; 524 if (*cp == '\0') 525 break; 526 if (isdigit(*cp)) { 527 if (requests >= MAXREQUESTS) 528 fatal(0, "Too many requests"); 529 requ[requests++] = atoi(cp); 530 } else { 531 if (users >= MAXUSERS) 532 fatal(0, "Too many users"); 533 user[users++] = cp; 534 } 535 } 536 status = getprintcap(printer, pp); 537 if (status < 0) 538 fatal(pp, "%s", pcaperr(status)); 539 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 540 exit(0); 541 case CMD_RMJOB: /* remove a job from the queue */ 542 if (!from_remote) { 543 syslog(LOG_INFO, "illegal request (%d)", *cp); 544 exit(1); 545 } 546 printer = cp; 547 while (*cp && *cp != ' ') 548 cp++; 549 if (!*cp) 550 break; 551 *cp++ = '\0'; 552 person = cp; 553 while (*cp) { 554 if (*cp != ' ') { 555 cp++; 556 continue; 557 } 558 *cp++ = '\0'; 559 while (isspace(*cp)) 560 cp++; 561 if (*cp == '\0') 562 break; 563 if (isdigit(*cp)) { 564 if (requests >= MAXREQUESTS) 565 fatal(0, "Too many requests"); 566 requ[requests++] = atoi(cp); 567 } else { 568 if (users >= MAXUSERS) 569 fatal(0, "Too many users"); 570 user[users++] = cp; 571 } 572 } 573 rmjob(printer); 574 break; 575 } 576 fatal(0, "Illegal service request"); 577 } 578 } 579 580 /* 581 * Make a pass through the printcap database and start printing any 582 * files left from the last time the machine went down. 583 */ 584 static void 585 startup(void) 586 { 587 int pid, status, more; 588 struct printer myprinter, *pp = &myprinter; 589 590 more = firstprinter(pp, &status); 591 if (status) 592 goto errloop; 593 while (more) { 594 if (ckqueue(pp) <= 0) { 595 goto next; 596 } 597 if (lflag) 598 syslog(LOG_INFO, "lpd startup: work for %s", 599 pp->printer); 600 if ((pid = fork()) < 0) { 601 syslog(LOG_WARNING, "lpd startup: cannot fork for %s", 602 pp->printer); 603 mcleanup(0); 604 } 605 if (pid == 0) { 606 lastprinter(); 607 printjob(pp); 608 /* NOTREACHED */ 609 } 610 do { 611 next: 612 more = nextprinter(pp, &status); 613 errloop: 614 if (status) 615 syslog(LOG_WARNING, 616 "lpd startup: printcap entry for %s has errors, skipping", 617 pp->printer ? pp->printer : "<noname?>"); 618 } while (more && status); 619 } 620 } 621 622 /* 623 * Make sure there's some work to do before forking off a child 624 */ 625 static int 626 ckqueue(struct printer *pp) 627 { 628 register struct dirent *d; 629 DIR *dirp; 630 char *spooldir; 631 632 spooldir = pp->spool_dir; 633 if ((dirp = opendir(spooldir)) == NULL) 634 return (-1); 635 while ((d = readdir(dirp)) != NULL) { 636 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 637 continue; /* daemon control files only */ 638 closedir(dirp); 639 return (1); /* found something */ 640 } 641 closedir(dirp); 642 return (0); 643 } 644 645 #define DUMMY ":nobody::" 646 647 /* 648 * Check to see if the host connecting to this host has access to any 649 * lpd services on this host. 650 */ 651 static void 652 chkhost(struct sockaddr *f, int ch_opts) 653 { 654 struct addrinfo hints, *res, *r; 655 register FILE *hostf; 656 char hostbuf[NI_MAXHOST], ip[NI_MAXHOST]; 657 char serv[NI_MAXSERV]; 658 int error, errsav, fpass, good, wantsl; 659 660 wantsl = 0; 661 if (ch_opts & LPD_LOGCONNERR) 662 wantsl = 1; /* also syslog the errors */ 663 664 from_host = ".na."; 665 666 /* Need real hostname for temporary filenames */ 667 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 668 NI_NAMEREQD); 669 if (error) { 670 errsav = error; 671 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), 672 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); 673 if (error) 674 fhosterr(wantsl, 675 "can not determine hostname for remote host (%d)", 676 "Host name for your address not known", error); 677 else 678 fhosterr(wantsl, 679 "Host name for remote host (%s) not known (%d)", 680 "Host name for your address (%s) not known", 681 hostbuf, errsav); 682 } 683 684 strlcpy(frombuf, hostbuf, sizeof(frombuf)); 685 from_host = frombuf; 686 687 /* Need address in stringform for comparison (no DNS lookup here) */ 688 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 689 NI_NUMERICHOST | NI_WITHSCOPEID); 690 if (error) 691 fhosterr(wantsl, "Cannot print IP address (error %d)", 692 "Cannot print IP address", error); 693 from_ip = strdup(hostbuf); 694 695 /* Reject numeric addresses */ 696 memset(&hints, 0, sizeof(hints)); 697 hints.ai_family = family; 698 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 699 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 700 if (getaddrinfo(from_host, NULL, &hints, &res) == 0) { 701 freeaddrinfo(res); 702 fhosterr(wantsl, NULL, "reverse lookup results in non-FQDN %s", 703 from_host); 704 } 705 706 /* Check for spoof, ala rlogind */ 707 memset(&hints, 0, sizeof(hints)); 708 hints.ai_family = family; 709 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 710 error = getaddrinfo(from_host, NULL, &hints, &res); 711 if (error) { 712 fhosterr(wantsl, "dns lookup for address %s failed: %s", 713 "hostname for your address (%s) unknown: %s", from_ip, 714 gai_strerror(error)); 715 } 716 good = 0; 717 for (r = res; good == 0 && r; r = r->ai_next) { 718 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 719 NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); 720 if (!error && !strcmp(from_ip, ip)) 721 good = 1; 722 } 723 if (res) 724 freeaddrinfo(res); 725 if (good == 0) 726 fhosterr(wantsl, "address for remote host (%s) not matched", 727 "address for your hostname (%s) not matched", from_ip); 728 729 fpass = 1; 730 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 731 again: 732 if (hostf) { 733 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 734 (void) fclose(hostf); 735 goto foundhost; 736 } 737 (void) fclose(hostf); 738 } 739 if (fpass == 1) { 740 fpass = 2; 741 hostf = fopen(_PATH_HOSTSLPD, "r"); 742 goto again; 743 } 744 fhosterr(wantsl, "refused connection from %s, sip=%s", 745 "Print-services are not available to your host (%s).", from_host, 746 from_ip); 747 /*NOTREACHED*/ 748 749 foundhost: 750 if (ch_opts & LPD_NOPORTCHK) 751 return; /* skip the reserved-port check */ 752 753 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 754 NI_NUMERICSERV); 755 if (error) 756 fhosterr(wantsl, NULL, "malformed from-address (%d)", error); 757 758 if (atoi(serv) >= IPPORT_RESERVED) 759 fhosterr(wantsl, NULL, "connected from invalid port (%s)", 760 serv); 761 } 762 763 #include <stdarg.h> 764 /* 765 * Handle fatal errors in chkhost. The first message will optionally be sent 766 * to syslog, the second one is sent to the connecting host. If the first 767 * message is NULL, then the same message is used for both. Note that the 768 * argument list for both messages are assumed to be the same (or at least 769 * the initial arguments for one must be EXACTLY the same as the complete 770 * argument list for the other message). 771 * 772 * The idea is that the syslog message is meant for an administrator of a 773 * print server (the host receiving connections), while the usermsg is meant 774 * for a remote user who may or may not be clueful, and may or may not be 775 * doing something nefarious. Some remote users (eg, MS-Windows...) may not 776 * even see whatever message is sent, which is why there's the option to 777 * start 'lpd' with the connection-errors also sent to syslog. 778 * 779 * Given that hostnames can theoretically be fairly long (well, over 250 780 * bytes), it would probably be helpful to have the 'from_host' field at 781 * the end of any error messages which include that info. 782 */ 783 void 784 fhosterr(int dosys, const char *sysmsg, const char *usermsg, ...) 785 { 786 va_list ap; 787 char *sbuf, *ubuf; 788 const char *testone; 789 790 va_start(ap, usermsg); 791 vasprintf(&ubuf, usermsg, ap); 792 va_end(ap); 793 794 if (dosys) { 795 sbuf = ubuf; /* assume sysmsg == NULL */ 796 if (sysmsg != NULL) { 797 va_start(ap, usermsg); 798 vasprintf(&sbuf, sysmsg, ap); 799 va_end(ap); 800 } 801 /* 802 * If the first variable-parameter is not the 'from_host', 803 * then first write THAT information as a line to syslog. 804 */ 805 va_start(ap, usermsg); 806 testone = va_arg(ap, const char *); 807 if (testone != from_host) { 808 syslog(LOG_WARNING, "for connection from %s:", from_host); 809 } 810 va_end(ap); 811 812 /* now write the syslog message */ 813 syslog(LOG_WARNING, "%s", sbuf); 814 } 815 816 printf("%s [@%s]: %s\n", progname, local_host, ubuf); 817 fflush(stdout); 818 819 /* 820 * Add a minimal delay before exiting (and disconnecting from the 821 * sending-host). This is just in case that machine responds by 822 * INSTANTLY retrying (and instantly re-failing...). This may also 823 * give the other side more time to read the error message. 824 */ 825 sleep(2); /* a paranoid throttling measure */ 826 exit(1); 827 } 828 829 /* setup server socket for specified address family */ 830 /* if af is PF_UNSPEC more than one socket may be returned */ 831 /* the returned list is dynamically allocated, so caller needs to free it */ 832 static int * 833 socksetup(int af, int debuglvl) 834 { 835 struct addrinfo hints, *res, *r; 836 int error, maxs, *s, *socks; 837 const int on = 1; 838 839 memset(&hints, 0, sizeof(hints)); 840 hints.ai_flags = AI_PASSIVE; 841 hints.ai_family = af; 842 hints.ai_socktype = SOCK_STREAM; 843 error = getaddrinfo(NULL, "printer", &hints, &res); 844 if (error) { 845 syslog(LOG_ERR, "%s", gai_strerror(error)); 846 mcleanup(0); 847 } 848 849 /* Count max number of sockets we may open */ 850 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 851 ; 852 socks = malloc((maxs + 1) * sizeof(int)); 853 if (!socks) { 854 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 855 mcleanup(0); 856 } 857 858 *socks = 0; /* num of sockets counter at start of array */ 859 s = socks + 1; 860 for (r = res; r; r = r->ai_next) { 861 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 862 if (*s < 0) { 863 syslog(LOG_DEBUG, "socket(): %m"); 864 continue; 865 } 866 if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) 867 < 0) { 868 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 869 close(*s); 870 continue; 871 } 872 if (debuglvl) 873 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, &debuglvl, 874 sizeof(debuglvl)) < 0) { 875 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 876 close(*s); 877 continue; 878 } 879 #ifdef IPV6_BINDV6ONLY 880 if (r->ai_family == AF_INET6) { 881 if (setsockopt(*s, IPPROTO_IPV6, IPV6_BINDV6ONLY, 882 &on, sizeof(on)) < 0) { 883 syslog(LOG_ERR, 884 "setsockopt (IPV6_BINDV6ONLY): %m"); 885 close(*s); 886 continue; 887 } 888 } 889 #endif 890 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 891 syslog(LOG_DEBUG, "bind(): %m"); 892 close(*s); 893 continue; 894 } 895 (*socks)++; 896 s++; 897 } 898 899 if (res) 900 freeaddrinfo(res); 901 902 if (*socks == 0) { 903 syslog(LOG_ERR, "Couldn't bind to any socket"); 904 free(socks); 905 mcleanup(0); 906 } 907 return(socks); 908 } 909 910 static void 911 usage(void) 912 { 913 #ifdef INET6 914 fprintf(stderr, "usage: lpd [-cdlpW46] [port#]\n"); 915 #else 916 fprintf(stderr, "usage: lpd [-cdlpW] [port#]\n"); 917 #endif 918 exit(EX_USAGE); 919 } 920