xref: /openbsd/usr.sbin/lpd/printer.c (revision 5a38ef86)
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