xref: /dragonfly/usr.sbin/lpr/lpd/printjob.c (revision cae2835b6b4ebad97f7a0b45157102f433a3c656)
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