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