1 /* $NetBSD: lpd.c,v 1.22 2000/04/10 08:09:33 mrg Exp $ */ 2 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 39 #ifndef lint 40 __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\ 41 The Regents of the University of California. All rights reserved.\n"); 42 #endif /* not lint */ 43 44 #ifndef lint 45 #if 0 46 static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; 47 #else 48 __RCSID("$NetBSD: lpd.c,v 1.22 2000/04/10 08:09:33 mrg Exp $"); 49 #endif 50 #endif /* not lint */ 51 52 /* 53 * lpd -- line printer daemon. 54 * 55 * Listen for a connection and perform the requested operation. 56 * Operations are: 57 * \1printer\n 58 * check the queue for jobs and print any found. 59 * \2printer\n 60 * receive a job from another machine and queue it. 61 * \3printer [users ...] [jobs ...]\n 62 * return the current state of the queue (short form). 63 * \4printer [users ...] [jobs ...]\n 64 * return the current state of the queue (long form). 65 * \5printer person [users ...] [jobs ...]\n 66 * remove jobs from the queue. 67 * 68 * Strategy to maintain protected spooling area: 69 * 1. Spooling area is writable only by daemon and spooling group 70 * 2. lpr runs setuid root and setgrp spooling group; it uses 71 * root to access any file it wants (verifying things before 72 * with an access call) and group id to know how it should 73 * set up ownership of files in the spooling area. 74 * 3. Files in spooling area are owned by root, group spooling 75 * group, with mode 660. 76 * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to 77 * access files and printer. Users can't get to anything 78 * w/o help of lpq and lprm programs. 79 */ 80 81 #include <sys/param.h> 82 #include <sys/wait.h> 83 #include <sys/types.h> 84 #include <sys/socket.h> 85 #include <sys/un.h> 86 #include <sys/stat.h> 87 #include <sys/file.h> 88 #include <netinet/in.h> 89 90 #include <err.h> 91 #include <netdb.h> 92 #include <unistd.h> 93 #include <syslog.h> 94 #include <signal.h> 95 #include <errno.h> 96 #include <fcntl.h> 97 #include <dirent.h> 98 #include <stdio.h> 99 #include <stdlib.h> 100 #include <string.h> 101 #include <ctype.h> 102 #include <arpa/inet.h> 103 104 #include "lp.h" 105 #include "lp.local.h" 106 #include "pathnames.h" 107 #include "extern.h" 108 109 /* XXX from libc/net/rcmd.c */ 110 extern int __ivaliduser_sa __P((FILE *, struct sockaddr *, socklen_t, 111 const char *, const char *)); 112 113 int lflag; /* log requests flag */ 114 int rflag; /* allow of for remote printers */ 115 int sflag; /* secure (no inet) flag */ 116 int from_remote; /* from remote socket */ 117 118 int main __P((int, char **)); 119 static void reapchild __P((int)); 120 static void mcleanup __P((int)); 121 static void doit __P((void)); 122 static void startup __P((void)); 123 static void chkhost __P((struct sockaddr *)); 124 static int ckqueue __P((char *)); 125 static void usage __P((void)); 126 static int *socksetup __P((int, int)); 127 128 uid_t uid, euid; 129 int child_count; 130 131 int 132 main(argc, argv) 133 int argc; 134 char **argv; 135 { 136 fd_set defreadfds; 137 struct sockaddr_un un, fromunix; 138 struct sockaddr_storage frominet; 139 sigset_t nmask, omask; 140 int lfd, errs, i, f, funix, *finet; 141 int child_max = 32; /* more then enough to hose the system */ 142 int options = 0; 143 struct servent *sp, serv; 144 145 euid = geteuid(); /* these shouldn't be different */ 146 uid = getuid(); 147 gethostname(host, sizeof(host)); 148 host[sizeof(host) - 1] = '\0'; 149 name = argv[0]; 150 151 errs = 0; 152 while ((i = getopt(argc, argv, "dln:srw:")) != -1) 153 switch (i) { 154 case 'd': 155 options |= SO_DEBUG; 156 break; 157 case 'l': 158 lflag++; 159 break; 160 case 'n': 161 child_max = atoi(optarg); 162 if (child_max < 0 || child_max > 1024) 163 errx(1, "invalid number of children: %s", 164 optarg); 165 break; 166 case 'r': 167 rflag++; 168 break; 169 case 's': 170 sflag++; 171 break; 172 case 'w': 173 wait_time = atoi(optarg); 174 if (wait_time < 0) 175 errx(1, "wait time must be postive: %s", 176 optarg); 177 if (wait_time < 30) 178 warnx("warning: wait time less than 30 seconds"); 179 break; 180 default: 181 errs++; 182 } 183 argc -= optind; 184 argv += optind; 185 if (errs) 186 usage(); 187 188 switch (argc) { 189 case 1: 190 if ((i = atoi(argv[0])) == 0) 191 usage(); 192 if (i < 0 || i > USHRT_MAX) 193 errx(1, "port # %d is invalid", i); 194 195 serv.s_port = htons(i); 196 sp = &serv; 197 break; 198 case 0: 199 sp = getservbyname("printer", "tcp"); 200 if (sp == NULL) 201 errx(1, "printer/tcp: unknown service"); 202 break; 203 default: 204 usage(); 205 } 206 207 #ifndef DEBUG 208 /* 209 * Set up standard environment by detaching from the parent. 210 */ 211 daemon(0, 0); 212 #endif 213 214 openlog("lpd", LOG_PID, LOG_LPR); 215 syslog(LOG_INFO, "restarted"); 216 (void)umask(0); 217 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); 218 if (lfd < 0) { 219 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 220 exit(1); 221 } 222 if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { 223 if (errno == EWOULDBLOCK) /* active deamon present */ 224 exit(0); 225 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 226 exit(1); 227 } 228 ftruncate(lfd, 0); 229 /* 230 * write process id for others to know 231 */ 232 (void)snprintf(line, sizeof(line), "%u\n", getpid()); 233 f = strlen(line); 234 if (write(lfd, line, f) != f) { 235 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 236 exit(1); 237 } 238 signal(SIGCHLD, reapchild); 239 /* 240 * Restart all the printers. 241 */ 242 startup(); 243 (void)unlink(_PATH_SOCKETNAME); 244 funix = socket(AF_LOCAL, SOCK_STREAM, 0); 245 if (funix < 0) { 246 syslog(LOG_ERR, "socket: %m"); 247 exit(1); 248 } 249 250 sigemptyset(&nmask); 251 sigaddset(&nmask, SIGHUP); 252 sigaddset(&nmask, SIGINT); 253 sigaddset(&nmask, SIGQUIT); 254 sigaddset(&nmask, SIGTERM); 255 sigprocmask(SIG_BLOCK, &nmask, &omask); 256 257 (void) umask(07); 258 signal(SIGHUP, mcleanup); 259 signal(SIGINT, mcleanup); 260 signal(SIGQUIT, mcleanup); 261 signal(SIGTERM, mcleanup); 262 memset(&un, 0, sizeof(un)); 263 un.sun_family = AF_LOCAL; 264 strncpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path) - 1); 265 #ifndef SUN_LEN 266 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 267 #endif 268 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 269 syslog(LOG_ERR, "ubind: %m"); 270 exit(1); 271 } 272 (void) umask(0); 273 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 274 FD_ZERO(&defreadfds); 275 FD_SET(funix, &defreadfds); 276 listen(funix, 5); 277 if (!sflag) 278 finet = socksetup(PF_UNSPEC, options); 279 else 280 finet = NULL; /* pretend we couldn't open TCP socket. */ 281 282 if (finet) { 283 for (i = 1; i <= *finet; i++) { 284 FD_SET(finet[i], &defreadfds); 285 listen(finet[i], 5); 286 } 287 } 288 /* 289 * Main loop: accept, do a request, continue. 290 */ 291 memset(&frominet, 0, sizeof(frominet)); 292 memset(&fromunix, 0, sizeof(fromunix)); 293 for (;;) { 294 int domain, nfds, s, fromlen; 295 fd_set readfds; 296 /* "short" so it overflows in about 2 hours */ 297 short sleeptime = 10; 298 299 while (child_max < child_count) { 300 syslog(LOG_WARNING, 301 "too many children, sleeping for %d seconds", 302 sleeptime); 303 sleep(sleeptime); 304 sleeptime <<= 1; 305 if (sleeptime < 0) { 306 syslog(LOG_CRIT, "sleeptime overflowed! help!"); 307 sleeptime = 10; 308 } 309 } 310 311 FD_COPY(&defreadfds, &readfds); 312 nfds = select(20, &readfds, 0, 0, 0); 313 if (nfds <= 0) { 314 if (nfds < 0 && errno != EINTR) 315 syslog(LOG_WARNING, "select: %m"); 316 continue; 317 } 318 if (FD_ISSET(funix, &readfds)) { 319 domain = AF_LOCAL; 320 fromlen = sizeof(fromunix); 321 s = accept(funix, 322 (struct sockaddr *)&fromunix, &fromlen); 323 } else { 324 for (i = 1; i <= *finet; i++) 325 if (FD_ISSET(finet[i], &readfds)) { 326 domain = AF_INET, fromlen = sizeof(frominet); 327 s = accept(finet[i], (struct sockaddr *)&frominet, &fromlen); 328 } 329 } 330 if (s < 0) { 331 if (errno != EINTR) 332 syslog(LOG_WARNING, "accept: %m"); 333 continue; 334 } 335 336 switch (fork()) { 337 case 0: 338 signal(SIGCHLD, SIG_IGN); 339 signal(SIGHUP, SIG_IGN); 340 signal(SIGINT, SIG_IGN); 341 signal(SIGQUIT, SIG_IGN); 342 signal(SIGTERM, SIG_IGN); 343 (void)close(funix); 344 if (!sflag && finet) 345 for (i = 1; i <= *finet; i++) 346 (void)close(finet[i]); 347 dup2(s, 1); 348 (void)close(s); 349 if (domain == AF_INET) { 350 /* for both AF_INET and AF_INET6 */ 351 from_remote = 1; 352 chkhost((struct sockaddr *)&frominet); 353 } else 354 from_remote = 0; 355 doit(); 356 exit(0); 357 case -1: 358 syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds..."); 359 sleep(10); 360 continue; 361 default: 362 child_count++; 363 } 364 (void)close(s); 365 } 366 } 367 368 static void 369 reapchild(signo) 370 int signo; 371 { 372 union wait status; 373 374 while (wait3((int *)&status, WNOHANG, 0) > 0) 375 child_count--; 376 } 377 378 static void 379 mcleanup(signo) 380 int signo; 381 { 382 if (lflag) 383 syslog(LOG_INFO, "exiting"); 384 unlink(_PATH_SOCKETNAME); 385 exit(0); 386 } 387 388 /* 389 * Stuff for handling job specifications 390 */ 391 char *user[MAXUSERS]; /* users to process */ 392 int users; /* # of users in user array */ 393 int requ[MAXREQUESTS]; /* job number of spool entries */ 394 int requests; /* # of spool requests */ 395 char *person; /* name of person doing lprm */ 396 397 char fromb[NI_MAXHOST]; /* buffer for client's machine name */ 398 char cbuf[BUFSIZ]; /* command line buffer */ 399 char *cmdnames[] = { 400 "null", 401 "printjob", 402 "recvjob", 403 "displayq short", 404 "displayq long", 405 "rmjob" 406 }; 407 408 static void 409 doit() 410 { 411 char *cp; 412 int n; 413 414 for (;;) { 415 cp = cbuf; 416 do { 417 if (cp >= &cbuf[sizeof(cbuf) - 1]) 418 fatal("Command line too long"); 419 if ((n = read(1, cp, 1)) != 1) { 420 if (n < 0) 421 fatal("Lost connection"); 422 return; 423 } 424 } while (*cp++ != '\n'); 425 *--cp = '\0'; 426 cp = cbuf; 427 if (lflag) { 428 if (*cp >= '\1' && *cp <= '\5') { 429 syslog(LOG_INFO, "%s requests %s %s", 430 from, cmdnames[(int)*cp], cp+1); 431 setproctitle("serving %s: %s %s", from, 432 cmdnames[(int)*cp], cp+1); 433 } 434 else 435 syslog(LOG_INFO, "bad request (%d) from %s", 436 *cp, from); 437 } 438 switch (*cp++) { 439 case '\1': /* check the queue and print any jobs there */ 440 printer = cp; 441 printjob(); 442 break; 443 case '\2': /* receive files to be queued */ 444 if (!from_remote) { 445 syslog(LOG_INFO, "illegal request (%d)", *cp); 446 exit(1); 447 } 448 printer = cp; 449 recvjob(); 450 break; 451 case '\3': /* display the queue (short form) */ 452 case '\4': /* display the queue (long form) */ 453 printer = cp; 454 while (*cp) { 455 if (*cp != ' ') { 456 cp++; 457 continue; 458 } 459 *cp++ = '\0'; 460 while (isspace(*cp)) 461 cp++; 462 if (*cp == '\0') 463 break; 464 if (isdigit(*cp)) { 465 if (requests >= MAXREQUESTS) 466 fatal("Too many requests"); 467 requ[requests++] = atoi(cp); 468 } else { 469 if (users >= MAXUSERS) 470 fatal("Too many users"); 471 user[users++] = cp; 472 } 473 } 474 displayq(cbuf[0] - '\3'); 475 exit(0); 476 case '\5': /* remove a job from the queue */ 477 if (!from_remote) { 478 syslog(LOG_INFO, "illegal request (%d)", *cp); 479 exit(1); 480 } 481 printer = cp; 482 while (*cp && *cp != ' ') 483 cp++; 484 if (!*cp) 485 break; 486 *cp++ = '\0'; 487 person = cp; 488 while (*cp) { 489 if (*cp != ' ') { 490 cp++; 491 continue; 492 } 493 *cp++ = '\0'; 494 while (isspace(*cp)) 495 cp++; 496 if (*cp == '\0') 497 break; 498 if (isdigit(*cp)) { 499 if (requests >= MAXREQUESTS) 500 fatal("Too many requests"); 501 requ[requests++] = atoi(cp); 502 } else { 503 if (users >= MAXUSERS) 504 fatal("Too many users"); 505 user[users++] = cp; 506 } 507 } 508 rmjob(); 509 break; 510 } 511 fatal("Illegal service request"); 512 } 513 } 514 515 /* 516 * Make a pass through the printcap database and start printing any 517 * files left from the last time the machine went down. 518 */ 519 static void 520 startup() 521 { 522 char *buf; 523 char *cp; 524 525 /* 526 * Restart the daemons. 527 */ 528 while (cgetnext(&buf, printcapdb) > 0) { 529 if (ckqueue(buf) <= 0) { 530 free(buf); 531 continue; /* no work to do for this printer */ 532 } 533 for (cp = buf; *cp; cp++) 534 if (*cp == '|' || *cp == ':') { 535 *cp = '\0'; 536 break; 537 } 538 if (lflag) 539 syslog(LOG_INFO, "work for %s", buf); 540 switch (fork()) { 541 case -1: 542 syslog(LOG_WARNING, "startup: cannot fork"); 543 mcleanup(0); 544 case 0: 545 printer = buf; 546 setproctitle("working on printer %s", printer); 547 cgetclose(); 548 printjob(); 549 /* NOTREACHED */ 550 default: 551 child_count++; 552 free(buf); 553 } 554 } 555 } 556 557 /* 558 * Make sure there's some work to do before forking off a child 559 */ 560 static int 561 ckqueue(cap) 562 char *cap; 563 { 564 struct dirent *d; 565 DIR *dirp; 566 char *spooldir; 567 568 if (cgetstr(cap, "sd", &spooldir) == -1) 569 spooldir = _PATH_DEFSPOOL; 570 if ((dirp = opendir(spooldir)) == NULL) 571 return (-1); 572 while ((d = readdir(dirp)) != NULL) { 573 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 574 continue; /* daemon control files only */ 575 closedir(dirp); 576 return (1); /* found something */ 577 } 578 closedir(dirp); 579 return (0); 580 } 581 582 #define DUMMY ":nobody::" 583 584 /* 585 * Check to see if the from host has access to the line printer. 586 */ 587 static void 588 chkhost(f) 589 struct sockaddr *f; 590 { 591 struct addrinfo hints, *res, *r; 592 FILE *hostf; 593 int first = 1, good = 0; 594 char host[NI_MAXHOST], ip[NI_MAXHOST]; 595 char serv[NI_MAXSERV]; 596 int error; 597 598 error = getnameinfo(f, f->sa_len, NULL, 0, serv, sizeof(serv), 599 NI_NUMERICSERV); 600 if (error || atoi(serv) >= IPPORT_RESERVED) 601 fatal("Malformed from address"); 602 603 /* Need real hostname for temporary filenames */ 604 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 605 NI_NAMEREQD); 606 if (error) { 607 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 608 NI_NUMERICHOST); 609 if (error) 610 fatal("Host name for your address unknown"); 611 else 612 fatal("Host name for your address (%s) unknown", host); 613 } 614 615 (void)strncpy(fromb, host, sizeof(fromb) - 1); 616 fromb[sizeof(fromb) - 1] = '\0'; 617 from = fromb; 618 619 /* need address in stringform for comparison (no DNS lookup here) */ 620 error = getnameinfo(f, f->sa_len, host, sizeof(host), NULL, 0, 621 NI_NUMERICHOST); 622 if (error) 623 fatal("Cannot print address"); 624 625 /* Check for spoof, ala rlogind */ 626 memset(&hints, 0, sizeof(hints)); 627 hints.ai_family = PF_UNSPEC; 628 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 629 error = getaddrinfo(fromb, NULL, &hints, &res); 630 if (error) { 631 fatal("hostname for your address (%s) unknown: %s", host, 632 gai_strerror(error)); 633 } 634 good = 0; 635 for (r = res; good == 0 && r; r = r->ai_next) { 636 error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, sizeof(ip), 637 NULL, 0, NI_NUMERICHOST); 638 if (!error && !strcmp(host, ip)) 639 good = 1; 640 } 641 if (res) 642 freeaddrinfo(res); 643 if (good == 0) 644 fatal("address for your hostname (%s) not matched", host); 645 setproctitle("serving %s", from); 646 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 647 again: 648 if (hostf) { 649 if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { 650 (void)fclose(hostf); 651 return; 652 } 653 (void)fclose(hostf); 654 } 655 if (first == 1) { 656 first = 0; 657 hostf = fopen(_PATH_HOSTSLPD, "r"); 658 goto again; 659 } 660 fatal("Your host does not have line printer access"); 661 /*NOTREACHED*/ 662 } 663 664 static void 665 usage() 666 { 667 extern char *__progname; /* XXX */ 668 669 fprintf(stderr, "usage: %s [-dlrs] [-n maxchild] [-w maxwait] [port]\n", 670 __progname); 671 exit(1); 672 } 673 674 /* setup server socket for specified address family */ 675 /* if af is PF_UNSPEC more than one socket may be returned */ 676 /* the returned list is dynamically allocated, so caller needs to free it */ 677 int * 678 socksetup(af, options) 679 int af, options; 680 { 681 struct addrinfo hints, *res, *r; 682 int error, maxs, *s, *socks; 683 const int on = 1; 684 685 memset(&hints, 0, sizeof(hints)); 686 hints.ai_flags = AI_PASSIVE; 687 hints.ai_family = af; 688 hints.ai_socktype = SOCK_STREAM; 689 error = getaddrinfo(NULL, "printer", &hints, &res); 690 if (error) { 691 syslog(LOG_ERR, (gai_strerror(error))); 692 mcleanup(0); 693 } 694 695 /* Count max number of sockets we may open */ 696 for (maxs = 0, r = res; r; r = r->ai_next, maxs++) 697 ; 698 socks = malloc((maxs + 1) * sizeof(int)); 699 if (!socks) { 700 syslog(LOG_ERR, "couldn't allocate memory for sockets"); 701 mcleanup(0); 702 } 703 704 *socks = 0; /* num of sockets counter at start of array */ 705 s = socks + 1; 706 for (r = res; r; r = r->ai_next) { 707 *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 708 if (*s < 0) { 709 syslog(LOG_DEBUG, "socket(): %m"); 710 continue; 711 } 712 if (options & SO_DEBUG) 713 if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, 714 &on, sizeof(on)) < 0) { 715 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 716 close (*s); 717 continue; 718 } 719 if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { 720 syslog(LOG_DEBUG, "bind(): %m"); 721 close (*s); 722 continue; 723 } 724 *socks = *socks + 1; 725 s++; 726 } 727 728 if (res) 729 freeaddrinfo(res); 730 731 if (*socks == 0) { 732 syslog(LOG_ERR, "Couldn't bind to any socket"); 733 free(socks); 734 mcleanup(0); 735 } 736 return(socks); 737 } 738