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 __P((int, char **)); 111 static void reapchild __P((int)); 112 static void mcleanup __P((int)); 113 static void doit __P((void)); 114 static void startup __P((void)); 115 static void chkhost __P((struct sockaddr_in *)); 116 static int ckqueue __P((struct printer *)); 117 static void usage __P((void)); 118 /* From rcmd.c: */ 119 int __ivaliduser __P((FILE *, u_long, const char *, 120 const char *)); 121 122 uid_t uid, euid; 123 124 int 125 main(argc, argv) 126 int argc; 127 char **argv; 128 { 129 int errs, f, funix, finet, fromlen, i, socket_debug; 130 fd_set defreadfds; 131 struct sockaddr_un un, fromunix; 132 struct sockaddr_in sin, frominet; 133 int lfd; 134 sigset_t omask, nmask; 135 struct servent *sp, serv; 136 137 euid = geteuid(); /* these shouldn't be different */ 138 uid = getuid(); 139 socket_debug = 0; 140 gethostname(host, sizeof(host)); 141 142 name = "lpd"; 143 144 if (euid != 0) 145 errx(EX_NOPERM,"must run as root"); 146 147 errs = 0; 148 while ((i = getopt(argc, argv, "dlp")) != -1) 149 switch (i) { 150 case 'd': 151 socket_debug++; 152 break; 153 case 'l': 154 lflag++; 155 break; 156 case 'p': 157 pflag++; 158 break; 159 default: 160 errs++; 161 } 162 argc -= optind; 163 argv += optind; 164 if (errs) 165 usage(); 166 167 if (argc == 1) { 168 if ((i = atoi(argv[0])) == 0) 169 usage(); 170 if (i < 0 || i > USHRT_MAX) 171 errx(EX_USAGE, "port # %d is invalid", i); 172 173 serv.s_port = htons(i); 174 sp = &serv; 175 argc--; 176 } else { 177 sp = getservbyname("printer", "tcp"); 178 if (sp == NULL) 179 errx(EX_OSFILE, "printer/tcp: unknown service"); 180 } 181 182 if (argc != 0) 183 usage(); 184 185 /* 186 * We run chkprintcap right away to catch any errors and blat them 187 * to stderr while we still have it open, rather than sending them 188 * to syslog and leaving the user wondering why lpd started and 189 * then stopped. There should probably be a command-line flag to 190 * ignore errors from chkprintcap. 191 */ 192 { 193 pid_t pid; 194 int status; 195 pid = fork(); 196 if (pid < 0) { 197 err(EX_OSERR, "cannot fork"); 198 } else if (pid == 0) { /* child */ 199 execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); 200 err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); 201 } 202 if (waitpid(pid, &status, 0) < 0) { 203 err(EX_OSERR, "cannot wait"); 204 } 205 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 206 errx(EX_OSFILE, "%d errors in printcap file, exiting", 207 WEXITSTATUS(status)); 208 } 209 210 #ifndef DEBUG 211 /* 212 * Set up standard environment by detaching from the parent. 213 */ 214 daemon(0, 0); 215 #endif 216 217 openlog("lpd", LOG_PID, LOG_LPR); 218 syslog(LOG_INFO, "lpd startup: logging=%d%s", lflag, 219 socket_debug ? " dbg" : ""); 220 (void) umask(0); 221 /* 222 * NB: This depends on O_NONBLOCK semantics doing the right thing; 223 * i.e., applying only to the O_EXLOCK and not to the rest of the 224 * open/creation. As of 1997-12-02, this is the case for commonly- 225 * used filesystems. There are other places in this code which 226 * make the same assumption. 227 */ 228 lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 229 LOCK_FILE_MODE); 230 if (lfd < 0) { 231 if (errno == EWOULDBLOCK) /* active deamon present */ 232 exit(0); 233 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 234 exit(1); 235 } 236 fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ 237 ftruncate(lfd, 0); 238 /* 239 * write process id for others to know 240 */ 241 sprintf(line, "%u\n", getpid()); 242 f = strlen(line); 243 if (write(lfd, line, f) != f) { 244 syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); 245 exit(1); 246 } 247 signal(SIGCHLD, reapchild); 248 /* 249 * Restart all the printers. 250 */ 251 startup(); 252 (void) unlink(_PATH_SOCKETNAME); 253 funix = socket(AF_UNIX, SOCK_STREAM, 0); 254 if (funix < 0) { 255 syslog(LOG_ERR, "socket: %m"); 256 exit(1); 257 } 258 259 sigemptyset(&nmask); 260 sigaddset(&nmask, SIGHUP); 261 sigaddset(&nmask, SIGINT); 262 sigaddset(&nmask, SIGQUIT); 263 sigaddset(&nmask, SIGTERM); 264 sigprocmask(SIG_BLOCK, &nmask, &omask); 265 266 (void) umask(07); 267 signal(SIGHUP, mcleanup); 268 signal(SIGINT, mcleanup); 269 signal(SIGQUIT, mcleanup); 270 signal(SIGTERM, mcleanup); 271 memset(&un, 0, sizeof(un)); 272 un.sun_family = AF_UNIX; 273 strcpy(un.sun_path, _PATH_SOCKETNAME); 274 #ifndef SUN_LEN 275 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 276 #endif 277 if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { 278 syslog(LOG_ERR, "ubind: %m"); 279 exit(1); 280 } 281 (void) umask(0); 282 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); 283 FD_ZERO(&defreadfds); 284 FD_SET(funix, &defreadfds); 285 listen(funix, 5); 286 finet = -1; 287 if (pflag == 0) { 288 finet = socket(AF_INET, SOCK_STREAM, 0); 289 if (finet >= 0) { 290 i = 1; 291 if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &i, 292 sizeof i) < 0) { 293 syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); 294 mcleanup(0); 295 } 296 if (socket_debug && 297 setsockopt(finet, SOL_SOCKET, SO_DEBUG, 298 &socket_debug, sizeof(socket_debug)) < 0) { 299 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m"); 300 mcleanup(0); 301 } 302 memset(&sin, 0, sizeof(sin)); 303 sin.sin_family = AF_INET; 304 sin.sin_port = sp->s_port; 305 if (bind(finet, (struct sockaddr *)&sin, 306 sizeof(sin)) < 0) { 307 syslog(LOG_ERR, "bind: %m"); 308 mcleanup(0); 309 } 310 FD_SET(finet, &defreadfds); 311 listen(finet, 5); 312 } 313 } 314 /* 315 * Main loop: accept, do a request, continue. 316 */ 317 memset(&frominet, 0, sizeof(frominet)); 318 memset(&fromunix, 0, sizeof(fromunix)); 319 if (lflag) 320 syslog(LOG_INFO, "lpd startup: ready to accept requests"); 321 /* 322 * XXX - should be redone for multi-protocol 323 */ 324 for (;;) { 325 int domain, nfds, s; 326 fd_set readfds; 327 328 FD_COPY(&defreadfds, &readfds); 329 nfds = select(20, &readfds, 0, 0, 0); 330 if (nfds <= 0) { 331 if (nfds < 0 && errno != EINTR) 332 syslog(LOG_WARNING, "select: %m"); 333 continue; 334 } 335 domain = 0; /* avoid compile-time warning */ 336 s = 0; /* avoid compile-time warning */ 337 if (FD_ISSET(funix, &readfds)) { 338 domain = AF_UNIX, fromlen = sizeof(fromunix); 339 s = accept(funix, 340 (struct sockaddr *)&fromunix, &fromlen); 341 } else if (pflag == 0) /* if (FD_ISSET(finet, &readfds)) */ { 342 domain = AF_INET, fromlen = sizeof(frominet); 343 s = accept(finet, 344 (struct sockaddr *)&frominet, &fromlen); 345 if (frominet.sin_port == htons(20)) { 346 close(s); 347 continue; 348 } 349 } 350 if (s < 0) { 351 if (errno != EINTR) 352 syslog(LOG_WARNING, "accept: %m"); 353 continue; 354 } 355 if (fork() == 0) { 356 signal(SIGCHLD, SIG_IGN); 357 signal(SIGHUP, SIG_IGN); 358 signal(SIGINT, SIG_IGN); 359 signal(SIGQUIT, SIG_IGN); 360 signal(SIGTERM, SIG_IGN); 361 (void) close(funix); 362 if (pflag == 0) { 363 (void) close(finet); 364 } 365 dup2(s, 1); 366 (void) close(s); 367 if (domain == AF_INET) { 368 from_remote = 1; 369 chkhost(&frominet); 370 } else 371 from_remote = 0; 372 doit(); 373 exit(0); 374 } 375 (void) close(s); 376 } 377 } 378 379 static void 380 reapchild(signo) 381 int signo; 382 { 383 union wait status; 384 385 while (wait3((int *)&status, WNOHANG, 0) > 0) 386 ; 387 } 388 389 static void 390 mcleanup(signo) 391 int signo; 392 { 393 /* 394 * XXX syslog(3) is not signal-safe. 395 */ 396 if (lflag) { 397 if (signo) 398 syslog(LOG_INFO, "exiting on signal %d", signo); 399 else 400 syslog(LOG_INFO, "exiting"); 401 } 402 unlink(_PATH_SOCKETNAME); 403 exit(0); 404 } 405 406 /* 407 * Stuff for handling job specifications 408 */ 409 char *user[MAXUSERS]; /* users to process */ 410 int users; /* # of users in user array */ 411 int requ[MAXREQUESTS]; /* job number of spool entries */ 412 int requests; /* # of spool requests */ 413 char *person; /* name of person doing lprm */ 414 415 char fromb[MAXHOSTNAMELEN]; /* buffer for client's machine name */ 416 char cbuf[BUFSIZ]; /* command line buffer */ 417 char *cmdnames[] = { 418 "null", 419 "printjob", 420 "recvjob", 421 "displayq short", 422 "displayq long", 423 "rmjob" 424 }; 425 426 static void 427 doit() 428 { 429 char *cp, *printer; 430 int n; 431 int status; 432 struct printer myprinter, *pp = &myprinter; 433 434 init_printer(&myprinter); 435 436 for (;;) { 437 cp = cbuf; 438 do { 439 if (cp >= &cbuf[sizeof(cbuf) - 1]) 440 fatal(0, "Command line too long"); 441 if ((n = read(1, cp, 1)) != 1) { 442 if (n < 0) 443 fatal(0, "Lost connection"); 444 return; 445 } 446 } while (*cp++ != '\n'); 447 *--cp = '\0'; 448 cp = cbuf; 449 if (lflag) { 450 if (*cp >= '\1' && *cp <= '\5') 451 syslog(LOG_INFO, "%s requests %s %s", 452 from, cmdnames[(u_char)*cp], cp+1); 453 else 454 syslog(LOG_INFO, "bad request (%d) from %s", 455 *cp, from); 456 } 457 switch (*cp++) { 458 case CMD_CHECK_QUE: /* check the queue, print any jobs there */ 459 startprinting(cp); 460 break; 461 case CMD_TAKE_THIS: /* receive files to be queued */ 462 if (!from_remote) { 463 syslog(LOG_INFO, "illegal request (%d)", *cp); 464 exit(1); 465 } 466 recvjob(cp); 467 break; 468 case CMD_SHOWQ_SHORT: /* display the queue (short form) */ 469 case CMD_SHOWQ_LONG: /* display the queue (long form) */ 470 /* XXX - this all needs to be redone. */ 471 printer = cp; 472 while (*cp) { 473 if (*cp != ' ') { 474 cp++; 475 continue; 476 } 477 *cp++ = '\0'; 478 while (isspace(*cp)) 479 cp++; 480 if (*cp == '\0') 481 break; 482 if (isdigit(*cp)) { 483 if (requests >= MAXREQUESTS) 484 fatal(0, "Too many requests"); 485 requ[requests++] = atoi(cp); 486 } else { 487 if (users >= MAXUSERS) 488 fatal(0, "Too many users"); 489 user[users++] = cp; 490 } 491 } 492 status = getprintcap(printer, pp); 493 if (status < 0) 494 fatal(pp, pcaperr(status)); 495 displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); 496 exit(0); 497 case CMD_RMJOB: /* remove a job from the queue */ 498 if (!from_remote) { 499 syslog(LOG_INFO, "illegal request (%d)", *cp); 500 exit(1); 501 } 502 printer = cp; 503 while (*cp && *cp != ' ') 504 cp++; 505 if (!*cp) 506 break; 507 *cp++ = '\0'; 508 person = cp; 509 while (*cp) { 510 if (*cp != ' ') { 511 cp++; 512 continue; 513 } 514 *cp++ = '\0'; 515 while (isspace(*cp)) 516 cp++; 517 if (*cp == '\0') 518 break; 519 if (isdigit(*cp)) { 520 if (requests >= MAXREQUESTS) 521 fatal(0, "Too many requests"); 522 requ[requests++] = atoi(cp); 523 } else { 524 if (users >= MAXUSERS) 525 fatal(0, "Too many users"); 526 user[users++] = cp; 527 } 528 } 529 rmjob(printer); 530 break; 531 } 532 fatal(0, "Illegal service request"); 533 } 534 } 535 536 /* 537 * Make a pass through the printcap database and start printing any 538 * files left from the last time the machine went down. 539 */ 540 static void 541 startup() 542 { 543 int pid, status, more; 544 struct printer myprinter, *pp = &myprinter; 545 546 more = firstprinter(pp, &status); 547 if (status) 548 goto errloop; 549 while (more) { 550 if (ckqueue(pp) <= 0) { 551 goto next; 552 } 553 if (lflag) 554 syslog(LOG_INFO, "lpd startup: work for %s", 555 pp->printer); 556 if ((pid = fork()) < 0) { 557 syslog(LOG_WARNING, "lpd startup: cannot fork for %s", 558 pp->printer); 559 mcleanup(0); 560 } 561 if (pid == 0) { 562 lastprinter(); 563 printjob(pp); 564 /* NOTREACHED */ 565 } 566 do { 567 next: 568 more = nextprinter(pp, &status); 569 errloop: 570 if (status) 571 syslog(LOG_WARNING, 572 "lpd startup: printcap entry for %s has errors, skipping", 573 pp->printer ? pp->printer : "<???>"); 574 } while (more && status); 575 } 576 } 577 578 /* 579 * Make sure there's some work to do before forking off a child 580 */ 581 static int 582 ckqueue(pp) 583 struct printer *pp; 584 { 585 register struct dirent *d; 586 DIR *dirp; 587 char *spooldir; 588 589 spooldir = pp->spool_dir; 590 if ((dirp = opendir(spooldir)) == NULL) 591 return (-1); 592 while ((d = readdir(dirp)) != NULL) { 593 if (d->d_name[0] != 'c' || d->d_name[1] != 'f') 594 continue; /* daemon control files only */ 595 closedir(dirp); 596 return (1); /* found something */ 597 } 598 closedir(dirp); 599 return (0); 600 } 601 602 #define DUMMY ":nobody::" 603 604 /* 605 * Check to see if the from host has access to the line printer. 606 */ 607 static void 608 chkhost(f) 609 struct sockaddr_in *f; 610 { 611 register struct hostent *hp; 612 register FILE *hostf; 613 int first = 1; 614 int good = 0; 615 616 /* Need real hostname for temporary filenames */ 617 hp = gethostbyaddr((char *)&f->sin_addr, 618 sizeof(struct in_addr), f->sin_family); 619 if (hp == NULL) 620 fatal(0, "Host name for your address (%s) unknown", 621 inet_ntoa(f->sin_addr)); 622 623 (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); 624 fromb[sizeof(fromb) - 1] = '\0'; 625 from = fromb; 626 strncpy(from_ip, inet_ntoa(f->sin_addr), MAXIPSTRLEN); 627 from_ip[sizeof(from_ip) - 1] = '\0'; 628 629 /* Check for spoof, ala rlogind */ 630 hp = gethostbyname(fromb); 631 if (!hp) 632 fatal(0, "hostname for your address (%s) unknown", from_ip); 633 for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { 634 if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, 635 sizeof(f->sin_addr))) 636 good = 1; 637 } 638 if (good == 0) 639 fatal(0, "address for your hostname (%s) not matched", 640 from_ip); 641 642 hostf = fopen(_PATH_HOSTSEQUIV, "r"); 643 again: 644 if (hostf) { 645 if (__ivaliduser(hostf, f->sin_addr.s_addr, 646 DUMMY, DUMMY) == 0) { 647 (void) fclose(hostf); 648 return; 649 } 650 (void) fclose(hostf); 651 } 652 if (first == 1) { 653 first = 0; 654 hostf = fopen(_PATH_HOSTSLPD, "r"); 655 goto again; 656 } 657 fatal(0, "Your host does not have line printer access"); 658 /*NOTREACHED*/ 659 } 660 661 static void 662 usage() 663 { 664 fprintf(stderr, "usage: lpd [-dlp] [port#]\n"); 665 exit(EX_USAGE); 666 } 667