1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1983, 1993, 1994\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #if 0 40 #ifndef lint 41 static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 42 #endif /* not lint */ 43 #endif 44 45 #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 46 __FBSDID("$FreeBSD$"); 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 daemon and spooling group 66 * 2. lpr runs setuid root and setgrp spooling group; it uses 67 * root to access any file it wants (verifying things before 68 * with an access call) and group id to know how it should 69 * set up ownership of files in the spooling area. 70 * 3. Files in spooling area are owned by root, group spooling 71 * group, with mode 660. 72 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 73 * access files and printer. Users can't get to anything 74 * w/o help of lpq and lprm programs. 75 */ 76 77 #include <sys/param.h> 78 #include <sys/wait.h> 79 #include <sys/types.h> 80 #include <sys/socket.h> 81 #include <sys/un.h> 82 #include <sys/stat.h> 83 #include <sys/file.h> 84 #include <netinet/in.h> 85 #include <arpa/inet.h> 86 87 #include <netdb.h> 88 #include <unistd.h> 89 #include <syslog.h> 90 #include <signal.h> 91 #include <err.h> 92 #include <errno.h> 93 #include <fcntl.h> 94 #include <dirent.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <string.h> 98 #include <sysexits.h> 99 #include <ctype.h> 100 #include "lp.h" 101 #include "lp.local.h" 102 #include "pathnames.h" 103 #include "extern.h" 104 105 int lflag; /* log requests flag */ 106 int sflag; /* no incoming port flag */ 107 int Fflag; /* run in foreground 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 _ch_opts, char *_sysmsg, char *_usermsg); 118 static int *socksetup(int _af, int _debuglvl); 119 static void usage(void); 120 121 /* XXX from libc/net/rcmd.c */ 122 extern int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t, 123 const char *, const char *); 124 125 uid_t uid, euid; 126 127 #define LPD_NOPORTCHK 0001 /* skip reserved-port check */ 128 #define LPD_LOGCONNERR 0002 /* (sys)log connection errors */ 129 #define LPD_ADDFROMLINE 0004 /* just used for fhosterr() */ 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, "cdlpswFW46")) != -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': /* letter initially used for -s */ 169 /* 170 * This will probably be removed with 5.0-release. 171 */ 172 /* FALLTHROUGH */ 173 case 's': /* secure (no inet) */ 174 sflag++; 175 break; 176 case 'w': /* netbsd uses -w for maxwait */ 177 /* 178 * This will be removed after the release of 4.4, as 179 * it conflicts with -w in netbsd's lpd. For now it 180 * is just a warning, so we won't suddenly break lpd 181 * for anyone who is currently using the option. 182 */ 183 syslog(LOG_WARNING, 184 "NOTE: the -w option has been renamed -W"); 185 syslog(LOG_WARNING, 186 "NOTE: please change your lpd config to use -W"); 187 /* FALLTHROUGH */ 188 case 'F': 189 Fflag++; 190 break; 191 case 'W': 192 /* allow connections coming from a non-reserved port */ 193 /* (done by some lpr-implementations for MS-Windows) */ 194 ch_options |= LPD_NOPORTCHK; 195 break; 196 case '4': 197 family = PF_INET; 198 inet_flag++; 199 break; 200 case '6': 201 #ifdef INET6 202 family = PF_INET6; 203 inet6_flag++; 204 #else 205 errx(EX_USAGE, "lpd compiled sans INET6 (IPv6 support)"); 206 #endif 207 break; 208 /* 209 * The following options are not in FreeBSD (yet?), but are 210 * listed here to "reserve" them, because the option-letters 211 * are used by either NetBSD or OpenBSD (as of July 2001). 212 */ 213 case 'b': /* set bind-addr */ 214 case 'n': /* set max num of children */ 215 case 'r': /* allow 'of' for remote ptrs */ 216 /* ...[not needed in freebsd] */ 217 /* FALLTHROUGH */ 218 default: 219 errs++; 220 } 221 if (inet_flag && inet6_flag) 222 family = PF_UNSPEC; 223 argc -= optind; 224 argv += optind; 225 if (errs) 226 usage(); 227 228 if (argc == 1) { 229 if ((i = atoi(argv[0])) == 0) 230 usage(); 231 if (i < 0 || i > USHRT_MAX) 232 errx(EX_USAGE, "port # %d is invalid", i); 233 234 serv.s_port = htons(i); 235 sp = &serv; 236 argc--; 237 } else { 238 sp = getservbyname("printer", "tcp"); 239 if (sp == NULL) 240 errx(EX_OSFILE, "printer/tcp: unknown service"); 241 } 242 243 if (argc != 0) 244 usage(); 245 246 /* 247 * We run chkprintcap right away to catch any errors and blat them 248 * to stderr while we still have it open, rather than sending them 249 * to syslog and leaving the user wondering why lpd started and 250 * then stopped. There should probably be a command-line flag to 251 * ignore errors from chkprintcap. 252 */ 253 { 254 pid_t pid; 255 int status; 256 pid = fork(); 257 if (pid < 0) { 258 err(EX_OSERR, "cannot fork"); 259 } else if (pid == 0) { /* child */ 260 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 261 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 262 } 263 if (waitpid(pid, &status, 0) < 0) { 264 err(EX_OSERR, "cannot wait"); 265 } 266 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 267 errx(EX_OSFILE, "%d errors in printcap file, exiting", 268 WEXITSTATUS(status)); 269 } 270 271 #ifdef DEBUG 272 Fflag++; 273 #endif 274 /* 275 * Set up standard environment by detaching from the parent 276 * if -F not specified 277 */ 278 if (Fflag == 0) { 279 daemon(0, 0); 280 } 281 282 openlog("lpd", LOG_PID, LOG_LPR); 283 syslog(LOG_INFO, "lpd startup: logging=%d%s%s", lflag, 284 socket_debug ? " dbg" : "", sflag ? " net-secure" : ""); 285 (void) umask(0); 286 /* 287 * NB: This depends on O_NONBLOCK semantics doing the right thing; 288 * i.e., applying only to the O_EXLOCK and not to the rest of the 289 * open/creation. As of 1997-12-02, this is the case for commonly- 290 * used filesystems. There are other places in this code which 291 * make the same assumption. 292 */ 293 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 294 LOCK_FILE_MODE); 295 if (lfd < 0) { 296 if (errno == EWOULDBLOCK) /* active daemon present */ 297 exit(0); 298 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 299 exit(1); 300 } 301 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 302 ftruncate(lfd, 0); 303 /* 304 * write process id for others to know 305 */ 306 sprintf(line, "%u\n", getpid()); 307 f = strlen(line); 308 if (write(lfd, line, f) != f) { 309 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 310 exit(1); 311 } 312 signal(SIGCHLD, reapchild); 313 /* 314 * Restart all the printers. 315 */ 316 startup(); 317 (void) unlink(_PATH_SOCKETNAME); 318 funix = socket(AF_UNIX, SOCK_STREAM, 0); 319 if (funix < 0) { 320 syslog(LOG_ERR, "socket: %m"); 321 exit(1); 322 } 323 324 sigemptyset(&nmask); 325 sigaddset(&nmask, SIGHUP); 326 sigaddset(&nmask, SIGINT); 327 sigaddset(&nmask, SIGQUIT); 328 sigaddset(&nmask, SIGTERM); 329 sigprocmask(SIG_BLOCK, &nmask, &omask); 330 331 (void) umask(07); 332 signal(SIGHUP, mcleanup); 333 signal(SIGINT, mcleanup); 334 signal(SIGQUIT, mcleanup); 335 signal(SIGTERM, mcleanup); 336 memset(&un, 0, sizeof(un)); 337 un.sun_family = AF_UNIX; 338 strcpy(un.sun_path, _PATH_SOCKETNAME); 339 #ifndef SUN_LEN 340 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 341 #endif 342 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 343 syslog(LOG_ERR, "ubind: %m"); 344 exit(1); 345 } 346 (void) umask(0); 347 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 348 FD_ZERO(&defreadfds); 349 FD_SET(funix, &defreadfds); 350 listen(funix, 5); 351 if (sflag == 0) { 352 finet = socksetup(family, socket_debug); 353 } else 354 finet = NULL; /* pretend we couldn't open TCP socket. */ 355 if (finet) { 356 for (i = 1; i <= *finet; i++) { 357 FD_SET(finet[i], &defreadfds); 358 listen(finet[i], 5); 359 } 360 } 361 /* 362 * Main loop: accept, do a request, continue. 363 */ 364 memset(&frominet, 0, sizeof(frominet)); 365 memset(&fromunix, 0, sizeof(fromunix)); 366 if (lflag) 367 syslog(LOG_INFO, "lpd startup: ready to accept requests"); 368 /* 369 * XXX - should be redone for multi-protocol 370 */ 371 for (;;) { 372 int domain, nfds, s; 373 fd_set readfds; 374 375 FD_COPY(&defreadfds, &readfds); 376 nfds = select(20, &readfds, 0, 0, 0); 377 if (nfds <= 0) { 378 if (nfds < 0 && errno != EINTR) 379 syslog(LOG_WARNING, "select: %m"); 380 continue; 381 } 382 domain = -1; /* avoid compile-time warning */ 383 s = -1; /* avoid compile-time warning */ 384 if (FD_ISSET(funix, &readfds)) { 385 domain = AF_UNIX, fromlen = sizeof(fromunix); 386 s = accept(funix, 387 (struct sockaddr *)&fromunix, &fromlen); 388 } else { 389 for (i = 1; i <= *finet; i++) 390 if (FD_ISSET(finet[i], &readfds)) { 391 domain = AF_INET; 392 fromlen = sizeof(frominet); 393 s = accept(finet[i], 394 (struct sockaddr *)&frominet, 395 &fromlen); 396 } 397 } 398 if (s < 0) { 399 if (errno != EINTR) 400 syslog(LOG_WARNING, "accept: %m"); 401 continue; 402 } 403 if (fork() == 0) { 404 /* 405 * Note that printjob() also plays around with 406 * signal-handling routines, and may need to be 407 * changed when making changes to signal-handling. 408 */ 409 signal(SIGCHLD, SIG_DFL); 410 signal(SIGHUP, SIG_IGN); 411 signal(SIGINT, SIG_IGN); 412 signal(SIGQUIT, SIG_IGN); 413 signal(SIGTERM, SIG_IGN); 414 (void) close(funix); 415 if (sflag == 0 && finet) { 416 for (i = 1; i <= *finet; i++) 417 (void)close(finet[i]); 418 } 419 dup2(s, STDOUT_FILENO); 420 (void) close(s); 421 if (domain == AF_INET) { 422 /* for both AF_INET and AF_INET6 */ 423 from_remote = 1; 424 chkhost((struct sockaddr *)&frominet, 425 ch_options); 426 } else 427 from_remote = 0; 428 doit(); 429 exit(0); 430 } 431 (void) close(s); 432 } 433 } 434 435 static void 436 reapchild(int signo __unused) 437 { 438 int status; 439 440 while (wait3(&status, WNOHANG, 0) > 0) 441 ; 442 } 443 444 static void 445 mcleanup(int signo) 446 { 447 /* 448 * XXX syslog(3) is not signal-safe. 449 */ 450 if (lflag) { 451 if (signo) 452 syslog(LOG_INFO, "exiting on signal %d", signo); 453 else 454 syslog(LOG_INFO, "exiting"); 455 } 456 unlink(_PATH_SOCKETNAME); 457 exit(0); 458 } 459 460 /* 461 * Stuff for handling job specifications 462 */ 463 char *user[MAXUSERS]; /* users to process */ 464 int users; /* # of users in user array */ 465 int requ[MAXREQUESTS]; /* job number of spool entries */ 466 int requests; /* # of spool requests */ 467 char *person; /* name of person doing lprm */ 468 469 /* buffer to hold the client's machine-name */ 470 static char frombuf[MAXHOSTNAMELEN]; 471 char cbuf[BUFSIZ]; /* command line buffer */ 472 const char *cmdnames[] = { 473 "null", 474 "printjob", 475 "recvjob", 476 "displayq short", 477 "displayq long", 478 "rmjob" 479 }; 480 481 static void 482 doit(void) 483 { 484 char *cp, *printer; 485 int n; 486 int status; 487 struct printer myprinter, *pp = &myprinter; 488 489 init_printer(&myprinter); 490 491 for (;;) { 492 cp = cbuf; 493 do { 494 if (cp >= &cbuf[sizeof(cbuf) - 1]) 495 fatal(0, "Command line too long"); 496 if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { 497 if (n < 0) 498 fatal(0, "Lost connection"); 499 return; 500 } 501 } while (*cp++ != '\n'); 502 *--cp = '\0'; 503 cp = cbuf; 504 if (lflag) { 505 if (*cp >= '\1' && *cp <= '\5') 506 syslog(LOG_INFO, "%s requests %s %s", 507 from_host, cmdnames[(u_char)*cp], cp+1); 508 else 509 syslog(LOG_INFO, "bad request (%d) from %s", 510 *cp, from_host); 511 } 512 switch (*cp++) { 513 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 514 startprinting(cp); 515 break; 516 case CMD_TAKE_THIS: /* receive files to be queued */ 517 if (!from_remote) { 518 syslog(LOG_INFO, "illegal request (%d)", *cp); 519 exit(1); 520 } 521 recvjob(cp); 522 break; 523 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 524 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 525 /* XXX - this all needs to be redone. */ 526 printer = cp; 527 while (*cp) { 528 if (*cp != ' ') { 529 cp++; 530 continue; 531 } 532 *cp++ = '\0'; 533 while (isspace(*cp)) 534 cp++; 535 if (*cp == '\0') 536 break; 537 if (isdigit(*cp)) { 538 if (requests >= MAXREQUESTS) 539 fatal(0, "Too many requests"); 540 requ[requests++] = atoi(cp); 541 } else { 542 if (users >= MAXUSERS) 543 fatal(0, "Too many users"); 544 user[users++] = cp; 545 } 546 } 547 status = getprintcap(printer, pp); 548 if (status < 0) 549 fatal(pp, "%s", pcaperr(status)); 550 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 551 exit(0); 552 case CMD_RMJOB: /* remove a job from the queue */ 553 if (!from_remote) { 554 syslog(LOG_INFO, "illegal request (%d)", *cp); 555 exit(1); 556 } 557 printer = cp; 558 while (*cp && *cp != ' ') 559 cp++; 560 if (!*cp) 561 break; 562 *cp++ = '\0'; 563 person = cp; 564 while (*cp) { 565 if (*cp != ' ') { 566 cp++; 567 continue; 568 } 569 *cp++ = '\0'; 570 while (isspace(*cp)) 571 cp++; 572 if (*cp == '\0') 573 break; 574 if (isdigit(*cp)) { 575 if (requests >= MAXREQUESTS) 576 fatal(0, "Too many requests"); 577 requ[requests++] = atoi(cp); 578 } else { 579 if (users >= MAXUSERS) 580 fatal(0, "Too many users"); 581 user[users++] = cp; 582 } 583 } 584 rmjob(printer); 585 break; 586 } 587 fatal(0, "Illegal service request"); 588 } 589 } 590 591 /* 592 * Make a pass through the printcap database and start printing any 593 * files left from the last time the machine went down. 594 */ 595 static void 596 startup(void) 597 { 598 int pid, status, more; 599 struct printer myprinter, *pp = &myprinter; 600 601 more = firstprinter(pp, &status); 602 if (status) 603 goto errloop; 604 while (more) { 605 if (ckqueue(pp) <= 0) { 606 goto next; 607 } 608 if (lflag) 609 syslog(LOG_INFO, "lpd startup: work for %s", 610 pp->printer); 611 if ((pid = fork()) < 0) { 612 syslog(LOG_WARNING, "lpd startup: cannot fork for %s", 613 pp->printer); 614 mcleanup(0); 615 } 616 if (pid == 0) { 617 lastprinter(); 618 printjob(pp); 619 /* NOTREACHED */ 620 } 621 do { 622 next: 623 more = nextprinter(pp, &status); 624 errloop: 625 if (status) 626 syslog(LOG_WARNING, 627 "lpd startup: printcap entry for %s has errors, skipping", 628 pp->printer ? pp->printer : "<noname?>"); 629 } while (more && status); 630 } 631 } 632 633 /* 634 * Make sure there's some work to do before forking off a child 635 */ 636 static int 637 ckqueue(struct printer *pp) 638 { 639 register struct dirent *d; 640 DIR *dirp; 641 char *spooldir; 642 643 spooldir = pp->spool_dir; 644 if ((dirp = opendir(spooldir)) == NULL) 645 return (-1); 646 while ((d = readdir(dirp)) != NULL) { 647 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 648 continue; /* daemon control files only */ 649 closedir(dirp); 650 return (1); /* found something */ 651 } 652 closedir(dirp); 653 return (0); 654 } 655 656 #define DUMMY ":nobody::" 657 658 /* 659 * Check to see if the host connecting to this host has access to any 660 * lpd services on this host. 661 */ 662 static void 663 chkhost(struct sockaddr *f, int ch_opts) 664 { 665 struct addrinfo hints, *res, *r; 666 register FILE *hostf; 667 char hostbuf[NI_MAXHOST], ip[NI_MAXHOST]; 668 char serv[NI_MAXSERV]; 669 char *syserr, *usererr; 670 int error, errsav, fpass, good; 671 672 from_host = ".na."; 673 674 /* Need real hostname for temporary filenames */ 675 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 676 NI_NAMEREQD); 677 if (error) { 678 errsav = error; 679 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), 680 NULL, 0, NI_NUMERICHOST); 681 if (error) { 682 asprintf(&syserr, 683 "can not determine hostname for remote host (%d,%d)", 684 errsav, error); 685 asprintf(&usererr, 686 "Host name for your address is not known"); 687 fhosterr(ch_opts, syserr, usererr); 688 /* NOTREACHED */ 689 } 690 asprintf(&syserr, 691 "Host name for remote host (%s) not known (%d)", 692 hostbuf, errsav); 693 asprintf(&usererr, 694 "Host name for your address (%s) is not known", 695 hostbuf); 696 fhosterr(ch_opts, syserr, usererr); 697 /* NOTREACHED */ 698 } 699 700 strlcpy(frombuf, hostbuf, sizeof(frombuf)); 701 from_host = frombuf; 702 ch_opts |= LPD_ADDFROMLINE; 703 704 /* Need address in stringform for comparison (no DNS lookup here) */ 705 error = getnameinfo(f, f->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 706 NI_NUMERICHOST); 707 if (error) { 708 asprintf(&syserr, "Cannot print IP address (error %d)", 709 error); 710 asprintf(&usererr, "Cannot print IP address for your host"); 711 fhosterr(ch_opts, syserr, usererr); 712 /* NOTREACHED */ 713 } 714 from_ip = strdup(hostbuf); 715 716 /* Reject numeric addresses */ 717 memset(&hints, 0, sizeof(hints)); 718 hints.ai_family = family; 719 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 720 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 721 if (getaddrinfo(from_host, NULL, &hints, &res) == 0) { 722 freeaddrinfo(res); 723 /* This syslog message already includes from_host */ 724 ch_opts &= ~LPD_ADDFROMLINE; 725 asprintf(&syserr, "reverse lookup results in non-FQDN %s", 726 from_host); 727 /* same message to both syslog and remote user */ 728 fhosterr(ch_opts, syserr, syserr); 729 /* NOTREACHED */ 730 } 731 732 /* Check for spoof, ala rlogind */ 733 memset(&hints, 0, sizeof(hints)); 734 hints.ai_family = family; 735 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 736 error = getaddrinfo(from_host, NULL, &hints, &res); 737 if (error) { 738 asprintf(&syserr, "dns lookup for address %s failed: %s", 739 from_ip, gai_strerror(error)); 740 asprintf(&usererr, "hostname for your address (%s) unknown: %s", 741 from_ip, gai_strerror(error)); 742 fhosterr(ch_opts, syserr, usererr); 743 /* NOTREACHED */ 744 } 745 good = 0; 746 for (r = res; good == 0 && r; r = r->ai_next) { 747 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 748 NULL, 0, NI_NUMERICHOST); 749 if (!error && !strcmp(from_ip, ip)) 750 good = 1; 751 } 752 if (res) 753 freeaddrinfo(res); 754 if (good == 0) { 755 asprintf(&syserr, "address for remote host (%s) not matched", 756 from_ip); 757 asprintf(&usererr, 758 "address for your hostname (%s) not matched", from_ip); 759 fhosterr(ch_opts, syserr, usererr); 760 /* NOTREACHED */ 761 } 762 763 fpass = 1; 764 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 765 again: 766 if (hostf) { 767 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 768 (void) fclose(hostf); 769 goto foundhost; 770 } 771 (void) fclose(hostf); 772 } 773 if (fpass == 1) { 774 fpass = 2; 775 hostf = fopen(_PATH_HOSTSLPD, "r"); 776 goto again; 777 } 778 /* This syslog message already includes from_host */ 779 ch_opts &= ~LPD_ADDFROMLINE; 780 asprintf(&syserr, "refused connection from %s, sip=%s", from_host, 781 from_ip); 782 asprintf(&usererr, 783 "Print-services are not available to your host (%s).", from_host); 784 fhosterr(ch_opts, syserr, usererr); 785 /* NOTREACHED */ 786 787 foundhost: 788 if (ch_opts & LPD_NOPORTCHK) 789 return; /* skip the reserved-port check */ 790 791 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 792 NI_NUMERICSERV); 793 if (error) { 794 /* same message to both syslog and remote user */ 795 asprintf(&syserr, "malformed from-address (%d)", error); 796 fhosterr(ch_opts, syserr, syserr); 797 /* NOTREACHED */ 798 } 799 800 if (atoi(serv) >= IPPORT_RESERVED) { 801 /* same message to both syslog and remote user */ 802 asprintf(&syserr, "connected from invalid port (%s)", serv); 803 fhosterr(ch_opts, syserr, syserr); 804 /* NOTREACHED */ 805 } 806 } 807 808 /* 809 * Handle fatal errors in chkhost. The first message will optionally be 810 * sent to syslog, the second one is sent to the connecting host. 811 * 812 * The idea is that the syslog message is meant for an administrator of a 813 * print server (the host receiving connections), while the usermsg is meant 814 * for a remote user who may or may not be clueful, and may or may not be 815 * doing something nefarious. Some remote users (eg, MS-Windows...) may not 816 * even see whatever message is sent, which is why there's the option to 817 * start 'lpd' with the connection-errors also sent to syslog. 818 * 819 * Given that hostnames can theoretically be fairly long (well, over 250 820 * bytes), it would probably be helpful to have the 'from_host' field at 821 * the end of any error messages which include that info. 822 * 823 * These are Fatal host-connection errors, so this routine does not return. 824 */ 825 static void 826 fhosterr(int ch_opts, char *sysmsg, char *usermsg) 827 { 828 829 /* 830 * If lpd was started up to print connection errors, then write 831 * the syslog message before the user message. 832 * And for many of the syslog messages, it is helpful to first 833 * write the from_host (if it is known) as a separate syslog 834 * message, since the hostname may be so long. 835 */ 836 if (ch_opts & LPD_LOGCONNERR) { 837 if (ch_opts & LPD_ADDFROMLINE) { 838 syslog(LOG_WARNING, "for connection from %s:", from_host); 839 } 840 syslog(LOG_WARNING, "%s", sysmsg); 841 } 842 843 /* 844 * Now send the error message to the remote host which is trying 845 * to make the connection. 846 */ 847 printf("%s [@%s]: %s\n", progname, local_host, usermsg); 848 fflush(stdout); 849 850 /* 851 * Add a minimal delay before exiting (and disconnecting from the 852 * sending-host). This is just in case that machine responds by 853 * INSTANTLY retrying (and instantly re-failing...). This may also 854 * give the other side more time to read the error message. 855 */ 856 sleep(2); /* a paranoid throttling measure */ 857 exit(1); 858 } 859 860 /* setup server socket for specified address family */ 861 /* if af is PF_UNSPEC more than one socket may be returned */ 862 /* the returned list is dynamically allocated, so caller needs to free it */ 863 static int * 864 socksetup(int af, int debuglvl) 865 { 866 struct addrinfo hints, *res, *r; 867 int error, maxs, *s, *socks; 868 const int on = 1; 869 870 memset(&hints, 0, sizeof(hints)); 871 hints.ai_flags = AI_PASSIVE; 872 hints.ai_family = af; 873 hints.ai_socktype = SOCK_STREAM; 874 error = getaddrinfo(NULL, "printer", &hints, &res); 875 if (error) { 876 syslog(LOG_ERR, "%s", gai_strerror(error)); 877 mcleanup(0); 878 } 879 880 /* Count max number of sockets we may open */ 881 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 882 ; 883 socks = malloc((maxs + 1) * sizeof(int)); 884 if (!socks) { 885 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 886 mcleanup(0); 887 } 888 889 *socks = 0; /* num of sockets counter at start of array */ 890 s = socks + 1; 891 for (r = res; r; r = r->ai_next) { 892 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 893 if (*s < 0) { 894 syslog(LOG_DEBUG, "socket(): %m"); 895 continue; 896 } 897 if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) 898 < 0) { 899 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 900 close(*s); 901 continue; 902 } 903 if (debuglvl) 904 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, &debuglvl, 905 sizeof(debuglvl)) < 0) { 906 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 907 close(*s); 908 continue; 909 } 910 if (r->ai_family == AF_INET6) { 911 if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, 912 &on, sizeof(on)) < 0) { 913 syslog(LOG_ERR, 914 "setsockopt (IPV6_V6ONLY): %m"); 915 close(*s); 916 continue; 917 } 918 } 919 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 920 syslog(LOG_DEBUG, "bind(): %m"); 921 close(*s); 922 continue; 923 } 924 (*socks)++; 925 s++; 926 } 927 928 if (res) 929 freeaddrinfo(res); 930 931 if (*socks == 0) { 932 syslog(LOG_ERR, "Couldn't bind to any socket"); 933 free(socks); 934 mcleanup(0); 935 } 936 return(socks); 937 } 938 939 static void 940 usage(void) 941 { 942 #ifdef INET6 943 fprintf(stderr, "usage: lpd [-cdlsFW46] [port#]\n"); 944 #else 945 fprintf(stderr, "usage: lpd [-cdlsFW] [port#]\n"); 946 #endif 947 exit(EX_USAGE); 948 } 949