1 /* $OpenBSD: printer.c,v 1.3 2021/10/24 21:24:18 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <sys/tree.h> 22 #include <sys/wait.h> 23 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <limits.h> 27 #include <pwd.h> 28 #include <signal.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <unistd.h> 34 #include <vis.h> 35 36 #include "lpd.h" 37 #include "lp.h" 38 #include "log.h" 39 40 #define RETRY_MAX 5 41 42 #define JOB_OK 0 43 #define JOB_AGAIN 1 44 #define JOB_IGNORE 2 45 #define JOB_ERROR 3 46 47 enum { 48 OK = 0, 49 ERR_TRANSIENT, /* transient error */ 50 ERR_ACCOUNT, /* account required on the local machine */ 51 ERR_ACCESS, /* cannot read file */ 52 ERR_INODE, /* inode changed */ 53 ERR_NOIMPL, /* unimplemented feature */ 54 ERR_REJECTED, /* remote server rejected a job */ 55 ERR_ERROR, /* filter report an error */ 56 ERR_FILTER, /* filter return invalid status */ 57 }; 58 59 struct job { 60 char *class; 61 char *host; 62 char *literal; 63 char *mail; 64 char *name; 65 char *person; 66 char *statinfo; 67 char *title; 68 int indent; 69 int pagewidth; 70 }; 71 72 struct prnstate { 73 int pfd; /* printer fd */ 74 int ofilter; /* use output filter when printing */ 75 int ofd; /* output filter fd */ 76 pid_t opid; /* output filter process */ 77 int tof; /* true if at top of form */ 78 int count; /* number of printed files */ 79 char efile[64]; /* filename for filter stderr */ 80 }; 81 82 static void sighandler(int); 83 static char *xstrdup(const char *); 84 85 static int openfile(const char *, const char *, struct stat *, FILE **); 86 static int printjob(const char *, int); 87 static void printbanner(struct job *); 88 static int printfile(struct job *, int, const char *, const char *); 89 static int sendjob(const char *, int); 90 static int sendcmd(const char *, ...); 91 static int sendfile(int, const char *, const char *); 92 static int recvack(void); 93 static void mailreport(struct job *, int); 94 95 static void prn_open(void); 96 static int prn_connect(void); 97 static void prn_close(void); 98 static int prn_fstart(void); 99 static void prn_fsuspend(void); 100 static void prn_fresume(void); 101 static void prn_fclose(void); 102 static int prn_formfeed(void); 103 static int prn_write(const char *, size_t); 104 static int prn_writefile(FILE *); 105 static int prn_puts(const char *); 106 static ssize_t prn_read(char *, size_t); 107 108 static struct lp_printer *lp; 109 static struct prnstate *prn; 110 111 void 112 printer(int debug, int verbose, const char *name) 113 { 114 struct sigaction sa; 115 struct passwd *pw; 116 struct lp_queue q; 117 int fd, jobidx, qstate, r, reload, retry; 118 char buf[64], curr[1024]; 119 120 /* Early initialisation. */ 121 log_init(debug, LOG_LPR); 122 log_setverbose(verbose); 123 snprintf(buf, sizeof(buf), "printer:%s", name); 124 log_procinit(buf); 125 setproctitle("%s", buf); 126 127 if ((lpd_hostname = malloc(HOST_NAME_MAX+1)) == NULL) 128 fatal("%s: malloc", __func__); 129 gethostname(lpd_hostname, HOST_NAME_MAX+1); 130 131 /* Detach from lpd session if not in debug mode. */ 132 if (!debug) 133 if (setsid() == -1) 134 fatal("%s: setsid", __func__); 135 136 /* Read printer config. */ 137 if ((lp = calloc(1, sizeof(*lp))) == NULL) 138 fatal("%s: calloc", __func__); 139 if (lp_getprinter(lp, name) == -1) 140 exit(1); 141 142 /* 143 * Redirect stderr if not in debug mode. 144 * This must be done before dropping priviledges. 145 */ 146 if (!debug) { 147 fd = open(LP_LF(lp), O_WRONLY|O_APPEND); 148 if (fd == -1) 149 fatal("%s: open: %s", __func__, LP_LF(lp)); 150 if (fd != STDERR_FILENO) { 151 if (dup2(fd, STDERR_FILENO) == -1) 152 fatalx("%s: dup2", __func__); 153 (void)close(fd); 154 } 155 } 156 157 /* Drop priviledges. */ 158 if ((pw = getpwnam(LPD_USER)) == NULL) 159 fatalx("unknown user " LPD_USER); 160 161 if (setgroups(1, &pw->pw_gid) || 162 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 163 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 164 fatal("cannot drop privileges"); 165 166 /* Initialize the printer state. */ 167 if ((prn = calloc(1, sizeof(*prn))) == NULL) 168 fatal("%s: calloc", __func__); 169 prn->pfd = -1; 170 prn->ofd = -1; 171 172 /* Setup signals */ 173 memset(&sa, 0, sizeof(sa)); 174 sa.sa_handler = sighandler; 175 sa.sa_flags = SA_RESTART; 176 sigemptyset(&sa.sa_mask); 177 sigaddset(&sa.sa_mask, SIGINT); /* for kill() in sighandler */ 178 sigaction(SIGHUP, &sa, NULL); 179 sigaction(SIGINT, &sa, NULL); 180 sigaction(SIGQUIT, &sa, NULL); 181 sigaction(SIGTERM, &sa, NULL); 182 183 /* Grab lock file. */ 184 if (lp_lock(lp) == -1) { 185 if (errno == EWOULDBLOCK) { 186 log_debug("already locked"); 187 exit(0); 188 } 189 fatalx("cannot open lock file"); 190 } 191 192 /* Pledge. */ 193 switch (lp->lp_type) { 194 case PRN_LOCAL: 195 pledge("stdio rpath wpath cpath flock getpw tty proc exec", 196 NULL); 197 break; 198 199 case PRN_NET: 200 pledge("stdio rpath wpath cpath inet flock dns getpw proc exec", 201 NULL); 202 break; 203 204 case PRN_LPR: 205 pledge("stdio rpath wpath cpath inet flock dns getpw", NULL); 206 break; 207 } 208 209 /* Start processing the queue. */ 210 memset(&q, 0, sizeof(q)); 211 jobidx = 0; 212 reload = 1; 213 retry = 0; 214 curr[0] = '\0'; 215 216 for (;;) { 217 218 /* Check the queue state. */ 219 if (lp_getqueuestate(lp, 1, &qstate) == -1) 220 fatalx("cannot get queue state"); 221 if (qstate & LPQ_PRINTER_DOWN) { 222 log_debug("printing disabled"); 223 break; 224 } 225 if (qstate & LPQ_QUEUE_UPDATED) { 226 log_debug("queue updated"); 227 if (reload == 0) 228 lp_clearqueue(&q); 229 reload = 1; 230 } 231 232 /* Read the queue if needed. */ 233 if (reload || q.count == 0) { 234 if (lp_readqueue(lp, &q) == -1) 235 fatalx("cannot read queue"); 236 jobidx = 0; 237 reload = 0; 238 } 239 240 /* If the queue is empty, all done */ 241 if (q.count <= jobidx) { 242 log_debug("queue empty"); 243 break; 244 } 245 246 /* Open the printer if needed. */ 247 if (prn->pfd == -1) { 248 prn_open(); 249 /* 250 * Opening the printer might take some time. 251 * Re-read the queue in case its state has changed. 252 */ 253 lp_clearqueue(&q); 254 reload = 1; 255 continue; 256 } 257 258 if (strcmp(curr, q.cfname[jobidx])) 259 retry = 0; 260 else 261 strlcpy(curr, q.cfname[jobidx], sizeof(curr)); 262 263 lp_setcurrtask(lp, q.cfname[jobidx]); 264 if (lp->lp_type == PRN_LPR) 265 r = sendjob(q.cfname[jobidx], retry); 266 else 267 r = printjob(q.cfname[jobidx], retry); 268 lp_setcurrtask(lp, NULL); 269 270 switch (r) { 271 case JOB_OK: 272 log_info("job %s %s successfully", q.cfname[jobidx], 273 (lp->lp_type == PRN_LPR) ? "relayed" : "printed"); 274 break; 275 case JOB_AGAIN: 276 retry++; 277 continue; 278 case JOB_IGNORE: 279 break; 280 case JOB_ERROR: 281 log_warnx("job %s could not be printed", 282 q.cfname[jobidx]); 283 break; 284 } 285 curr[0] = '\0'; 286 jobidx++; 287 retry = 0; 288 } 289 290 if (prn->pfd != -1) { 291 if (prn->count) { 292 prn_formfeed(); 293 if (lp->lp_tr) 294 prn_puts(lp->lp_tr); 295 } 296 prn_close(); 297 } 298 299 exit(0); 300 } 301 302 static void 303 sighandler(int code) 304 { 305 log_info("got signal %d", code); 306 307 exit(0); 308 } 309 310 static char * 311 xstrdup(const char *s) 312 { 313 char *r; 314 315 if ((r = strdup(s)) == NULL) 316 fatal("strdup"); 317 318 return r; 319 } 320 321 /* 322 * Open control/data file, and check that the inode information is valid. 323 * On success, fill the "st" structure and set "fpp" and return 0 (OK). 324 * Return an error code on error. 325 */ 326 static int 327 openfile(const char *fname, const char *inodeinfo, struct stat *st, FILE **fpp) 328 { 329 FILE *fp; 330 char buf[64]; 331 332 if (inodeinfo) { 333 log_warnx("cannot open %s: symlink not implemented", fname); 334 return ERR_NOIMPL; 335 } 336 else { 337 if ((fp = lp_fopen(lp, fname)) == NULL) { 338 log_warn("cannot open %s", fname); 339 return ERR_ACCESS; 340 } 341 } 342 343 if (fstat(fileno(fp), st) == -1) { 344 log_warn("%s: fstat: %s", __func__, fname); 345 fclose(fp); 346 return ERR_ACCESS; 347 } 348 349 if (inodeinfo) { 350 snprintf(buf, sizeof(buf), "%d %llu", st->st_dev, st->st_ino); 351 if (strcmp(inodeinfo, buf)) { 352 log_warnx("inode changed for %s", fname); 353 fclose(fp); 354 return ERR_INODE; 355 } 356 } 357 358 *fpp = fp; 359 360 return OK; 361 } 362 363 /* 364 * Print the job described by the control file. 365 */ 366 static int 367 printjob(const char *cfname, int retry) 368 { 369 struct job job; 370 FILE *fp; 371 ssize_t len; 372 size_t linesz = 0; 373 char *line = NULL; 374 const char *errstr; 375 long long num; 376 int r, ret = JOB_OK; 377 378 log_debug("printing job %s...", cfname); 379 380 prn->efile[0] = '\0'; 381 memset(&job, 0, sizeof(job)); 382 job.pagewidth = lp->lp_pw; 383 384 if ((fp = lp_fopen(lp, cfname)) == NULL) { 385 if (errno == ENOENT) { 386 log_info("missing control file %s", cfname); 387 return JOB_IGNORE; 388 } 389 /* XXX no fatal? */ 390 fatal("cannot open %s", cfname); 391 } 392 393 /* First pass: setup the job structure, print banner and print data. */ 394 while ((len = getline(&line, &linesz, fp)) != -1) { 395 if (line[len-1] == '\n') 396 line[len-1] = '\0'; 397 398 switch (line[0]) { 399 case 'C': /* Classification */ 400 if (line[1]) { 401 free(job.class); 402 job.class = xstrdup(line + 1); 403 } 404 else if (job.class == NULL) 405 job.class = xstrdup(lpd_hostname); 406 break; 407 408 case 'H': /* Host name */ 409 free(job.host); 410 job.host = xstrdup(line + 1); 411 if (job.class == NULL) 412 job.class = xstrdup(line + 1); 413 break; 414 415 case 'I': /* Indent */ 416 errstr = NULL; 417 num = strtonum(line + 1, 0, INT_MAX, &errstr); 418 if (errstr == NULL) 419 job.indent = num; 420 else 421 log_warnx("strtonum: %s", errstr); 422 break; 423 424 case 'J': /* Job Name */ 425 free(job.name); 426 if (line[1]) 427 job.name = strdup(line + 1); 428 else 429 job.name = strdup(" "); 430 break; 431 432 case 'L': /* Literal */ 433 free(job.literal); 434 job.literal = xstrdup(line + 1); 435 if (!lp->lp_sh && !lp->lp_hl) 436 printbanner(&job); 437 break; 438 439 case 'M': /* Send mail to the specified user */ 440 free(job.mail); 441 job.mail = xstrdup(line + 1); 442 break; 443 444 case 'N': /* Filename */ 445 break; 446 447 case 'P': /* Person */ 448 free(job.person); 449 job.person = xstrdup(line + 1); 450 if (lp->lp_rs && getpwnam(job.person) == NULL) { 451 mailreport(&job, ERR_ACCOUNT); 452 ret = JOB_ERROR; 453 goto remove; 454 } 455 break; 456 457 case 'S': /* Stat info for symlink protection */ 458 job.statinfo = xstrdup(line + 1); 459 break; 460 461 case 'T': /* Title for pr */ 462 job.title = xstrdup(line + 1); 463 break; 464 465 case 'U': /* Unlink */ 466 break; 467 468 case 'W': /* Width */ 469 errstr = NULL; 470 num = strtonum(line + 1, 0, INT_MAX, &errstr); 471 if (errstr == NULL) 472 job.pagewidth = num; 473 else 474 log_warnx("strtonum: %s", errstr); 475 break; 476 477 case '1': /* troff fonts */ 478 case '2': 479 case '3': 480 case '4': 481 /* XXX not implemented */ 482 break; 483 484 default: 485 if (line[0] < 'a' || line[0] > 'z') 486 break; 487 488 r = printfile(&job, line[0], line+1, job.statinfo); 489 free(job.statinfo); 490 job.statinfo = NULL; 491 free(job.title); 492 job.title = NULL; 493 if (r) { 494 if (r == ERR_TRANSIENT && retry < RETRY_MAX) { 495 ret = JOB_AGAIN; 496 goto done; 497 } 498 mailreport(&job, r); 499 ret = JOB_ERROR; 500 goto remove; 501 } 502 } 503 } 504 505 remove: 506 if (lp_unlink(lp, cfname) == -1) 507 log_warn("cannot unlink %s", cfname); 508 509 /* Second pass: print trailing banner, mail report, and remove files. */ 510 rewind(fp); 511 while ((len = getline(&line, &linesz, fp)) != -1) { 512 if (line[len-1] == '\n') 513 line[len-1] = '\0'; 514 515 switch (line[0]) { 516 case 'L': /* Literal */ 517 if (ret != JOB_OK) 518 break; 519 if (!lp->lp_sh && lp->lp_hl) 520 printbanner(&job); 521 break; 522 523 case 'M': /* Send mail to the specified user */ 524 if (ret == JOB_OK) 525 mailreport(&job, ret); 526 break; 527 528 case 'U': /* Unlink */ 529 if (lp_unlink(lp, line + 1) == -1) 530 log_warn("cannot unlink %s", line + 1); 531 break; 532 } 533 } 534 535 done: 536 if (prn->efile[0]) 537 unlink(prn->efile); 538 (void)fclose(fp); 539 free(job.class); 540 free(job.host); 541 free(job.literal); 542 free(job.mail); 543 free(job.name); 544 free(job.person); 545 free(job.statinfo); 546 free(job.title); 547 return ret; 548 } 549 550 static void 551 printbanner(struct job *job) 552 { 553 time_t t; 554 555 time(&t); 556 557 prn_formfeed(); 558 559 if (lp->lp_sb) { 560 if (job->class) { 561 prn_puts(job->class); 562 prn_puts(":"); 563 } 564 prn_puts(job->literal); 565 prn_puts(" Job: "); 566 prn_puts(job->name); 567 prn_puts(" Date: "); 568 prn_puts(ctime(&t)); 569 prn_puts("\n"); 570 } else { 571 prn_puts("\n\n\n"); 572 lp_banner(prn->pfd, job->literal, lp->lp_pw); 573 prn_puts("\n\n"); 574 lp_banner(prn->pfd, job->name, lp->lp_pw); 575 if (job->class) { 576 prn_puts("\n\n\n"); 577 lp_banner(prn->pfd, job->class, lp->lp_pw); 578 } 579 prn_puts("\n\n\n\n\t\t\t\t\tJob: "); 580 prn_puts(job->name); 581 prn_puts("\n\t\t\t\t\tDate: "); 582 prn_puts(ctime(&t)); 583 prn_puts("\n"); 584 } 585 586 prn_formfeed(); 587 } 588 589 static int 590 printfile(struct job *job, int fmt, const char *fname, const char *inodeinfo) 591 { 592 pid_t pid; 593 struct stat st; 594 FILE *fp; 595 size_t n; 596 int ret, argc, efd, status; 597 char *argv[16], *prog, width[16], length[16], indent[16], tmp[512]; 598 599 log_debug("printing file %s...", fname); 600 601 switch (fmt) { 602 case 'f': /* print file as-is */ 603 case 'o': /* print postscript file */ 604 case 'l': /* print file as-is but pass control chars */ 605 break; 606 607 case 'p': /* print using pr(1) */ 608 case 'r': /* print fortran text file */ 609 case 't': /* print troff output */ 610 case 'n': /* print ditroff output */ 611 case 'd': /* print tex output */ 612 case 'c': /* print cifplot output */ 613 case 'g': /* print plot output */ 614 case 'v': /* print raster output */ 615 default: 616 log_warn("unrecognized output format '%c'", fmt); 617 return ERR_NOIMPL; 618 } 619 620 if ((ret = openfile(fname, inodeinfo, &st, &fp)) != OK) 621 return ret; 622 623 prn_formfeed(); 624 625 /* 626 * No input filter, just write the raw file. 627 */ 628 if (!lp->lp_if) { 629 if (prn_writefile(fp) == -1) 630 ret = ERR_TRANSIENT; 631 else 632 ret = OK; 633 (void)fclose(fp); 634 return ret; 635 } 636 637 /* 638 * Otherwise, run the input filter with proper plumbing. 639 */ 640 641 /* Prepare filter arguments. */ 642 snprintf(width, sizeof(width), "-w%d", job->pagewidth); 643 snprintf(length, sizeof(length), "-l%ld", lp->lp_pl); 644 snprintf(indent, sizeof(indent), "-i%d", job->indent); 645 prog = strrchr(lp->lp_if, '/'); 646 647 argc = 0; 648 argv[argc++] = prog ? (prog + 1) : lp->lp_if; 649 if (fmt == 'l') 650 argv[argc++] = "-c"; 651 argv[argc++] = width; 652 argv[argc++] = length; 653 argv[argc++] = indent; 654 argv[argc++] = "-n"; 655 argv[argc++] = job->person; 656 if (job->name) { 657 argv[argc++] = "-j"; 658 argv[argc++]= job->name; 659 } 660 argv[argc++] = "-h"; 661 argv[argc++] = job->host; 662 argv[argc++] = lp->lp_af; 663 argv[argc++] = NULL; 664 665 /* Open the stderr file. */ 666 strlcpy(prn->efile, "/tmp/prn.XXXXXXXX", sizeof(prn->efile)); 667 if ((efd = mkstemp(prn->efile)) == -1) { 668 log_warn("%s: mkstemp", __func__); 669 (void)fclose(fp); 670 return ERR_TRANSIENT; 671 } 672 673 /* Disable output filter. */ 674 prn_fsuspend(); 675 676 /* Run input filter */ 677 switch ((pid = fork())) { 678 case -1: 679 log_warn("%s: fork", __func__); 680 close(efd); 681 prn_fresume(); 682 return ERR_TRANSIENT; 683 684 case 0: 685 if (dup2(fileno(fp), STDIN_FILENO) == -1) 686 fatal("%s:, dup2", __func__); 687 if (dup2(prn->pfd, STDOUT_FILENO) == -1) 688 fatal("%s:, dup2", __func__); 689 if (dup2(efd, STDERR_FILENO) == -1) 690 fatal("%s:, dup2", __func__); 691 if (closefrom(3) == -1) 692 fatal("%s:, closefrom", __func__); 693 execv(lp->lp_if, argv); 694 log_warn("%s:, execv", __func__); 695 exit(2); 696 697 default: 698 break; 699 } 700 701 log_debug("waiting for ifilter..."); 702 703 /* Wait for input filter to finish. */ 704 while (waitpid(pid, &status, 0) == -1) 705 log_warn("%s: waitpid", __func__); 706 707 log_debug("ifilter done, status %d", status); 708 709 /* Resume output filter */ 710 prn_fresume(); 711 prn->tof = 0; 712 713 /* Copy efd to stderr */ 714 if (lseek(efd, 0, SEEK_SET) == -1) 715 log_warn("%s: lseek", __func__); 716 while ((n = read(efd, tmp, sizeof(tmp))) > 0) 717 (void)write(STDERR_FILENO, tmp, n); 718 close(efd); 719 720 if (!WIFEXITED(status)) { 721 log_warn("filter terminated (termsig=%d)", WTERMSIG(status)); 722 return ERR_FILTER; 723 } 724 725 switch (WEXITSTATUS(status)) { 726 case 0: 727 prn->tof = 1; 728 return OK; 729 730 case 1: 731 return ERR_TRANSIENT; 732 733 case 2: 734 return ERR_ERROR; 735 736 default: 737 log_warn("filter exited (exitstatus=%d)", WEXITSTATUS(status)); 738 return ERR_FILTER; 739 } 740 } 741 742 static int 743 sendjob(const char *cfname, int retry) 744 { 745 struct job job; 746 FILE *fp; 747 ssize_t len; 748 size_t linesz = 0; 749 char *line = NULL; 750 int ret = JOB_OK, r; 751 752 log_debug("sending job %s...", cfname); 753 754 memset(&job, 0, sizeof(job)); 755 756 if ((fp = lp_fopen(lp, cfname)) == NULL) { 757 if (errno == ENOENT) { 758 log_info("missing control file %s", cfname); 759 return JOB_IGNORE; 760 } 761 /* XXX no fatal? */ 762 fatal("cannot open %s", cfname); 763 } 764 765 /* First pass: setup the job structure, and forward data files. */ 766 while ((len = getline(&line, &linesz, fp)) != -1) { 767 if (line[len-1] == '\n') 768 line[len-1] = '\0'; 769 770 switch (line[0]) { 771 case 'P': 772 free(job.person); 773 job.person = xstrdup(line + 1); 774 break; 775 776 case 'S': 777 free(job.statinfo); 778 job.statinfo = xstrdup(line + 1); 779 break; 780 781 default: 782 if (line[0] < 'a' || line[0] > 'z') 783 break; 784 785 r = sendfile('\3', line+1, job.statinfo); 786 free(job.statinfo); 787 job.statinfo = NULL; 788 if (r) { 789 if (r == ERR_TRANSIENT && retry < RETRY_MAX) { 790 ret = JOB_AGAIN; 791 goto done; 792 } 793 mailreport(&job, r); 794 ret = JOB_ERROR; 795 goto remove; 796 } 797 } 798 } 799 800 /* Send the control file. */ 801 if ((r = sendfile('\2', cfname, ""))) { 802 if (r == ERR_TRANSIENT && retry < RETRY_MAX) { 803 ret = JOB_AGAIN; 804 goto done; 805 } 806 mailreport(&job, r); 807 ret = JOB_ERROR; 808 } 809 810 remove: 811 if (lp_unlink(lp, cfname) == -1) 812 log_warn("cannot unlink %s", cfname); 813 814 /* Second pass: remove files. */ 815 rewind(fp); 816 while ((len = getline(&line, &linesz, fp)) != -1) { 817 if (line[len-1] == '\n') 818 line[len-1] = '\0'; 819 820 switch (line[0]) { 821 case 'U': 822 if (lp_unlink(lp, line + 1) == -1) 823 log_warn("cannot unlink %s", line + 1); 824 break; 825 } 826 } 827 828 done: 829 (void)fclose(fp); 830 free(line); 831 free(job.person); 832 free(job.statinfo); 833 return ret; 834 } 835 836 /* 837 * Send a LPR command to the remote lpd server and return the ack. 838 * Return 0 for ack, 1 or nack, -1 and set errno on error. 839 */ 840 static int 841 sendcmd(const char *fmt, ...) 842 { 843 va_list ap; 844 unsigned char line[1024]; 845 int len; 846 847 va_start(ap, fmt); 848 len = vsnprintf(line, sizeof(line), fmt, ap); 849 va_end(ap); 850 851 if (len < 0) { 852 log_warn("%s: vsnprintf", __func__); 853 return -1; 854 } 855 856 if (prn_puts(line) == -1) 857 return -1; 858 859 return recvack(); 860 } 861 862 static int 863 sendfile(int type, const char *fname, const char *inodeinfo) 864 { 865 struct stat st; 866 FILE *fp = NULL; 867 int ret; 868 869 log_debug("sending file %s...", fname); 870 871 if ((ret = openfile(fname, inodeinfo, &st, &fp)) != OK) 872 return ret; 873 874 ret = ERR_TRANSIENT; 875 if (sendcmd("%c%lld %s\n", type, (long long)st.st_size, fname)) { 876 if (errno == 0) 877 ret = ERR_REJECTED; 878 goto fail; 879 } 880 881 lp_setstatus(lp, "sending %s to %s", fname, lp->lp_rm); 882 if (prn_writefile(fp) == -1 || prn_write("\0", 1) == -1) 883 goto fail; 884 if (recvack()) { 885 if (errno == 0) 886 ret = ERR_REJECTED; 887 goto fail; 888 } 889 890 ret = OK; 891 892 fail: 893 (void)fclose(fp); 894 895 if (ret == ERR_REJECTED) 896 log_warnx("%s rejected by remote host", fname); 897 898 return ret; 899 } 900 901 /* 902 * Read a ack response from the server. 903 * Return 0 for ack, 1 or nack, -1 and set errno on error. 904 */ 905 static int 906 recvack(void) 907 { 908 char visbuf[256 * 4 + 1]; 909 unsigned char line[1024]; 910 ssize_t n; 911 912 if ((n = prn_read(line, sizeof(line))) == -1) 913 return -1; 914 915 if (n == 1) { 916 errno = 0; 917 if (line[0]) 918 log_warnx("%s: \\%d", lp->lp_host, line[0]); 919 return line[0] ? 1 : 0; 920 } 921 922 if (n > 256) 923 n = 256; 924 line[n] = '\0'; 925 if (line[n-1] == '\n') 926 line[--n] = '\0'; 927 928 strvisx(visbuf, line, n, VIS_NL | VIS_CSTYLE); 929 log_warnx("%s: %s", lp->lp_host, visbuf); 930 931 errno = 0; 932 return -1; 933 } 934 935 static void 936 mailreport(struct job *job, int result) 937 { 938 struct stat st; 939 FILE *fp = NULL, *efp; 940 const char *user; 941 char *cp; 942 int p[2], c; 943 944 if (job->mail) 945 user = job->mail; 946 else 947 user = job->person; 948 if (user == NULL) { 949 log_warnx("no user to send report to"); 950 return; 951 } 952 953 if (pipe(p) == -1) { 954 log_warn("pipe"); 955 return; 956 } 957 958 switch (fork()) { 959 case -1: 960 (void)close(p[0]); 961 (void)close(p[1]); 962 log_warn("fork"); 963 return; 964 965 case 0: 966 if (dup2(p[0], 0) == -1) 967 fatal("%s: dup2", __func__); 968 (void)closefrom(3); 969 if ((cp = strrchr(_PATH_SENDMAIL, '/'))) 970 cp++; 971 else 972 cp = _PATH_SENDMAIL; 973 execl(_PATH_SENDMAIL, cp, "-t", (char *)NULL); 974 fatal("%s: execl: %s", __func__, _PATH_SENDMAIL); 975 976 default: 977 (void)close(p[0]); 978 if ((fp = fdopen(p[1], "w")) == NULL) { 979 (void)close(p[1]); 980 log_warn("fdopen"); 981 return; 982 } 983 } 984 985 fprintf(fp, "Auto-Submitted: auto-generated\n"); 986 fprintf(fp, "To: %s@%s\n", user, job->host); 987 fprintf(fp, "Subject: %s printer job \"%s\"\n", lp->lp_name, 988 job->name ? job->name : "<unknown>"); 989 fprintf(fp, "Reply-To: root@%s\n\n", lpd_hostname); 990 fprintf(fp, "Your printer job "); 991 if (job->name) 992 fprintf(fp, " (%s) ", job->name); 993 994 fprintf(fp, "\n"); 995 996 switch (result) { 997 case OK: 998 fprintf(fp, "completed successfully"); 999 break; 1000 1001 case ERR_ACCOUNT: 1002 fprintf(fp, "could not be printed without an account on %s", 1003 lpd_hostname); 1004 break; 1005 1006 case ERR_ACCESS: 1007 fprintf(fp, "could not be printed because the file could " 1008 " not be read"); 1009 break; 1010 1011 case ERR_INODE: 1012 fprintf(fp, "was not printed because it was not linked to" 1013 " the original file"); 1014 break; 1015 1016 case ERR_NOIMPL: 1017 fprintf(fp, "was not printed because some feature is missing"); 1018 break; 1019 1020 case ERR_FILTER: 1021 efp = fopen(prn->efile, "r"); 1022 if (efp && fstat(fileno(efp), &st) == 0 && st.st_size) { 1023 fprintf(fp, 1024 "had the following errors and may not have printed:\n"); 1025 while ((c = getc(efp)) != EOF) 1026 putc(c, fp); 1027 } 1028 else 1029 fprintf(fp, 1030 "had some errors and may not have printed\n"); 1031 1032 if (efp) 1033 fclose(efp); 1034 break; 1035 1036 default: 1037 printf("could not be printed"); 1038 break; 1039 } 1040 1041 fprintf(fp, "\n"); 1042 fclose(fp); 1043 1044 wait(NULL); 1045 } 1046 1047 static void 1048 prn_open(void) 1049 { 1050 const char *status, *oldstatus; 1051 int i; 1052 1053 switch (lp->lp_type) { 1054 case PRN_LOCAL: 1055 lp_setstatus(lp, "opening %s", LP_LP(lp)); 1056 break; 1057 1058 case PRN_NET: 1059 case PRN_LPR: 1060 lp_setstatus(lp, "connecting to %s:%s", lp->lp_host, 1061 lp->lp_port ? lp->lp_port : "printer"); 1062 break; 1063 } 1064 1065 status = oldstatus = NULL; 1066 for (i = 0; prn->pfd == -1; i += (i < 6) ? 1 : 0) { 1067 1068 if (status != oldstatus) { 1069 lp_setstatus(lp, "%s", status); 1070 oldstatus = status; 1071 } 1072 1073 if (i) 1074 sleep(1 << i); 1075 1076 if ((prn->pfd = prn_connect()) == -1) { 1077 status = "waiting for printer to come up"; 1078 continue; 1079 } 1080 1081 if (lp->lp_type == PRN_LPR) { 1082 /* Send a recvjob request. */ 1083 if (sendcmd("\2%s\n", LP_RP(lp))) { 1084 if (errno == 0) 1085 log_warnx("remote queue is disabled"); 1086 (void)close(prn->pfd); 1087 prn->pfd = -1; 1088 status = "waiting for queue to be enabled"; 1089 } 1090 } 1091 } 1092 1093 switch (lp->lp_type) { 1094 case PRN_LOCAL: 1095 lp_setstatus(lp, "printing to %s", LP_LP(lp)); 1096 break; 1097 1098 case PRN_NET: 1099 lp_setstatus(lp, "printing to %s:%s", lp->lp_host, lp->lp_port); 1100 break; 1101 1102 case PRN_LPR: 1103 lp_setstatus(lp, "sending to %s", lp->lp_host); 1104 break; 1105 } 1106 1107 prn->tof = lp->lp_fo ? 0 : 1; 1108 prn->count = 0; 1109 1110 prn_fstart(); 1111 } 1112 1113 /* 1114 * Open the printer device, or connect to the remote host. 1115 * Return the printer file desciptor, or -1 on error. 1116 */ 1117 static int 1118 prn_connect(void) 1119 { 1120 struct addrinfo hints, *res, *res0; 1121 int save_errno; 1122 int fd, e, mode; 1123 const char *cause = NULL, *host, *port; 1124 1125 if (lp->lp_type == PRN_LOCAL) { 1126 mode = lp->lp_rw ? O_RDWR : O_WRONLY; 1127 if ((fd = open(LP_LP(lp), mode)) == -1) { 1128 log_warn("failed to open %s", LP_LP(lp)); 1129 return -1; 1130 } 1131 1132 if (isatty(fd)) { 1133 lp_stty(lp, fd); 1134 return -1; 1135 } 1136 1137 return fd; 1138 } 1139 1140 host = lp->lp_host; 1141 port = lp->lp_port ? lp->lp_port : "printer"; 1142 1143 memset(&hints, 0, sizeof(hints)); 1144 hints.ai_family = AF_UNSPEC; 1145 hints.ai_socktype = SOCK_STREAM; 1146 if ((e = getaddrinfo(host, port, &hints, &res0))) { 1147 log_warnx("%s:%s: %s", host, port, gai_strerror(e)); 1148 return -1; 1149 } 1150 1151 fd = -1; 1152 for (res = res0; res && fd == -1; res = res->ai_next) { 1153 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 1154 if (fd == -1) 1155 cause = "socket"; 1156 else if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { 1157 cause = "connect"; 1158 save_errno = errno; 1159 (void)close(fd); 1160 errno = save_errno; 1161 fd = -1; 1162 } 1163 } 1164 1165 if (fd == -1) 1166 log_warn("%s", cause); 1167 else 1168 log_debug("connected to %s:%s", host, port); 1169 1170 freeaddrinfo(res0); 1171 return fd; 1172 } 1173 1174 static void 1175 prn_close(void) 1176 { 1177 prn_fclose(); 1178 1179 (void)close(prn->pfd); 1180 prn->pfd = -1; 1181 } 1182 1183 /* 1184 * Fork the output filter process if needed. 1185 */ 1186 static int 1187 prn_fstart(void) 1188 { 1189 char width[32], length[32], *cp; 1190 int fildes[2], i; 1191 1192 if (lp->lp_type == PRN_LPR || (!lp->lp_of)) 1193 return 0; 1194 1195 pipe(fildes); 1196 1197 for (i = 0; i < 20; i++) { 1198 if (i) 1199 sleep(i); 1200 if ((prn->opid = fork()) != -1) 1201 break; 1202 log_warn("%s: fork", __func__); 1203 } 1204 1205 if (prn->opid == -1) { 1206 log_warnx("cannot fork output filter"); 1207 return -1; 1208 } 1209 1210 if (prn->opid == 0) { 1211 /* child */ 1212 dup2(fildes[0], 0); 1213 dup2(prn->pfd, 1); 1214 (void)closefrom(3); 1215 cp = strrchr(lp->lp_of, '/'); 1216 if (cp) 1217 cp += 1; 1218 else 1219 cp = lp->lp_of; 1220 snprintf(width, sizeof(width), "-w%ld", lp->lp_pw); 1221 snprintf(length, sizeof(length), "-l%ld", lp->lp_pl); 1222 execl(lp->lp_of, cp, width, length, (char *)NULL); 1223 log_warn("%s: execl", __func__); 1224 exit(1); 1225 } 1226 1227 close(fildes[0]); 1228 prn->ofd = fildes[1]; 1229 prn->ofilter = 1; 1230 1231 return 0; 1232 } 1233 1234 /* 1235 * Suspend the output filter process. 1236 */ 1237 static void 1238 prn_fsuspend(void) 1239 { 1240 pid_t pid; 1241 int status; 1242 1243 if (prn->opid == 0) 1244 return; 1245 1246 prn_puts("\031\1"); 1247 while ((pid = waitpid(WAIT_ANY, &status, WUNTRACED)) && pid != prn->opid) 1248 ; 1249 1250 prn->ofilter = 0; 1251 if (!WIFSTOPPED(status)) { 1252 log_warn("output filter died (exitstatus=%d termsig=%d)", 1253 WEXITSTATUS(status), WTERMSIG(status)); 1254 prn->opid = 0; 1255 prn_fclose(); 1256 } 1257 } 1258 1259 /* 1260 * Resume the output filter process. 1261 */ 1262 static void 1263 prn_fresume(void) 1264 { 1265 if (prn->opid == 0) 1266 return; 1267 1268 if (kill(prn->opid, SIGCONT) == -1) 1269 fatal("cannot restart output filter"); 1270 prn->ofilter = 1; 1271 } 1272 1273 /* 1274 * Close the output filter socket and wait for the process to terminate 1275 * if currently running. 1276 */ 1277 static void 1278 prn_fclose(void) 1279 { 1280 pid_t pid; 1281 1282 close(prn->ofd); 1283 prn->ofd = -1; 1284 1285 while (prn->opid) { 1286 pid = wait(NULL); 1287 if (pid == -1) 1288 log_warn("%s: wait", __func__); 1289 else if (pid == prn->opid) 1290 prn->opid = 0; 1291 } 1292 } 1293 1294 /* 1295 * Write a form-feed if the printer cap requires it, and if not currently 1296 * at top of form. Return 0 on success, or -1 on error and set errno. 1297 */ 1298 static int 1299 prn_formfeed(void) 1300 { 1301 if (!lp->lp_sf && !prn->tof) 1302 if (prn_puts(LP_FF(lp)) == -1) 1303 return -1; 1304 prn->tof = 1; 1305 return 0; 1306 } 1307 1308 /* 1309 * Write data to the printer (or output filter process). 1310 * Return 0 on success, or -1 and set errno. 1311 */ 1312 static int 1313 prn_write(const char *buf, size_t len) 1314 { 1315 ssize_t n; 1316 int fd; 1317 1318 fd = prn->ofilter ? prn->ofd : prn->pfd; 1319 1320 log_debug("prn_write(fd=%d len=%zu, of=%d pfd=%d ofd=%d)", fd, len, 1321 prn->ofilter, prn->pfd, prn->ofd); 1322 1323 if (fd == -1) { 1324 log_warnx("printer socket not opened"); 1325 errno = EPIPE; 1326 return -1; 1327 } 1328 1329 while (len) { 1330 if ((n = write(fd, buf, len)) == -1) { 1331 if (errno == EINTR) 1332 continue; 1333 log_warn("%s: write", __func__); 1334 /* XXX close the printer */ 1335 return -1; 1336 } 1337 len -= n; 1338 buf += n; 1339 prn->tof = 0; 1340 } 1341 1342 return 0; 1343 } 1344 1345 /* 1346 * Write a string to the printer (or output filter process). 1347 * Return 0 on success, or -1 and set errno. 1348 */ 1349 static int 1350 prn_puts(const char *buf) 1351 { 1352 return prn_write(buf, strlen(buf)); 1353 } 1354 1355 /* 1356 * Write the FILE content to the printer (or output filter process). 1357 * Return 0 on success, or -1 and set errno. 1358 */ 1359 static int 1360 prn_writefile(FILE *fp) 1361 { 1362 char buf[BUFSIZ]; 1363 size_t r; 1364 1365 while (!feof(fp)) { 1366 r = fread(buf, 1, sizeof(buf), fp); 1367 if (ferror(fp)) { 1368 log_warn("%s: fread", __func__); 1369 return -1; 1370 } 1371 if (r && (prn_write(buf, r) == -1)) 1372 return -1; 1373 } 1374 1375 return 0; 1376 } 1377 1378 /* 1379 * Read data from the printer socket into the given buffer. 1380 * Return 0 on success, or -1 and set errno. 1381 */ 1382 static ssize_t 1383 prn_read(char *buf, size_t sz) 1384 { 1385 ssize_t n; 1386 1387 for (;;) { 1388 if ((n = read(prn->pfd, buf, sz)) == 0) { 1389 errno = ECONNRESET; 1390 n = -1; 1391 } 1392 if (n == -1) { 1393 if (errno == EINTR) 1394 continue; 1395 /* XXX close printer? */ 1396 log_warn("%s: read", __func__); 1397 return -1; 1398 } 1399 return n; 1400 } 1401 } 1402