1 /*
2 * Copyright (c) 1983, 1993
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. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
31 * @(#)printjob.c 8.7 (Berkeley) 5/10/95
32 * $FreeBSD: src/usr.sbin/lpr/lpd/printjob.c,v 1.22.2.32 2002/06/19 23:58:16 gad Exp $
33 */
34
35 /*
36 * printjob -- print jobs in the queue.
37 *
38 * NOTE: the lock file is used to pass information to lpq and lprm.
39 * it does not need to be removed because file locks are dynamic.
40 */
41
42 #include <sys/param.h>
43 #include <sys/wait.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46
47 #include <pwd.h>
48 #include <unistd.h>
49 #include <signal.h>
50 #include <syslog.h>
51 #include <fcntl.h>
52 #include <dirent.h>
53 #include <errno.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <sys/ioctl.h>
58 #include <termios.h>
59 #include <time.h>
60 #include "lp.h"
61 #include "lp.local.h"
62 #include "pathnames.h"
63 #include "extern.h"
64
65 #define DORETURN 0 /* dofork should return "can't fork" error */
66 #define DOABORT 1 /* dofork should just die if fork() fails */
67
68 /*
69 * Error tokens
70 */
71 #define REPRINT -2
72 #define ERROR -1
73 #define OK 0
74 #define FATALERR 1
75 #define NOACCT 2
76 #define FILTERERR 3
77 #define ACCESS 4
78
79 static dev_t fdev; /* device of file pointed to by symlink */
80 static ino_t fino; /* inode of file pointed to by symlink */
81 static FILE *cfp; /* control file */
82 static pid_t of_pid; /* process id of output filter, if any */
83 static int child; /* id of any filters */
84 static int job_dfcnt; /* count of datafiles in current user job */
85 static int lfd; /* lock file descriptor */
86 static int ofd; /* output filter file descriptor */
87 static int tfd = -1; /* output filter temp file output */
88 static int pfd; /* prstatic inter file descriptor */
89 static int prchild; /* id of pr process */
90 static char title[80]; /* ``pr'' title */
91 static char locale[80]; /* ``pr'' locale */
92
93 /* these two are set from pp->daemon_user, but only if they are needed */
94 static char *daemon_uname; /* set from pwd->pw_name */
95 static int daemon_defgid;
96
97 static char class[32]; /* classification field */
98 static char origin_host[MAXHOSTNAMELEN]; /* user's host machine */
99 /* indentation size in static characters */
100 static char indent[10] = "-i0";
101 static char jobname[100]; /* job or file name */
102 static char length[10] = "-l"; /* page length in lines */
103 static char logname[32]; /* user's login name */
104 static char pxlength[10] = "-y"; /* page length in pixels */
105 static char pxwidth[10] = "-x"; /* page width in pixels */
106 /* tempstderr is the filename used to catch stderr from exec-ing filters */
107 static char tempstderr[] = "errs.XXXXXXX";
108 static char width[10] = "-w"; /* page width in static characters */
109 #define TFILENAME "fltXXXXXX"
110 static char tfile[] = TFILENAME; /* file name for filter output */
111
112 static void abortpr(int _signo);
113 static void alarmhandler(int _signo);
114 static void banner(struct printer *_pp, char *_name1, char *_name2);
115 static int dofork(const struct printer *_pp, int _action);
116 static int dropit(int _c);
117 static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av,
118 int _infd, int _outfd);
119 static void init(struct printer *_pp);
120 static void openpr(const struct printer *_pp);
121 static void opennet(const struct printer *_pp);
122 static void opentty(const struct printer *_pp);
123 static void openrem(const struct printer *pp);
124 static int print(struct printer *_pp, int _format, char *_file);
125 static int printit(struct printer *_pp, char *_file);
126 static void pstatus(const struct printer *_pp, const char *_msg, ...)
127 __printflike(2, 3);
128 static char response(const struct printer *_pp);
129 static void scan_out(struct printer *_pp, int _scfd, char *_scsp,
130 int _dlm);
131 static char *scnline(int _key, char *_p, int _c);
132 static int sendfile(struct printer *_pp, int _type, char *_file,
133 char _format, int _copyreq);
134 static int sendit(struct printer *_pp, char *_file);
135 static void sendmail(struct printer *_pp, char *_userid, int _bombed);
136 static void setty(const struct printer *_pp);
137
138 void
printjob(struct printer * pp)139 printjob(struct printer *pp)
140 {
141 struct stat stb;
142 struct jobqueue *q, **qp;
143 struct jobqueue **queue;
144 int i, nitems;
145 off_t pidoff;
146 pid_t printpid;
147 int errcnt, jobcount, tempfd;
148
149 jobcount = 0;
150 init(pp); /* set up capabilities */
151 write(1, "", 1); /* ack that daemon is started */
152 close(2); /* set up log file */
153 if (open(pp->log_file, O_WRONLY|O_APPEND, LOG_FILE_MODE) < 0) {
154 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
155 pp->log_file);
156 open(_PATH_DEVNULL, O_WRONLY);
157 }
158 setgid(getegid());
159 printpid = getpid(); /* for use with lprm */
160 setpgrp(0, printpid);
161
162 /*
163 * At initial lpd startup, printjob may be called with various
164 * signal handlers in effect. After that initial startup, any
165 * calls to printjob will have a *different* set of signal-handlers
166 * in effect. Make sure all handlers are the ones we want.
167 */
168 signal(SIGCHLD, SIG_DFL);
169 signal(SIGHUP, abortpr);
170 signal(SIGINT, abortpr);
171 signal(SIGQUIT, abortpr);
172 signal(SIGTERM, abortpr);
173
174 /*
175 * uses short form file names
176 */
177 if (chdir(pp->spool_dir) < 0) {
178 syslog(LOG_ERR, "%s: chdir(%s): %m", pp->printer,
179 pp->spool_dir);
180 exit(1);
181 }
182 if (stat(pp->lock_file, &stb) == 0 && (stb.st_mode & LFM_PRINT_DIS))
183 exit(0); /* printing disabled */
184 lfd = open(pp->lock_file, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
185 LOCK_FILE_MODE);
186 if (lfd < 0) {
187 if (errno == EWOULDBLOCK) /* active daemon present */
188 exit(0);
189 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
190 pp->lock_file);
191 exit(1);
192 }
193 /* turn off non-blocking mode (was turned on for lock effects only) */
194 if (fcntl(lfd, F_SETFL, 0) < 0) {
195 syslog(LOG_ERR, "%s: fcntl(%s): %m", pp->printer,
196 pp->lock_file);
197 exit(1);
198 }
199 ftruncate(lfd, 0);
200 /*
201 * write process id for others to know
202 */
203 sprintf(line, "%u\n", printpid);
204 pidoff = i = strlen(line);
205 if (write(lfd, line, i) != i) {
206 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
207 pp->lock_file);
208 exit(1);
209 }
210 /*
211 * search the spool directory for work and sort by queue order.
212 */
213 if ((nitems = getq(pp, &queue)) < 0) {
214 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
215 pp->spool_dir);
216 exit(1);
217 }
218 if (nitems == 0) /* no work to do */
219 exit(0);
220 if (stb.st_mode & LFM_RESET_QUE) { /* reset queue flag */
221 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE) < 0)
222 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
223 pp->lock_file);
224 }
225
226 /* create a file which will be used to hold stderr from filters */
227 if ((tempfd = mkstemp(tempstderr)) == -1) {
228 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
229 tempstderr);
230 exit(1);
231 }
232 if ((i = fchmod(tempfd, 0664)) == -1) {
233 syslog(LOG_ERR, "%s: fchmod(%s): %m", pp->printer,
234 tempstderr);
235 exit(1);
236 }
237 /* lpd doesn't need it to be open, it just needs it to exist */
238 close(tempfd);
239
240 openpr(pp); /* open printer or remote */
241 again:
242 /*
243 * we found something to do now do it --
244 * write the name of the current control file into the lock file
245 * so the spool queue program can tell what we're working on
246 */
247 for (qp = queue; nitems--; free((char *) q)) {
248 q = *qp++;
249 if (stat(q->job_cfname, &stb) < 0)
250 continue;
251 errcnt = 0;
252 restart:
253 lseek(lfd, pidoff, 0);
254 snprintf(line, sizeof(line), "%s\n", q->job_cfname);
255 i = strlen(line);
256 if (write(lfd, line, i) != i)
257 syslog(LOG_ERR, "%s: write(%s): %m", pp->printer,
258 pp->lock_file);
259 if (!pp->remote)
260 i = printit(pp, q->job_cfname);
261 else
262 i = sendit(pp, q->job_cfname);
263 /*
264 * Check to see if we are supposed to stop printing or
265 * if we are to rebuild the queue.
266 */
267 if (fstat(lfd, &stb) == 0) {
268 /* stop printing before starting next job? */
269 if (stb.st_mode & LFM_PRINT_DIS)
270 goto done;
271 /* rebuild queue (after lpc topq) */
272 if (stb.st_mode & LFM_RESET_QUE) {
273 for (free(q); nitems--; free(q))
274 q = *qp++;
275 if (fchmod(lfd, stb.st_mode & ~LFM_RESET_QUE)
276 < 0)
277 syslog(LOG_WARNING,
278 "%s: fchmod(%s): %m",
279 pp->printer, pp->lock_file);
280 break;
281 }
282 }
283 if (i == OK) /* all files of this job printed */
284 jobcount++;
285 else if (i == REPRINT && ++errcnt < 5) {
286 /* try reprinting the job */
287 syslog(LOG_INFO, "restarting %s", pp->printer);
288 if (of_pid > 0) {
289 kill(of_pid, SIGCONT); /* to be sure */
290 close(ofd);
291 while ((i = wait(NULL)) > 0 && i != of_pid)
292 ;
293 if (i < 0)
294 syslog(LOG_WARNING, "%s: after kill(of=%d), wait() returned: %m",
295 pp->printer, of_pid);
296 of_pid = 0;
297 }
298 close(pfd); /* close printer */
299 if (ftruncate(lfd, pidoff) < 0)
300 syslog(LOG_WARNING, "%s: ftruncate(%s): %m",
301 pp->printer, pp->lock_file);
302 openpr(pp); /* try to reopen printer */
303 goto restart;
304 } else {
305 syslog(LOG_WARNING, "%s: job could not be %s (%s)",
306 pp->printer,
307 pp->remote ? "sent to remote host" : "printed",
308 q->job_cfname);
309 if (i == REPRINT) {
310 /* ensure we don't attempt this job again */
311 unlink(q->job_cfname);
312 q->job_cfname[0] = 'd';
313 unlink(q->job_cfname);
314 if (logname[0])
315 sendmail(pp, logname, FATALERR);
316 }
317 }
318 }
319 free(queue);
320 /*
321 * search the spool directory for more work.
322 */
323 if ((nitems = getq(pp, &queue)) < 0) {
324 syslog(LOG_ERR, "%s: can't scan %s", pp->printer,
325 pp->spool_dir);
326 exit(1);
327 }
328 if (nitems == 0) { /* no more work to do */
329 done:
330 if (jobcount > 0) { /* jobs actually printed */
331 if (!pp->no_formfeed && !pp->tof)
332 write(ofd, pp->form_feed,
333 strlen(pp->form_feed));
334 if (pp->trailer != NULL) /* output trailer */
335 write(ofd, pp->trailer, strlen(pp->trailer));
336 }
337 close(ofd);
338 wait(NULL);
339 unlink(tempstderr);
340 exit(0);
341 }
342 goto again;
343 }
344
345 char fonts[4][50]; /* fonts for troff */
346
347 char ifonts[4][40] = {
348 _PATH_VFONTR,
349 _PATH_VFONTI,
350 _PATH_VFONTB,
351 _PATH_VFONTS,
352 };
353
354 /*
355 * The remaining part is the reading of the control file (cf)
356 * and performing the various actions.
357 */
358 static int
printit(struct printer * pp,char * file)359 printit(struct printer *pp, char *file)
360 {
361 int i;
362 char *cp;
363 int bombed, didignorehdr;
364
365 bombed = OK;
366 didignorehdr = 0;
367 /*
368 * open control file; ignore if no longer there.
369 */
370 if ((cfp = fopen(file, "r")) == NULL) {
371 syslog(LOG_INFO, "%s: fopen(%s): %m", pp->printer, file);
372 return (OK);
373 }
374 /*
375 * Reset troff fonts.
376 */
377 for (i = 0; i < 4; i++)
378 strcpy(fonts[i], ifonts[i]);
379 sprintf(&width[2], "%ld", pp->page_width);
380 strcpy(indent+2, "0");
381
382 /* initialize job-specific count of datafiles processed */
383 job_dfcnt = 0;
384
385 /*
386 * read the control file for work to do
387 *
388 * file format -- first character in the line is a command
389 * rest of the line is the argument.
390 * valid commands are:
391 *
392 * S -- "stat info" for symbolic link protection
393 * J -- "job name" on banner page
394 * C -- "class name" on banner page
395 * L -- "literal" user's name to print on banner
396 * T -- "title" for pr
397 * H -- "host name" of machine where lpr was done
398 * P -- "person" user's login name
399 * I -- "indent" amount to indent output
400 * R -- laser dpi "resolution"
401 * f -- "file name" name of text file to print
402 * l -- "file name" text file with control chars
403 * o -- "file name" postscript file, according to
404 * the RFC. Here it is treated like an 'f'.
405 * p -- "file name" text file to print with pr(1)
406 * t -- "file name" troff(1) file to print
407 * n -- "file name" ditroff(1) file to print
408 * d -- "file name" dvi file to print
409 * g -- "file name" plot(1G) file to print
410 * v -- "file name" plain raster file to print
411 * c -- "file name" cifplot file to print
412 * 1 -- "R font file" for troff
413 * 2 -- "I font file" for troff
414 * 3 -- "B font file" for troff
415 * 4 -- "S font file" for troff
416 * N -- "name" of file (used by lpq)
417 * U -- "unlink" name of file to remove
418 * (after we print it. (Pass 2 only)).
419 * M -- "mail" to user when done printing
420 * Z -- "locale" for pr
421 *
422 * get_line reads a line and expands tabs to blanks
423 */
424
425 /* pass 1 */
426
427 while (get_line(cfp))
428 switch (line[0]) {
429 case 'H':
430 strlcpy(origin_host, line + 1, sizeof(origin_host));
431 if (class[0] == '\0') {
432 strlcpy(class, line+1, sizeof(class));
433 }
434 continue;
435
436 case 'P':
437 strlcpy(logname, line + 1, sizeof(logname));
438 if (pp->restricted) { /* restricted */
439 if (getpwnam(logname) == NULL) {
440 bombed = NOACCT;
441 sendmail(pp, line+1, bombed);
442 goto pass2;
443 }
444 }
445 continue;
446
447 case 'S':
448 cp = line+1;
449 i = 0;
450 while (*cp >= '0' && *cp <= '9')
451 i = i * 10 + (*cp++ - '0');
452 fdev = i;
453 cp++;
454 i = 0;
455 while (*cp >= '0' && *cp <= '9')
456 i = i * 10 + (*cp++ - '0');
457 fino = i;
458 continue;
459
460 case 'J':
461 if (line[1] != '\0') {
462 strlcpy(jobname, line + 1, sizeof(jobname));
463 } else
464 strcpy(jobname, " ");
465 continue;
466
467 case 'C':
468 if (line[1] != '\0')
469 strlcpy(class, line + 1, sizeof(class));
470 else if (class[0] == '\0') {
471 /* XXX - why call gethostname instead of
472 * just strlcpy'ing local_host? */
473 gethostname(class, sizeof(class));
474 class[sizeof(class) - 1] = '\0';
475 }
476 continue;
477
478 case 'T': /* header title for pr */
479 strlcpy(title, line + 1, sizeof(title));
480 continue;
481
482 case 'L': /* identification line */
483 if (!pp->no_header && !pp->header_last)
484 banner(pp, line+1, jobname);
485 continue;
486
487 case '1': /* troff fonts */
488 case '2':
489 case '3':
490 case '4':
491 if (line[1] != '\0') {
492 strlcpy(fonts[line[0]-'1'], line + 1,
493 (size_t)50);
494 }
495 continue;
496
497 case 'W': /* page width */
498 strlcpy(width+2, line + 1, sizeof(width) - 2);
499 continue;
500
501 case 'I': /* indent amount */
502 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
503 continue;
504
505 case 'Z': /* locale for pr */
506 strlcpy(locale, line + 1, sizeof(locale));
507 continue;
508
509 default: /* some file to print */
510 /* only lowercase cmd-codes include a file-to-print */
511 if ((line[0] < 'a') || (line[0] > 'z')) {
512 /* ignore any other lines */
513 if (lflag <= 1)
514 continue;
515 if (!didignorehdr) {
516 syslog(LOG_INFO, "%s: in %s :",
517 pp->printer, file);
518 didignorehdr = 1;
519 }
520 syslog(LOG_INFO, "%s: ignoring line: '%c' %s",
521 pp->printer, line[0], &line[1]);
522 continue;
523 }
524 i = print(pp, line[0], line+1);
525 switch (i) {
526 case ERROR:
527 if (bombed == OK)
528 bombed = FATALERR;
529 break;
530 case REPRINT:
531 fclose(cfp);
532 return (REPRINT);
533 case FILTERERR:
534 case ACCESS:
535 bombed = i;
536 sendmail(pp, logname, bombed);
537 }
538 title[0] = '\0';
539 continue;
540
541 case 'N':
542 case 'U':
543 case 'M':
544 case 'R':
545 continue;
546 }
547
548 /* pass 2 */
549
550 pass2:
551 fseek(cfp, 0L, 0);
552 while (get_line(cfp))
553 switch (line[0]) {
554 case 'L': /* identification line */
555 if (!pp->no_header && pp->header_last)
556 banner(pp, line+1, jobname);
557 continue;
558
559 case 'M':
560 if (bombed < NOACCT) /* already sent if >= NOACCT */
561 sendmail(pp, line+1, bombed);
562 continue;
563
564 case 'U':
565 if (strchr(line+1, '/'))
566 continue;
567 unlink(line+1);
568 }
569 /*
570 * clean-up in case another control file exists
571 */
572 fclose(cfp);
573 unlink(file);
574 return (bombed == OK ? OK : ERROR);
575 }
576
577 /*
578 * Print a file.
579 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
580 * Return -1 if a non-recoverable error occured,
581 * 2 if the filter detected some errors (but printed the job anyway),
582 * 1 if we should try to reprint this job and
583 * 0 if all is well.
584 * Note: all filters take stdin as the file, stdout as the printer,
585 * stderr as the log file, and must not ignore SIGINT.
586 */
587 static int
print(struct printer * pp,int format,char * file)588 print(struct printer *pp, int format, char *file)
589 {
590 int n, i;
591 char *prog;
592 int fi, fo;
593 FILE *fp;
594 char *av[15], buf[BUFSIZ];
595 pid_t wpid;
596 int p[2], retcode, stopped, wstatus, wstatus_set;
597 struct stat stb;
598
599 if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) {
600 syslog(LOG_INFO, "%s: unable to open %s ('%c' line)",
601 pp->printer, file, format);
602 return (ERROR);
603 }
604 /*
605 * Check to see if data file is a symbolic link. If so, it should
606 * still point to the same file or someone is trying to print
607 * something he shouldn't.
608 */
609 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(fi, &stb) == 0 &&
610 (stb.st_dev != fdev || stb.st_ino != fino))
611 return (ACCESS);
612
613 job_dfcnt++; /* increment datafile counter for this job */
614 stopped = 0; /* output filter is not stopped */
615
616 /* everything seems OK, start it up */
617 if (!pp->no_formfeed && !pp->tof) { /* start on a fresh page */
618 write(ofd, pp->form_feed, strlen(pp->form_feed));
619 pp->tof = 1;
620 }
621 if (pp->filters[LPF_INPUT] == NULL
622 && (format == 'f' || format == 'l' || format == 'o')) {
623 pp->tof = 0;
624 while ((n = read(fi, buf, BUFSIZ)) > 0)
625 if (write(ofd, buf, n) != n) {
626 close(fi);
627 return (REPRINT);
628 }
629 close(fi);
630 return (OK);
631 }
632 switch (format) {
633 case 'p': /* print file using 'pr' */
634 if (pp->filters[LPF_INPUT] == NULL) { /* use output filter */
635 prog = _PATH_PR;
636 i = 0;
637 av[i++] = "pr";
638 av[i++] = width;
639 av[i++] = length;
640 av[i++] = "-h";
641 av[i++] = *title ? title : " ";
642 av[i++] = "-L";
643 av[i++] = *locale ? locale : "C";
644 av[i++] = "-F";
645 av[i] = NULL;
646 fo = ofd;
647 goto start;
648 }
649 pipe(p);
650 if ((prchild = dofork(pp, DORETURN)) == 0) { /* child */
651 dup2(fi, 0); /* file is stdin */
652 dup2(p[1], 1); /* pipe is stdout */
653 closelog();
654 closeallfds(3);
655 execl(_PATH_PR, "pr", width, length,
656 "-h", *title ? title : " ",
657 "-L", *locale ? locale : "C",
658 "-F", NULL);
659 syslog(LOG_ERR, "cannot execl %s", _PATH_PR);
660 exit(2);
661 }
662 close(p[1]); /* close output side */
663 close(fi);
664 if (prchild < 0) {
665 prchild = 0;
666 close(p[0]);
667 return (ERROR);
668 }
669 fi = p[0]; /* use pipe for input */
670 case 'f': /* print plain text file */
671 prog = pp->filters[LPF_INPUT];
672 av[1] = width;
673 av[2] = length;
674 av[3] = indent;
675 n = 4;
676 break;
677 case 'o': /* print postscript file */
678 /*
679 * Treat this as a "plain file with control characters", and
680 * assume the standard LPF_INPUT filter will recognize that
681 * the data is postscript and know what to do with it. These
682 * 'o'-file requests could come from MacOS 10.1 systems.
683 * (later versions of MacOS 10 will explicitly use 'l')
684 * A postscript file can contain binary data, which is why 'l'
685 * is somewhat more appropriate than 'f'.
686 */
687 /* FALLTHROUGH */
688 case 'l': /* like 'f' but pass control characters */
689 prog = pp->filters[LPF_INPUT];
690 av[1] = "-c";
691 av[2] = width;
692 av[3] = length;
693 av[4] = indent;
694 n = 5;
695 break;
696 case 'r': /* print a fortran text file */
697 prog = pp->filters[LPF_FORTRAN];
698 av[1] = width;
699 av[2] = length;
700 n = 3;
701 break;
702 case 't': /* print troff output */
703 case 'n': /* print ditroff output */
704 case 'd': /* print tex output */
705 unlink(".railmag");
706 if ((fo = creat(".railmag", FILMOD)) < 0) {
707 syslog(LOG_ERR, "%s: cannot create .railmag",
708 pp->printer);
709 unlink(".railmag");
710 } else {
711 for (n = 0; n < 4; n++) {
712 if (fonts[n][0] != '/')
713 write(fo, _PATH_VFONT,
714 sizeof(_PATH_VFONT) - 1);
715 write(fo, fonts[n], strlen(fonts[n]));
716 write(fo, "\n", 1);
717 }
718 close(fo);
719 }
720 prog = (format == 't') ? pp->filters[LPF_TROFF]
721 : ((format == 'n') ? pp->filters[LPF_DITROFF]
722 : pp->filters[LPF_DVI]);
723 av[1] = pxwidth;
724 av[2] = pxlength;
725 n = 3;
726 break;
727 case 'c': /* print cifplot output */
728 prog = pp->filters[LPF_CIFPLOT];
729 av[1] = pxwidth;
730 av[2] = pxlength;
731 n = 3;
732 break;
733 case 'g': /* print plot(1G) output */
734 prog = pp->filters[LPF_GRAPH];
735 av[1] = pxwidth;
736 av[2] = pxlength;
737 n = 3;
738 break;
739 case 'v': /* print raster output */
740 prog = pp->filters[LPF_RASTER];
741 av[1] = pxwidth;
742 av[2] = pxlength;
743 n = 3;
744 break;
745 default:
746 close(fi);
747 syslog(LOG_ERR, "%s: illegal format character '%c'",
748 pp->printer, format);
749 return (ERROR);
750 }
751 if (prog == NULL) {
752 close(fi);
753 syslog(LOG_ERR,
754 "%s: no filter found in printcap for format character '%c'",
755 pp->printer, format);
756 return (ERROR);
757 }
758 if ((av[0] = strrchr(prog, '/')) != NULL)
759 av[0]++;
760 else
761 av[0] = prog;
762 av[n++] = "-n";
763 av[n++] = logname;
764 av[n++] = "-h";
765 av[n++] = origin_host;
766 av[n++] = pp->acct_file;
767 av[n] = NULL;
768 fo = pfd;
769 if (of_pid > 0) { /* stop output filter */
770 write(ofd, "\031\1", 2);
771 while ((wpid =
772 wait3(&wstatus, WUNTRACED, 0)) > 0 && wpid != of_pid)
773 ;
774 if (wpid < 0)
775 syslog(LOG_WARNING,
776 "%s: after stopping 'of', wait3() returned: %m",
777 pp->printer);
778 else if (!WIFSTOPPED(wstatus)) {
779 close(fi);
780 syslog(LOG_WARNING, "%s: output filter died "
781 "(pid=%d retcode=%d termsig=%d)",
782 pp->printer, of_pid, WEXITSTATUS(wstatus),
783 WTERMSIG(wstatus));
784 return (REPRINT);
785 }
786 stopped++;
787 }
788 start:
789 if ((child = dofork(pp, DORETURN)) == 0) { /* child */
790 dup2(fi, 0);
791 dup2(fo, 1);
792 /* setup stderr for the filter (child process)
793 * so it goes to our temporary errors file */
794 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
795 if (n >= 0)
796 dup2(n, 2);
797 closelog();
798 closeallfds(3);
799 execv(prog, av);
800 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer,
801 prog);
802 exit(2);
803 }
804 close(fi);
805 wstatus_set = 0;
806 if (child < 0)
807 retcode = 100;
808 else {
809 while ((wpid = wait(&wstatus)) > 0 && wpid != child)
810 ;
811 if (wpid < 0) {
812 retcode = 100;
813 syslog(LOG_WARNING,
814 "%s: after execv(%s), wait() returned: %m",
815 pp->printer, prog);
816 } else {
817 wstatus_set = 1;
818 retcode = WEXITSTATUS(wstatus);
819 }
820 }
821 child = 0;
822 prchild = 0;
823 if (stopped) { /* restart output filter */
824 if (kill(of_pid, SIGCONT) < 0) {
825 syslog(LOG_ERR, "cannot restart output filter");
826 exit(1);
827 }
828 }
829 pp->tof = 0;
830
831 /* Copy the filter's output to "lf" logfile */
832 if ((fp = fopen(tempstderr, "r"))) {
833 while (fgets(buf, sizeof(buf), fp))
834 fputs(buf, stderr);
835 fclose(fp);
836 }
837
838 if (wstatus_set && !WIFEXITED(wstatus)) {
839 syslog(LOG_WARNING, "%s: filter '%c' terminated (termsig=%d)",
840 pp->printer, format, WTERMSIG(wstatus));
841 return (ERROR);
842 }
843 switch (retcode) {
844 case 0:
845 pp->tof = 1;
846 return (OK);
847 case 1:
848 return (REPRINT);
849 case 2:
850 return (ERROR);
851 default:
852 syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)",
853 pp->printer, format, retcode);
854 return (FILTERERR);
855 }
856 }
857
858 /*
859 * Send the daemon control file (cf) and any data files.
860 * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
861 * 0 if all is well.
862 */
863 static int
sendit(struct printer * pp,char * file)864 sendit(struct printer *pp, char *file)
865 {
866 int dfcopies, err, i;
867 char *cp, last[BUFSIZ];
868
869 /*
870 * open control file
871 */
872 if ((cfp = fopen(file, "r")) == NULL)
873 return (OK);
874
875 /* initialize job-specific count of datafiles processed */
876 job_dfcnt = 0;
877
878 /*
879 * read the control file for work to do
880 *
881 * file format -- first character in the line is a command
882 * rest of the line is the argument.
883 * commands of interest are:
884 *
885 * a-z -- "file name" name of file to print
886 * U -- "unlink" name of file to remove
887 * (after we print it. (Pass 2 only)).
888 */
889
890 /*
891 * pass 1
892 */
893 err = OK;
894 while (get_line(cfp)) {
895 again:
896 if (line[0] == 'S') {
897 cp = line+1;
898 i = 0;
899 while (*cp >= '0' && *cp <= '9')
900 i = i * 10 + (*cp++ - '0');
901 fdev = i;
902 cp++;
903 i = 0;
904 while (*cp >= '0' && *cp <= '9')
905 i = i * 10 + (*cp++ - '0');
906 fino = i;
907 } else if (line[0] == 'H') {
908 strlcpy(origin_host, line + 1, sizeof(origin_host));
909 if (class[0] == '\0') {
910 strlcpy(class, line + 1, sizeof(class));
911 }
912 } else if (line[0] == 'P') {
913 strlcpy(logname, line + 1, sizeof(logname));
914 if (pp->restricted) { /* restricted */
915 if (getpwnam(logname) == NULL) {
916 sendmail(pp, line+1, NOACCT);
917 err = ERROR;
918 break;
919 }
920 }
921 } else if (line[0] == 'I') {
922 strlcpy(indent+2, line + 1, sizeof(indent) - 2);
923 } else if (line[0] >= 'a' && line[0] <= 'z') {
924 dfcopies = 1;
925 strcpy(last, line);
926 while ((i = get_line(cfp)) != 0) {
927 if (strcmp(last, line) != 0)
928 break;
929 dfcopies++;
930 }
931 switch (sendfile(pp, '\3', last+1, *last, dfcopies)) {
932 case OK:
933 if (i)
934 goto again;
935 break;
936 case REPRINT:
937 fclose(cfp);
938 return (REPRINT);
939 case ACCESS:
940 sendmail(pp, logname, ACCESS);
941 case ERROR:
942 err = ERROR;
943 }
944 break;
945 }
946 }
947 if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) {
948 fclose(cfp);
949 return (REPRINT);
950 }
951 /*
952 * pass 2
953 */
954 fseek(cfp, 0L, 0);
955 while (get_line(cfp))
956 if (line[0] == 'U' && !strchr(line+1, '/'))
957 unlink(line+1);
958 /*
959 * clean-up in case another control file exists
960 */
961 fclose(cfp);
962 unlink(file);
963 return (err);
964 }
965
966 /*
967 * Send a data file to the remote machine and spool it.
968 * Return positive if we should try resending.
969 */
970 static int
sendfile(struct printer * pp,int type,char * file,char format,int copyreq)971 sendfile(struct printer *pp, int type, char *file, char format, int copyreq)
972 {
973 int i, amt;
974 struct stat stb;
975 char *av[15], *filtcmd;
976 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4];
977 int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc;
978
979 statrc = lstat(file, &stb);
980 if (statrc < 0) {
981 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
982 pp->printer, file);
983 return (ERROR);
984 }
985 sfd = open(file, O_RDONLY);
986 if (sfd < 0) {
987 syslog(LOG_ERR, "%s: error from open(%s,O_RDONLY): %m",
988 pp->printer, file);
989 return (ERROR);
990 }
991 /*
992 * Check to see if data file is a symbolic link. If so, it should
993 * still point to the same file or someone is trying to print something
994 * he shouldn't.
995 */
996 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(sfd, &stb) == 0 &&
997 (stb.st_dev != fdev || stb.st_ino != fino)) {
998 close(sfd);
999 return (ACCESS);
1000 }
1001
1002 /* Everything seems OK for reading the file, now to send it */
1003 filtcmd = NULL;
1004 sizerr = 0;
1005 tfd = -1;
1006 if (type == '\3') {
1007 /*
1008 * Type == 3 means this is a datafile, not a control file.
1009 * Increment the counter of data-files in this job, and
1010 * then check for input or output filters (which are only
1011 * applied to datafiles, not control files).
1012 */
1013 job_dfcnt++;
1014
1015 /*
1016 * Note that here we are filtering datafiles, one at a time,
1017 * as they are sent to the remote machine. Here, the *only*
1018 * difference between an input filter (`if=') and an output
1019 * filter (`of=') is the argument list that the filter is
1020 * started up with. Here, the output filter is executed
1021 * for each individual file as it is sent. This is not the
1022 * same as local print queues, where the output filter is
1023 * started up once, and then all jobs are passed thru that
1024 * single invocation of the output filter.
1025 *
1026 * Also note that a queue for a remote-machine can have an
1027 * input filter or an output filter, but not both.
1028 */
1029 if (pp->filters[LPF_INPUT]) {
1030 filtcmd = pp->filters[LPF_INPUT];
1031 av[0] = filtcmd;
1032 narg = 0;
1033 strcpy(opt_c, "-c");
1034 strcpy(opt_h, "-h");
1035 strcpy(opt_n, "-n");
1036 if (format == 'l')
1037 av[++narg] = opt_c;
1038 av[++narg] = width;
1039 av[++narg] = length;
1040 av[++narg] = indent;
1041 av[++narg] = opt_n;
1042 av[++narg] = logname;
1043 av[++narg] = opt_h;
1044 av[++narg] = origin_host;
1045 av[++narg] = pp->acct_file;
1046 av[++narg] = NULL;
1047 } else if (pp->filters[LPF_OUTPUT]) {
1048 filtcmd = pp->filters[LPF_OUTPUT];
1049 av[0] = filtcmd;
1050 narg = 0;
1051 av[++narg] = width;
1052 av[++narg] = length;
1053 av[++narg] = NULL;
1054 }
1055 }
1056 if (filtcmd) {
1057 /*
1058 * If there is an input or output filter, we have to run
1059 * the datafile thru that filter and store the result as
1060 * a temporary spool file, because the protocol requires
1061 * that we send the remote host the file-size before we
1062 * start to send any of the data.
1063 */
1064 strcpy(tfile, TFILENAME);
1065 tfd = mkstemp(tfile);
1066 if (tfd == -1) {
1067 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer,
1068 TFILENAME);
1069 sfres = ERROR;
1070 goto return_sfres;
1071 }
1072 filtstat = execfilter(pp, filtcmd, av, sfd, tfd);
1073
1074 /* process the return-code from the filter */
1075 switch (filtstat) {
1076 case 0:
1077 break;
1078 case 1:
1079 sfres = REPRINT;
1080 goto return_sfres;
1081 case 2:
1082 sfres = ERROR;
1083 goto return_sfres;
1084 default:
1085 syslog(LOG_WARNING,
1086 "%s: filter '%c' exited (retcode=%d)",
1087 pp->printer, format, filtstat);
1088 sfres = FILTERERR;
1089 goto return_sfres;
1090 }
1091 statrc = fstat(tfd, &stb); /* to find size of tfile */
1092 if (statrc < 0) {
1093 syslog(LOG_ERR,
1094 "%s: error processing 'if', fstat(%s): %m",
1095 pp->printer, tfile);
1096 sfres = ERROR;
1097 goto return_sfres;
1098 }
1099 close(sfd);
1100 sfd = tfd;
1101 lseek(sfd, 0, SEEK_SET);
1102 }
1103
1104 copycnt = 0;
1105 sendagain:
1106 copycnt++;
1107
1108 if (copycnt < 2)
1109 sprintf(buf, "%c%jd %s\n", type, (intmax_t)stb.st_size, file);
1110 else
1111 sprintf(buf, "%c%jd %s_c%d\n", type, (intmax_t)stb.st_size,
1112 file, copycnt);
1113 amt = strlen(buf);
1114 for (i = 0; ; i++) {
1115 if (write(pfd, buf, amt) != amt ||
1116 (resp = response(pp)) < 0 || resp == '\1') {
1117 sfres = REPRINT;
1118 goto return_sfres;
1119 } else if (resp == '\0')
1120 break;
1121 if (i == 0)
1122 pstatus(pp,
1123 "no space on remote; waiting for queue to drain");
1124 if (i == 10)
1125 syslog(LOG_ALERT, "%s: can't send to %s; queue full",
1126 pp->printer, pp->remote_host);
1127 sleep(5 * 60);
1128 }
1129 if (i)
1130 pstatus(pp, "sending to %s", pp->remote_host);
1131 /*
1132 * XXX - we should change trstat_init()/trstat_write() to include
1133 * the copycnt in the statistics record it may write.
1134 */
1135 if (type == '\3')
1136 trstat_init(pp, file, job_dfcnt);
1137 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1138 amt = BUFSIZ;
1139 if (i + amt > stb.st_size)
1140 amt = stb.st_size - i;
1141 if (sizerr == 0 && read(sfd, buf, amt) != amt)
1142 sizerr = 1;
1143 if (write(pfd, buf, amt) != amt) {
1144 sfres = REPRINT;
1145 goto return_sfres;
1146 }
1147 }
1148
1149 if (sizerr) {
1150 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1151 /* tell recvjob to ignore this file */
1152 write(pfd, "\1", 1);
1153 sfres = ERROR;
1154 goto return_sfres;
1155 }
1156 if (write(pfd, "", 1) != 1 || response(pp)) {
1157 sfres = REPRINT;
1158 goto return_sfres;
1159 }
1160 if (type == '\3') {
1161 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1162 pp->remote_host, origin_host);
1163 /*
1164 * Usually we only need to send one copy of a datafile,
1165 * because the control-file will simply print the same
1166 * file multiple times. However, some printers ignore
1167 * the control file, and simply print each data file as
1168 * it arrives. For such "remote hosts", we need to
1169 * transfer the same data file multiple times. Such a
1170 * a host is indicated by adding 'rc' to the printcap
1171 * entry.
1172 * XXX - Right now this ONLY works for remote hosts which
1173 * do ignore the name of the data file, because
1174 * this sends the file multiple times with slight
1175 * changes to the filename. To do this right would
1176 * require that we also rewrite the control file
1177 * to match those filenames.
1178 */
1179 if (pp->resend_copies && (copycnt < copyreq)) {
1180 lseek(sfd, 0, SEEK_SET);
1181 goto sendagain;
1182 }
1183 }
1184 sfres = OK;
1185
1186 return_sfres:
1187 close(sfd);
1188 if (tfd != -1) {
1189 /*
1190 * If tfd is set, then it is the same value as sfd, and
1191 * therefore it is already closed at this point. All
1192 * we need to do is remove the temporary file.
1193 */
1194 tfd = -1;
1195 unlink(tfile);
1196 }
1197 return (sfres);
1198 }
1199
1200 /*
1201 * This routine is called to execute one of the filters as was
1202 * specified in a printcap entry. While the child-process will read
1203 * all of 'infd', it is up to the caller to close that file descriptor
1204 * in the parent process.
1205 */
1206 static int
execfilter(struct printer * pp,char * f_cmd,char * f_av[],int infd,int outfd)1207 execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd)
1208 {
1209 pid_t fpid, wpid;
1210 int errfd, retcode, wstatus;
1211 FILE *errfp;
1212 char buf[BUFSIZ], *slash;
1213
1214 fpid = dofork(pp, DORETURN);
1215 if (fpid != 0) {
1216 /*
1217 * This is the parent process, which just waits for the child
1218 * to complete and then returns the result. Note that it is
1219 * the child process which reads the input stream.
1220 */
1221 if (fpid < 0)
1222 retcode = 100;
1223 else {
1224 while ((wpid = wait(&wstatus)) > 0 &&
1225 wpid != fpid)
1226 ;
1227 if (wpid < 0) {
1228 retcode = 100;
1229 syslog(LOG_WARNING,
1230 "%s: after execv(%s), wait() returned: %m",
1231 pp->printer, f_cmd);
1232 } else
1233 retcode = WEXITSTATUS(wstatus);
1234 }
1235
1236 /*
1237 * Copy everything the filter wrote to stderr from our
1238 * temporary errors file to the "lf=" logfile.
1239 */
1240 errfp = fopen(tempstderr, "r");
1241 if (errfp) {
1242 while (fgets(buf, sizeof(buf), errfp))
1243 fputs(buf, stderr);
1244 fclose(errfp);
1245 }
1246
1247 return (retcode);
1248 }
1249
1250 /*
1251 * This is the child process, which is the one that executes the
1252 * given filter.
1253 */
1254 /*
1255 * If the first parameter has any slashes in it, then change it
1256 * to point to the first character after the last slash.
1257 */
1258 slash = strrchr(f_av[0], '/');
1259 if (slash != NULL)
1260 f_av[0] = slash + 1;
1261 /*
1262 * XXX - in the future, this should setup an explicit list of
1263 * environment variables and use execve()!
1264 */
1265
1266 /*
1267 * Setup stdin, stdout, and stderr as we want them when the filter
1268 * is running. Stderr is setup so it points to a temporary errors
1269 * file, and the parent process will copy that temporary file to
1270 * the real logfile after the filter completes.
1271 */
1272 dup2(infd, 0);
1273 dup2(outfd, 1);
1274 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1275 if (errfd >= 0)
1276 dup2(errfd, 2);
1277 closelog();
1278 closeallfds(3);
1279 execv(f_cmd, f_av);
1280 syslog(LOG_ERR, "%s: cannot execv(%s): %m", pp->printer, f_cmd);
1281 exit(2);
1282 /* NOTREACHED */
1283 }
1284
1285 /*
1286 * Check to make sure there have been no errors and that both programs
1287 * are in sync with eachother.
1288 * Return non-zero if the connection was lost.
1289 */
1290 static char
response(const struct printer * pp)1291 response(const struct printer *pp)
1292 {
1293 char resp;
1294
1295 if (read(pfd, &resp, 1) != 1) {
1296 syslog(LOG_INFO, "%s: lost connection", pp->printer);
1297 return (-1);
1298 }
1299 return (resp);
1300 }
1301
1302 /*
1303 * Banner printing stuff
1304 */
1305 static void
banner(struct printer * pp,char * name1,char * name2)1306 banner(struct printer *pp, char *name1, char *name2)
1307 {
1308 time_t tvec;
1309
1310 time(&tvec);
1311 if (!pp->no_formfeed && !pp->tof)
1312 write(ofd, pp->form_feed, strlen(pp->form_feed));
1313 if (pp->short_banner) { /* short banner only */
1314 if (class[0]) {
1315 write(ofd, class, strlen(class));
1316 write(ofd, ":", 1);
1317 }
1318 write(ofd, name1, strlen(name1));
1319 write(ofd, " Job: ", 7);
1320 write(ofd, name2, strlen(name2));
1321 write(ofd, " Date: ", 8);
1322 write(ofd, ctime(&tvec), 24);
1323 write(ofd, "\n", 1);
1324 } else { /* normal banner */
1325 write(ofd, "\n\n\n", 3);
1326 scan_out(pp, ofd, name1, '\0');
1327 write(ofd, "\n\n", 2);
1328 scan_out(pp, ofd, name2, '\0');
1329 if (class[0]) {
1330 write(ofd,"\n\n\n",3);
1331 scan_out(pp, ofd, class, '\0');
1332 }
1333 write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1334 write(ofd, name2, strlen(name2));
1335 write(ofd, "\n\t\t\t\t\tDate: ", 12);
1336 write(ofd, ctime(&tvec), 24);
1337 write(ofd, "\n", 1);
1338 }
1339 if (!pp->no_formfeed)
1340 write(ofd, pp->form_feed, strlen(pp->form_feed));
1341 pp->tof = 1;
1342 }
1343
1344 static char *
scnline(int key,char * p,int c)1345 scnline(int key, char *p, int c)
1346 {
1347 int scnwidth;
1348
1349 for (scnwidth = WIDTH; --scnwidth;) {
1350 key <<= 1;
1351 *p++ = key & 0200 ? c : BACKGND;
1352 }
1353 return (p);
1354 }
1355
1356 #define TRC(q) (((q)-' ')&0177)
1357
1358 static void
scan_out(struct printer * pp,int scfd,char * scsp,int dlm)1359 scan_out(struct printer *pp, int scfd, char *scsp, int dlm)
1360 {
1361 char *strp;
1362 int nchrs, j;
1363 char outbuf[LINELEN+1], *sp, c, cc;
1364 int d, scnhgt;
1365
1366 for (scnhgt = 0; scnhgt++ < HEIGHT+DROP; ) {
1367 strp = &outbuf[0];
1368 sp = scsp;
1369 for (nchrs = 0; ; ) {
1370 d = dropit(c = TRC(cc = *sp++));
1371 if ((!d && scnhgt > HEIGHT) || (scnhgt <= DROP && d))
1372 for (j = WIDTH; --j;)
1373 *strp++ = BACKGND;
1374 else
1375 strp = scnline(scnkey[(int)c][scnhgt-1-d], strp, cc);
1376 if (*sp == dlm || *sp == '\0' ||
1377 nchrs++ >= pp->page_width/(WIDTH+1)-1)
1378 break;
1379 *strp++ = BACKGND;
1380 *strp++ = BACKGND;
1381 }
1382 while (*--strp == BACKGND && strp >= outbuf)
1383 ;
1384 strp++;
1385 *strp++ = '\n';
1386 write(scfd, outbuf, strp-outbuf);
1387 }
1388 }
1389
1390 static int
dropit(int c)1391 dropit(int c)
1392 {
1393 switch(c) {
1394
1395 case TRC('_'):
1396 case TRC(';'):
1397 case TRC(','):
1398 case TRC('g'):
1399 case TRC('j'):
1400 case TRC('p'):
1401 case TRC('q'):
1402 case TRC('y'):
1403 return (DROP);
1404
1405 default:
1406 return (0);
1407 }
1408 }
1409
1410 /*
1411 * sendmail ---
1412 * tell people about job completion
1413 */
1414 static void
sendmail(struct printer * pp,char * userid,int bombed)1415 sendmail(struct printer *pp, char *userid, int bombed)
1416 {
1417 int i;
1418 int p[2], s;
1419 const char *cp;
1420 struct stat stb;
1421 FILE *fp;
1422
1423 pipe(p);
1424 if ((s = dofork(pp, DORETURN)) == 0) { /* child */
1425 dup2(p[0], 0);
1426 closelog();
1427 closeallfds(3);
1428 if ((cp = strrchr(_PATH_SENDMAIL, '/')) != NULL)
1429 cp++;
1430 else
1431 cp = _PATH_SENDMAIL;
1432 execl(_PATH_SENDMAIL, cp, "-t", NULL);
1433 _exit(0);
1434 } else if (s > 0) { /* parent */
1435 dup2(p[1], 1);
1436 printf("To: %s@%s\n", userid, origin_host);
1437 printf("Subject: %s printer job \"%s\"\n", pp->printer,
1438 *jobname ? jobname : "<unknown>");
1439 printf("Reply-To: root@%s\n\n", local_host);
1440 printf("Your printer job ");
1441 if (*jobname)
1442 printf("(%s) ", jobname);
1443
1444 switch (bombed) {
1445 case OK:
1446 cp = "OK";
1447 printf("\ncompleted successfully\n");
1448 break;
1449 default:
1450 case FATALERR:
1451 cp = "FATALERR";
1452 printf("\ncould not be printed\n");
1453 break;
1454 case NOACCT:
1455 cp = "NOACCT";
1456 printf("\ncould not be printed without an account on %s\n",
1457 local_host);
1458 break;
1459 case FILTERERR:
1460 cp = "FILTERERR";
1461 if (stat(tempstderr, &stb) < 0 || stb.st_size == 0
1462 || (fp = fopen(tempstderr, "r")) == NULL) {
1463 printf("\nhad some errors and may not have printed\n");
1464 break;
1465 }
1466 printf("\nhad the following errors and may not have printed:\n");
1467 while ((i = getc(fp)) != EOF)
1468 putchar(i);
1469 fclose(fp);
1470 break;
1471 case ACCESS:
1472 cp = "ACCESS";
1473 printf("\nwas not printed because it was not linked to the original file\n");
1474 }
1475 fflush(stdout);
1476 close(1);
1477 } else {
1478 syslog(LOG_WARNING, "unable to send mail to %s: %m", userid);
1479 return;
1480 }
1481 close(p[0]);
1482 close(p[1]);
1483 wait(NULL);
1484 syslog(LOG_INFO, "mail sent to user %s about job %s on printer %s (%s)",
1485 userid, *jobname ? jobname : "<unknown>", pp->printer, cp);
1486 }
1487
1488 /*
1489 * dofork - fork with retries on failure
1490 */
1491 static int
dofork(const struct printer * pp,int action)1492 dofork(const struct printer *pp, int action)
1493 {
1494 pid_t forkpid;
1495 int i, fail;
1496 struct passwd *pwd;
1497
1498 forkpid = -1;
1499 if (daemon_uname == NULL) {
1500 pwd = getpwuid(pp->daemon_user);
1501 if (pwd == NULL) {
1502 syslog(LOG_ERR, "%s: Can't lookup default daemon uid (%ld) in password file",
1503 pp->printer, pp->daemon_user);
1504 goto error_ret;
1505 }
1506 daemon_uname = strdup(pwd->pw_name);
1507 daemon_defgid = pwd->pw_gid;
1508 }
1509
1510 for (i = 0; i < 20; i++) {
1511 forkpid = fork();
1512 if (forkpid < 0) {
1513 sleep((unsigned)(i*i));
1514 continue;
1515 }
1516 /*
1517 * Child should run as daemon instead of root
1518 */
1519 if (forkpid == 0) {
1520 errno = 0;
1521 fail = initgroups(daemon_uname, daemon_defgid);
1522 if (fail) {
1523 syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
1524 pp->printer, daemon_uname, daemon_defgid);
1525 break;
1526 }
1527 fail = setgid(daemon_defgid);
1528 if (fail) {
1529 syslog(LOG_ERR, "%s: setgid(%u): %m",
1530 pp->printer, daemon_defgid);
1531 break;
1532 }
1533 fail = setuid(pp->daemon_user);
1534 if (fail) {
1535 syslog(LOG_ERR, "%s: setuid(%ld): %m",
1536 pp->printer, pp->daemon_user);
1537 break;
1538 }
1539 }
1540 return (forkpid);
1541 }
1542
1543 /*
1544 * An error occurred. If the error is in the child process, then
1545 * this routine MUST always exit(). DORETURN only effects how
1546 * errors should be handled in the parent process.
1547 */
1548 error_ret:
1549 if (forkpid == 0) {
1550 syslog(LOG_ERR, "%s: dofork(): aborting child process...",
1551 pp->printer);
1552 exit(1);
1553 }
1554 syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);
1555
1556 sleep(1); /* throttle errors, as a safety measure */
1557 switch (action) {
1558 case DORETURN:
1559 return (-1);
1560 default:
1561 syslog(LOG_ERR, "bad action (%d) to dofork", action);
1562 /* FALLTHROUGH */
1563 case DOABORT:
1564 exit(1);
1565 }
1566 /*NOTREACHED*/
1567 }
1568
1569 /*
1570 * Kill child processes to abort current job.
1571 */
1572 static void
abortpr(int signo __unused)1573 abortpr(int signo __unused)
1574 {
1575
1576 unlink(tempstderr);
1577 kill(0, SIGINT);
1578 if (of_pid > 0)
1579 kill(of_pid, SIGCONT);
1580 while (wait(NULL) > 0)
1581 ;
1582 if (of_pid > 0 && tfd != -1)
1583 unlink(tfile);
1584 exit(0);
1585 }
1586
1587 static void
init(struct printer * pp)1588 init(struct printer *pp)
1589 {
1590 char *s;
1591
1592 sprintf(&width[2], "%ld", pp->page_width);
1593 sprintf(&length[2], "%ld", pp->page_length);
1594 sprintf(&pxwidth[2], "%ld", pp->page_pwidth);
1595 sprintf(&pxlength[2], "%ld", pp->page_plength);
1596 if ((s = checkremote(pp)) != NULL) {
1597 syslog(LOG_WARNING, "%s", s);
1598 free(s);
1599 }
1600 }
1601
1602 void
startprinting(const char * printer)1603 startprinting(const char *printer)
1604 {
1605 struct printer myprinter, *pp = &myprinter;
1606 int status;
1607
1608 init_printer(pp);
1609 status = getprintcap(printer, pp);
1610 switch(status) {
1611 case PCAPERR_OSERR:
1612 syslog(LOG_ERR, "can't open printer description file: %m");
1613 exit(1);
1614 case PCAPERR_NOTFOUND:
1615 syslog(LOG_ERR, "unknown printer: %s", printer);
1616 exit(1);
1617 case PCAPERR_TCLOOP:
1618 fatal(pp, "potential reference loop detected in printcap file");
1619 default:
1620 break;
1621 }
1622 printjob(pp);
1623 }
1624
1625 /*
1626 * Acquire line printer or remote connection.
1627 */
1628 static void
openpr(const struct printer * pp)1629 openpr(const struct printer *pp)
1630 {
1631 int p[2];
1632 char *cp;
1633
1634 if (pp->remote) {
1635 openrem(pp);
1636 /*
1637 * Lpd does support the setting of 'of=' filters for
1638 * jobs going to remote machines, but that does not
1639 * have the same meaning as 'of=' does when handling
1640 * local print queues. For remote machines, all 'of='
1641 * filter processing is handled in sendfile(), and that
1642 * does not use these global "output filter" variables.
1643 */
1644 ofd = -1;
1645 of_pid = 0;
1646 return;
1647 } else if (*pp->lp) {
1648 if ((cp = strchr(pp->lp, '@')) != NULL)
1649 opennet(pp);
1650 else
1651 opentty(pp);
1652 } else {
1653 syslog(LOG_ERR, "%s: no line printer device or host name",
1654 pp->printer);
1655 exit(1);
1656 }
1657
1658 /*
1659 * Start up an output filter, if needed.
1660 */
1661 if (pp->filters[LPF_OUTPUT] && !pp->filters[LPF_INPUT] && !of_pid) {
1662 pipe(p);
1663 if (pp->remote) {
1664 strcpy(tfile, TFILENAME);
1665 tfd = mkstemp(tfile);
1666 }
1667 if ((of_pid = dofork(pp, DOABORT)) == 0) { /* child */
1668 dup2(p[0], 0); /* pipe is std in */
1669 /* tfile/printer is stdout */
1670 dup2(pp->remote ? tfd : pfd, 1);
1671 closelog();
1672 closeallfds(3);
1673 if ((cp = strrchr(pp->filters[LPF_OUTPUT], '/')) == NULL)
1674 cp = pp->filters[LPF_OUTPUT];
1675 else
1676 cp++;
1677 execl(pp->filters[LPF_OUTPUT], cp, width, length,
1678 NULL);
1679 syslog(LOG_ERR, "%s: execl(%s): %m", pp->printer,
1680 pp->filters[LPF_OUTPUT]);
1681 exit(1);
1682 }
1683 close(p[0]); /* close input side */
1684 ofd = p[1]; /* use pipe for output */
1685 } else {
1686 ofd = pfd;
1687 of_pid = 0;
1688 }
1689 }
1690
1691 /*
1692 * Printer connected directly to the network
1693 * or to a terminal server on the net
1694 */
1695 static void
opennet(const struct printer * pp)1696 opennet(const struct printer *pp)
1697 {
1698 int i;
1699 int resp;
1700 u_long port;
1701 char *ep;
1702 void (*savealrm)(int);
1703
1704 port = strtoul(pp->lp, &ep, 0);
1705 if (*ep != '@' || port > 65535) {
1706 syslog(LOG_ERR, "%s: bad port number: %s", pp->printer,
1707 pp->lp);
1708 exit(1);
1709 }
1710 ep++;
1711
1712 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1713 resp = -1;
1714 savealrm = signal(SIGALRM, alarmhandler);
1715 alarm(pp->conn_timeout);
1716 pfd = getport(pp, ep, port);
1717 alarm(0);
1718 signal(SIGALRM, savealrm);
1719 if (pfd < 0 && errno == ECONNREFUSED)
1720 resp = 1;
1721 else if (pfd >= 0) {
1722 /*
1723 * need to delay a bit for rs232 lines
1724 * to stabilize in case printer is
1725 * connected via a terminal server
1726 */
1727 delay(500);
1728 break;
1729 }
1730 if (i == 1) {
1731 if (resp < 0)
1732 pstatus(pp, "waiting for %s to come up",
1733 pp->lp);
1734 else
1735 pstatus(pp,
1736 "waiting for access to printer on %s",
1737 pp->lp);
1738 }
1739 sleep(i);
1740 }
1741 pstatus(pp, "sending to %s port %lu", ep, port);
1742 }
1743
1744 /*
1745 * Printer is connected to an RS232 port on this host
1746 */
1747 static void
opentty(const struct printer * pp)1748 opentty(const struct printer *pp)
1749 {
1750 int i;
1751
1752 for (i = 1; ; i = i < 32 ? i << 1 : i) {
1753 pfd = open(pp->lp, pp->rw ? O_RDWR : O_WRONLY);
1754 if (pfd >= 0) {
1755 delay(500);
1756 break;
1757 }
1758 if (errno == ENOENT) {
1759 syslog(LOG_ERR, "%s: %m", pp->lp);
1760 exit(1);
1761 }
1762 if (i == 1)
1763 pstatus(pp,
1764 "waiting for %s to become ready (offline?)",
1765 pp->printer);
1766 sleep(i);
1767 }
1768 if (isatty(pfd))
1769 setty(pp);
1770 pstatus(pp, "%s is ready and printing", pp->printer);
1771 }
1772
1773 /*
1774 * Printer is on a remote host
1775 */
1776 static void
openrem(const struct printer * pp)1777 openrem(const struct printer *pp)
1778 {
1779 int i;
1780 int resp;
1781 void (*savealrm)(int);
1782
1783 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1784 resp = -1;
1785 savealrm = signal(SIGALRM, alarmhandler);
1786 alarm(pp->conn_timeout);
1787 pfd = getport(pp, pp->remote_host, 0);
1788 alarm(0);
1789 signal(SIGALRM, savealrm);
1790 if (pfd >= 0) {
1791 if ((writel(pfd, "\2", pp->remote_queue, "\n", NULL)
1792 == 2 + strlen(pp->remote_queue))
1793 && (resp = response(pp)) == 0)
1794 break;
1795 close(pfd);
1796 }
1797 if (i == 1) {
1798 if (resp < 0)
1799 pstatus(pp, "waiting for %s to come up",
1800 pp->remote_host);
1801 else {
1802 pstatus(pp,
1803 "waiting for queue to be enabled on %s",
1804 pp->remote_host);
1805 i = 256;
1806 }
1807 }
1808 sleep(i);
1809 }
1810 pstatus(pp, "sending to %s", pp->remote_host);
1811 }
1812
1813 /*
1814 * setup tty lines.
1815 */
1816 static void
setty(const struct printer * pp)1817 setty(const struct printer *pp)
1818 {
1819 struct termios ttybuf;
1820
1821 if (ioctl(pfd, TIOCEXCL, NULL) < 0) {
1822 syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", pp->printer);
1823 exit(1);
1824 }
1825 if (tcgetattr(pfd, &ttybuf) < 0) {
1826 syslog(LOG_ERR, "%s: tcgetattr: %m", pp->printer);
1827 exit(1);
1828 }
1829 if (pp->baud_rate > 0)
1830 cfsetspeed(&ttybuf, pp->baud_rate);
1831 if (pp->mode_set) {
1832 char *s = strdup(pp->mode_set), *tmp;
1833
1834 while ((tmp = strsep(&s, ",")) != NULL) {
1835 msearch(tmp, &ttybuf);
1836 }
1837 }
1838 if (pp->mode_set != 0 || pp->baud_rate > 0) {
1839 if (tcsetattr(pfd, TCSAFLUSH, &ttybuf) == -1) {
1840 syslog(LOG_ERR, "%s: tcsetattr: %m", pp->printer);
1841 }
1842 }
1843 }
1844
1845 #include <stdarg.h>
1846
1847 static void
pstatus(const struct printer * pp,const char * msg,...)1848 pstatus(const struct printer *pp, const char *msg, ...)
1849 {
1850 int fd;
1851 char *buf;
1852 va_list ap;
1853 va_start(ap, msg);
1854
1855 umask(0);
1856 fd = open(pp->status_file, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
1857 if (fd < 0) {
1858 syslog(LOG_ERR, "%s: open(%s): %m", pp->printer,
1859 pp->status_file);
1860 exit(1);
1861 }
1862 ftruncate(fd, 0);
1863 vasprintf(&buf, msg, ap);
1864 va_end(ap);
1865 writel(fd, buf, "\n", NULL);
1866 close(fd);
1867 free(buf);
1868 }
1869
1870 void
alarmhandler(int signo __unused)1871 alarmhandler(int signo __unused)
1872 {
1873 /* the signal is ignored */
1874 /* (the '__unused' is just to avoid a compile-time warning) */
1875 }
1876