Bug Summary

File:src/usr.sbin/lpr/lpd/printjob.c
Warning:line 1565, column 9
Potential leak of memory pointed to by 'val'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name printjob.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/lpr/lpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/lpr/lpd/../common_source -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/lpr/lpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/lpr/lpd/printjob.c
1/* $OpenBSD: printjob.c,v 1.62 2021/10/24 21:24:18 deraadt Exp $ */
2/* $NetBSD: printjob.c,v 1.31 2002/01/21 14:42:30 wiz Exp $ */
3
4/*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * printjob -- print jobs in the queue.
36 *
37 * NOTE: the lock file is used to pass information to lpq and lprm.
38 * it does not need to be removed because file locks are dynamic.
39 */
40
41#include <sys/types.h>
42#include <sys/wait.h>
43#include <sys/stat.h>
44
45#include <pwd.h>
46#include <unistd.h>
47#include <signal.h>
48#include <termios.h>
49#include <syslog.h>
50#include <fcntl.h>
51#include <dirent.h>
52#include <errno(*__errno()).h>
53#include <stdio.h>
54#include <string.h>
55#include <limits.h>
56#include <stdlib.h>
57#include <stdarg.h>
58#include <ctype.h>
59
60#include "lp.h"
61#include "lp.local.h"
62#include "pathnames.h"
63#include "extern.h"
64
65#define DORETURN0 0 /* absorb fork error */
66#define DOABORT1 1 /* abort if dofork fails */
67
68/*
69 * Error tokens
70 */
71#define REPRINT-2 -2
72#define ERROR-1 -1
73#define OK0 0
74#define FATALERR1 1
75#define NOACCT2 2
76#define FILTERERR3 3
77#define ACCESS4 4
78
79static dev_t fdev; /* device of file pointed to by symlink */
80static ino_t fino; /* inode of file pointed to by symlink */
81static FILE *cfp; /* control file */
82static pid_t child; /* pid of any filters */
83static int lfd; /* lock file descriptor */
84static int ofd; /* output filter file descriptor */
85static pid_t ofilter; /* pid of output filter, if any */
86static int pfd; /* prstatic inter file descriptor */
87static pid_t pid; /* pid of lpd process */
88static pid_t prchild; /* pid of pr process */
89static char title[80]; /* ``pr'' title */
90static int tof; /* true if at top of form */
91
92static char class[32]; /* classification field */
93static char fromhost[HOST_NAME_MAX255+1]; /* user's host machine */
94 /* indentation size in static characters */
95static char indent[10] = "-i0";
96static char jobname[NAME_MAX255]; /* job or file name */
97static char length[10] = "-l"; /* page length in lines */
98static char logname[LOGIN_NAME_MAX32];/* user's login name */
99static char pxlength[10] = "-y"; /* page length in pixels */
100static char pxwidth[10] = "-x"; /* page width in pixels */
101static char tempfile[] = "errsXXXXXXXXXX"; /* file name for filter output */
102static char width[10] = "-w"; /* page width in static characters */
103
104static void abortpr(int);
105static void banner(char *, char *);
106static void delay(int);
107static pid_t dofork(int);
108static int dropit(int);
109static void init(void);
110static void openpr(void);
111static void opennet(char *);
112static void opentty(void);
113static void openrem(void);
114static int print(int, char *);
115static int printit(char *);
116static void pstatus(const char *, ...)
117 __attribute__((__format__(__printf__, 1, 2)));
118static char response(void);
119static void scan_out(int, char *, int);
120static char *scnline(int, char *, int);
121static int sendfile(int, char *);
122static int sendit(char *);
123static void sendmail(char *, int);
124static void setty(void);
125static void alarmer(int);
126
127void
128printjob(void)
129{
130 struct stat stb;
131 struct queue *q, **qp;
132 struct queue **queue;
133 struct sigaction sa;
134 int i, fd, nitems;
135 off_t pidoff;
136 int errcnt, count = 0;
137
138 init(); /* set up capabilities */
139 (void)write(STDOUT_FILENO1, "", 1); /* ack that daemon is started */
140 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1
Loop condition is false. Exiting loop
141 fd = open(LF, O_WRONLY0x0001|O_APPEND0x0008); /* set up log file */
142 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
2
Loop condition is false. Exiting loop
143 if (fd < 0) {
3
Assuming 'fd' is >= 0
4
Taking false branch
144 syslog(LOG_ERR3, "%s: %m", LF);
145 if ((fd = open(_PATH_DEVNULL"/dev/null", O_WRONLY0x0001)) < 0)
146 exit(1);
147 }
148 if (fd != STDERR_FILENO2) {
5
Assuming 'fd' is equal to STDERR_FILENO
6
Taking false branch
149 if (dup2(fd, STDERR_FILENO2) < 0) {
150 syslog(LOG_ERR3, "dup2: %m");
151 exit(1);
152 }
153 (void)close(fd);
154 }
155 setpgid(0, 0);
156
157 /* we add SIGINT to the mask so abortpr() doesn't kill itself */
158 memset(&sa, 0, sizeof(sa));
159 sa.sa_handler__sigaction_u.__sa_handler = abortpr;
160 sa.sa_flags = SA_RESTART0x0002;
161 sigemptyset(&sa.sa_mask);
162 sigaddset(&sa.sa_mask, SIGINT2);
163 sigaction(SIGHUP1, &sa, NULL((void *)0));
164 sigaction(SIGINT2, &sa, NULL((void *)0));
165 sigaction(SIGQUIT3, &sa, NULL((void *)0));
166 sigaction(SIGTERM15, &sa, NULL((void *)0));
167
168 /* so we can use short form file names */
169 if (chdir(SD) < 0) {
7
Assuming the condition is false
8
Taking false branch
170 syslog(LOG_ERR3, "%s: %m", SD);
171 exit(1);
172 }
173
174 (void)mktemp(tempfile); /* safe */
175
176 lfd = safe_open(LO, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100|O_EXLOCK0x0020, 0640);
177 if (lfd < 0) {
9
Assuming 'lfd' is >= 0
10
Taking false branch
178 if (errno(*__errno()) == EWOULDBLOCK35) /* active daemon present */
179 exit(0);
180 syslog(LOG_ERR3, "%s: %s: %m", printer, LO);
181 exit(1);
182 }
183 if (fstat(lfd, &stb) == 0 && (stb.st_mode & S_IXUSR0000100))
11
Assuming the condition is false
184 exit(0); /* printing disabled */
185 ftruncate(lfd, 0);
186 /*
187 * write process id for others to know
188 */
189 pid = getpid();
190 if ((pidoff = i = snprintf(line, sizeof(line), "%d\n", pid)) < 0 ||
12
Assuming the condition is false
14
Taking false branch
191 i >= sizeof(line)) {
13
Assuming the condition is false
192 syslog(LOG_ERR3, "impossibly large pid: %u", pid);
193 exit(1);
194 }
195 if (write(lfd, line, i) != i) {
15
Assuming the condition is false
16
Taking false branch
196 syslog(LOG_ERR3, "%s: %s: %m", printer, LO);
197 exit(1);
198 }
199 /*
200 * search the spool directory for work and sort by queue order.
201 */
202 if ((nitems = getq(&queue)) < 0) {
17
Assuming the condition is false
18
Taking false branch
203 syslog(LOG_ERR3, "%s: can't scan %s", printer, SD);
204 exit(1);
205 }
206 if (nitems == 0) /* no work to do */
19
Assuming 'nitems' is not equal to 0
20
Taking false branch
207 exit(0);
208 if (stb.st_mode & S_IXOTH0000001) { /* reset queue flag */
21
Assuming the condition is false
22
Taking false branch
209 stb.st_mode &= ~S_IXOTH0000001;
210 if (fchmod(lfd, stb.st_mode & 0777) < 0)
211 syslog(LOG_ERR3, "%s: %s: %m", printer, LO);
212 }
213 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
23
Loop condition is false. Exiting loop
214 openpr(); /* open printer or remote */
24
Calling 'openpr'
215 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
216
217again:
218 /*
219 * we found something to do now do it --
220 * write the name of the current control file into the lock file
221 * so the spool queue program can tell what we're working on
222 */
223 for (qp = queue; nitems--; free(q)) {
224 q = *qp++;
225 if (stat(q->q_name, &stb) < 0)
226 continue;
227 errcnt = 0;
228 restart:
229 fdev = (dev_t)-1;
230 fino = (ino_t)-1;
231
232 (void)lseek(lfd, pidoff, SEEK_SET0);
233 if ((i = snprintf(line, sizeof(line), "%s\n", q->q_name)) < 0 ||
234 i >= sizeof(line))
235 i = sizeof(line) - 1; /* can't happen */
236 if (write(lfd, line, i) != i)
237 syslog(LOG_ERR3, "%s: %s: %m", printer, LO);
238 if (!remote)
239 i = printit(q->q_name);
240 else
241 i = sendit(q->q_name);
242 /*
243 * Check to see if we are supposed to stop printing or
244 * if we are to rebuild the queue.
245 */
246 if (fstat(lfd, &stb) == 0) {
247 /* stop printing before starting next job? */
248 if (stb.st_mode & S_IXUSR0000100)
249 goto done;
250 /* rebuild queue (after lpc topq) */
251 if (stb.st_mode & S_IXOTH0000001) {
252 for (free(q); nitems--; free(q))
253 q = *qp++;
254 stb.st_mode &= ~S_IXOTH0000001;
255 if (fchmod(lfd, stb.st_mode & 0777) < 0)
256 syslog(LOG_WARNING4, "%s: %s: %m",
257 printer, LO);
258 break;
259 }
260 }
261 if (i == OK0) /* file ok and printed */
262 count++;
263 else if (i == REPRINT-2 && ++errcnt < 5) {
264 /* try reprinting the job */
265 syslog(LOG_INFO6, "restarting %s", printer);
266 if (ofilter > 0) {
267 kill(ofilter, SIGCONT19); /* to be sure */
268 (void)close(ofd);
269 while ((i = wait(NULL((void *)0))) > 0 && i != ofilter)
270 ;
271 ofilter = 0;
272 }
273 (void)close(pfd); /* close printer */
274 if (ftruncate(lfd, pidoff) < 0)
275 syslog(LOG_WARNING4, "%s: %s: %m", printer, LO);
276 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
277 openpr(); /* try to reopen printer */
278 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
279 goto restart;
280 } else {
281 syslog(LOG_WARNING4, "%s: job could not be %s (%s)", printer,
282 remote ? "sent to remote host" : "printed", q->q_name);
283 if (i == REPRINT-2) {
284 /* ensure we don't attempt this job again */
285 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
286 (void)unlink(q->q_name);
287 q->q_name[0] = 'd';
288 (void)unlink(q->q_name);
289 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
290 if (logname[0])
291 sendmail(logname, FATALERR1);
292 }
293 }
294 }
295 free(queue);
296 /*
297 * search the spool directory for more work.
298 */
299 if ((nitems = getq(&queue)) < 0) {
300 syslog(LOG_ERR3, "%s: can't scan %s", printer, SD);
301 exit(1);
302 }
303 if (nitems == 0) { /* no more work to do */
304 done:
305 if (count > 0) { /* Files actually printed */
306 if (!SF && !tof)
307 (void)write(ofd, FF, strlen(FF));
308 if (TR != NULL((void *)0)) /* output trailer */
309 (void)write(ofd, TR, strlen(TR));
310 }
311 (void)close(ofd);
312 (void)wait(NULL((void *)0));
313 (void)unlink(tempfile);
314 exit(0);
315 }
316 goto again;
317}
318
319#define FONTLEN50 50
320char fonts[4][FONTLEN50]; /* fonts for troff */
321
322char ifonts[4][40] = {
323 _PATH_VFONTR"/usr/libdata/vfont/R",
324 _PATH_VFONTI"/usr/libdata/vfont/I",
325 _PATH_VFONTB"/usr/libdata/vfont/B",
326 _PATH_VFONTS"/usr/libdata/vfont/S",
327};
328
329/*
330 * The remaining part is the reading of the control file (cf)
331 * and performing the various actions.
332 */
333static int
334printit(char *file)
335{
336 int i, fd;
337 char *cp;
338 int bombed = OK0;
339
340 /*
341 * open control file; ignore if no longer there.
342 */
343 fd = safe_open(file, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
344 if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL((void *)0)) {
345 syslog(LOG_INFO6, "%s: %s: %m", printer, file);
346 if (fd >= 0)
347 (void)close(fd);
348 return(OK0);
349 }
350 /*
351 * Reset troff fonts.
352 */
353 for (i = 0; i < 4; i++)
354 strlcpy(fonts[i], ifonts[i], FONTLEN50);
355 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
356 indent[2] = '0';
357 indent[3] = '\0';
358
359 /*
360 * read the control file for work to do
361 *
362 * file format -- first character in the line is a command
363 * rest of the line is the argument.
364 * valid commands are:
365 *
366 * S -- "stat info" for symbolic link protection
367 * J -- "job name" on banner page
368 * C -- "class name" on banner page
369 * L -- "literal" user's name to print on banner
370 * T -- "title" for pr
371 * H -- "host name" of machine where lpr was done
372 * P -- "person" user's login name
373 * I -- "indent" amount to indent output
374 * R -- laser dpi "resolution"
375 * f -- "file name" name of text file to print
376 * l -- "file name" text file with control chars
377 * p -- "file name" text file to print with pr(1)
378 * t -- "file name" troff(1) file to print
379 * n -- "file name" ditroff(1) file to print
380 * d -- "file name" dvi file to print
381 * g -- "file name" plot(1G) file to print
382 * v -- "file name" plain raster file to print
383 * c -- "file name" cifplot file to print
384 * 1 -- "R font file" for troff
385 * 2 -- "I font file" for troff
386 * 3 -- "B font file" for troff
387 * 4 -- "S font file" for troff
388 * N -- "name" of file (used by lpq)
389 * U -- "unlink" name of file to remove
390 * (after we print it. (Pass 2 only)).
391 * M -- "mail" to user when done printing
392 *
393 * get_line reads a line and expands tabs to blanks
394 */
395
396 /* pass 1 */
397
398 while (get_line(cfp))
399 switch (line[0]) {
400 case 'H':
401 strlcpy(fromhost, line+1, sizeof(fromhost));
402 if (class[0] == '\0')
403 strlcpy(class, line+1, sizeof(class));
404 continue;
405
406 case 'P':
407 strlcpy(logname, line+1, sizeof(logname));
408 if (RS) { /* restricted */
409 if (getpwnam(logname) == NULL((void *)0)) {
410 bombed = NOACCT2;
411 sendmail(line+1, bombed);
412 goto pass2;
413 }
414 }
415 continue;
416
417 case 'S':
418 cp = line+1;
419 fdev = 0;
420 while (*cp >= '0' && *cp <= '9')
421 fdev = fdev * 10 + (*cp++ - '0');
422 cp++;
423 fino = 0;
424 while (*cp >= '0' && *cp <= '9')
425 fino = fino * 10 + (*cp++ - '0');
426 continue;
427
428 case 'J':
429 if (line[1] != '\0')
430 strlcpy(jobname, line+1, sizeof(jobname));
431 else {
432 jobname[0] = ' ';
433 jobname[1] = '\0';
434 }
435 continue;
436
437 case 'C':
438 if (line[1] != '\0')
439 strlcpy(class, line+1, sizeof(class));
440 else if (class[0] == '\0')
441 gethostname(class, sizeof(class));
442 continue;
443
444 case 'T': /* header title for pr */
445 strlcpy(title, line+1, sizeof(title));
446 continue;
447
448 case 'L': /* identification line */
449 if (!SH && !HL)
450 banner(line+1, jobname);
451 continue;
452
453 case '1': /* troff fonts */
454 case '2':
455 case '3':
456 case '4':
457 if (line[1] != '\0')
458 strlcpy(fonts[line[0]-'1'], line+1, FONTLEN50);
459 continue;
460
461 case 'W': /* page width */
462 strlcpy(width+2, line+1, sizeof(width) - 2);
463 continue;
464
465 case 'I': /* indent amount */
466 strlcpy(indent+2, line+1, sizeof(indent) - 2);
467 continue;
468
469 default: /* some file to print */
470 switch (i = print(line[0], line+1)) {
471 case ERROR-1:
472 if (bombed == OK0)
473 bombed = FATALERR1;
474 break;
475 case REPRINT-2:
476 (void)fclose(cfp);
477 return(REPRINT-2);
478 case FILTERERR3:
479 case ACCESS4:
480 bombed = i;
481 sendmail(logname, bombed);
482 }
483 title[0] = '\0';
484 continue;
485
486 case 'N':
487 case 'U':
488 case 'M':
489 case 'R':
490 continue;
491 }
492
493 /* pass 2 */
494
495pass2:
496 fseek(cfp, 0L, SEEK_SET0);
497 while (get_line(cfp))
498 switch (line[0]) {
499 case 'L': /* identification line */
500 if (!SH && HL)
501 banner(line+1, jobname);
502 continue;
503
504 case 'M':
505 if (bombed < NOACCT2) /* already sent if >= NOACCT */
506 sendmail(line+1, bombed);
507 continue;
508
509 case 'U':
510 if (strchr(line+1, '/'))
511 continue;
512 (void)unlink(line+1);
513 }
514 /*
515 * clean-up in case another control file exists
516 */
517 (void)fclose(cfp);
518 (void)unlink(file);
519 return(bombed == OK0 ? OK0 : ERROR-1);
520}
521
522/*
523 * Print a file.
524 * Set up the chain [ PR [ | {IF, OF} ] ] or {IF, RF, TF, NF, DF, CF, VF}.
525 * Return -1 if a non-recoverable error occurred,
526 * 2 if the filter detected some errors (but printed the job anyway),
527 * 1 if we should try to reprint this job and
528 * 0 if all is well.
529 * Note: all filters take stdin as the file, stdout as the printer,
530 * stderr as the log file, and must not ignore SIGINT.
531 */
532static int
533print(int format, char *file)
534{
535 ssize_t nread;
536 struct stat stb;
537 pid_t pid;
538 char *prog, *av[17], buf[BUFSIZ1024];
539 int fd, status, serrno;
540 int n, fi, fo, p[2], stopped = 0, nofile;
541
542 if (fdev != (dev_t)-1 && fino != (ino_t)-1) {
543 /* symbolic link */
544 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
545 fi = safe_open(file, O_RDONLY0x0000, 0);
546 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
547 if (fi != -1) {
548 /*
549 * The symbolic link should still point to the same file
550 * or someone is trying to print something he shouldn't.
551 */
552 if (fstat(fi, &stb) == -1 ||
553 stb.st_dev != fdev || stb.st_ino != fino) {
554 close(fi);
555 return(ACCESS4);
556 }
557 }
558 } else {
559 /* regular file */
560 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
561 fi = safe_open(file, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
562 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
563 }
564 if (fi == -1)
565 return(ERROR-1);
566 if (!SF && !tof) { /* start on a fresh page */
567 (void)write(ofd, FF, strlen(FF));
568 tof = 1;
569 }
570 if (IF == NULL((void *)0) && (format == 'f' || format == 'l' || format == 'o')) {
571 tof = 0;
572 while ((n = read(fi, buf, BUFSIZ1024)) > 0)
573 if (write(ofd, buf, n) != n) {
574 (void)close(fi);
575 return(REPRINT-2);
576 }
577 (void)close(fi);
578 return(OK0);
579 }
580 switch (format) {
581 case 'p': /* print file using 'pr' */
582 if (IF == NULL((void *)0)) { /* use output filter */
583 prog = _PATH_PR"/usr/bin/pr";
584 av[0] = "pr";
585 av[1] = width;
586 av[2] = length;
587 av[3] = "-h";
588 av[4] = *title ? title : " ";
589 av[5] = NULL((void *)0);
590 fo = ofd;
591 goto start;
592 }
593 pipe(p);
594 if ((prchild = dofork(DORETURN0)) == 0) { /* child */
595 dup2(fi, 0); /* file is stdin */
596 dup2(p[1], 1); /* pipe is stdout */
597 closelog();
598 nofile = sysconf(_SC_OPEN_MAX5);
599 for (n = 3; n < nofile; n++)
600 (void)close(n);
601 execl(_PATH_PR"/usr/bin/pr", "pr", width, length,
602 "-h", *title ? title : " ", (char *)NULL((void *)0));
603 syslog(LOG_ERR3, "cannot execl %s", _PATH_PR"/usr/bin/pr");
604 exit(2);
605 }
606 (void)close(p[1]); /* close output side */
607 (void)close(fi);
608 if (prchild < 0) {
609 prchild = 0;
610 (void)close(p[0]);
611 return(ERROR-1);
612 }
613 fi = p[0]; /* use pipe for input */
614 case 'f': /* print plain text file */
615 prog = IF;
616 av[1] = width;
617 av[2] = length;
618 av[3] = indent;
619 n = 4;
620 break;
621 case 'o': /* print postscript file */
622 /*
623 * Treat this as a "plain file with control characters", and
624 * assume the standard LPF_INPUT filter will recognize that
625 * the data is postscript and know what to do with it. These
626 * 'o'-file requests could come from MacOS 10.1 systems.
627 * (later versions of MacOS 10 will explicitly use 'l')
628 * A postscript file can contain binary data, which is why 'l'
629 * is somewhat more appropriate than 'f'.
630 */
631 /* FALLTHROUGH */
632 case 'l': /* like 'f' but pass control characters */
633 prog = IF;
634 av[1] = "-c";
635 av[2] = width;
636 av[3] = length;
637 av[4] = indent;
638 n = 5;
639 break;
640 case 'r': /* print a fortran text file */
641 prog = RF;
642 av[1] = width;
643 av[2] = length;
644 n = 3;
645 break;
646 case 't': /* print troff output */
647 case 'n': /* print ditroff output */
648 case 'd': /* print tex output */
649 (void)unlink(".railmag");
650 if ((fo = open(".railmag", O_CREAT0x0200|O_WRONLY0x0001|O_EXCL0x0800, FILMOD0660)) < 0) {
651 syslog(LOG_ERR3, "%s: cannot create .railmag", printer);
652 (void)unlink(".railmag");
653 } else {
654 for (n = 0; n < 4; n++) {
655 if (fonts[n][0] != '/')
656 (void)write(fo, _PATH_VFONT"/usr/libdata/vfont/",
657 sizeof(_PATH_VFONT"/usr/libdata/vfont/") - 1);
658 (void)write(fo, fonts[n], strlen(fonts[n]));
659 (void)write(fo, "\n", 1);
660 }
661 (void)close(fo);
662 }
663 prog = (format == 't') ? TF : (format == 'n') ? NF : DF;
664 av[1] = pxwidth;
665 av[2] = pxlength;
666 n = 3;
667 break;
668 case 'c': /* print cifplot output */
669 prog = CF;
670 av[1] = pxwidth;
671 av[2] = pxlength;
672 n = 3;
673 break;
674 case 'g': /* print plot(1G) output */
675 prog = GF;
676 av[1] = pxwidth;
677 av[2] = pxlength;
678 n = 3;
679 break;
680 case 'v': /* print raster output */
681 prog = VF;
682 av[1] = pxwidth;
683 av[2] = pxlength;
684 n = 3;
685 break;
686 default:
687 (void)close(fi);
688 syslog(LOG_ERR3, "%s: illegal format character '%c'",
689 printer, format);
690 return(ERROR-1);
691 }
692 if (prog == NULL((void *)0)) {
693 (void)close(fi);
694 syslog(LOG_ERR3,
695 "%s: no filter found in printcap for format character '%c'",
696 printer, format);
697 return(ERROR-1);
698 }
699 if ((av[0] = strrchr(prog, '/')) != NULL((void *)0))
700 av[0]++;
701 else
702 av[0] = prog;
703 av[n++] = "-n";
704 av[n++] = logname;
705 if (*jobname != '\0' && strcmp(jobname, " ") != 0) {
706 av[n++] = "-j";
707 av[n++] = jobname;
708 }
709 av[n++] = "-h";
710 av[n++] = fromhost;
711 av[n++] = AF;
712 av[n] = 0;
713 fo = pfd;
714 if (ofilter > 0) { /* stop output filter */
715 write(ofd, "\031\1", 2);
716 while ((pid = waitpid((pid_t)-1, &status, WUNTRACED2)) > 0
717 && pid != ofilter)
718 ;
719 if (WIFSTOPPED(status)(((status) & 0xff) == 0177) == 0) {
720 (void)close(fi);
721 syslog(LOG_WARNING4,
722 "%s: output filter died (retcode=%d termsig=%d)",
723 printer, WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff), WTERMSIG(status)(((status) & 0177)));
724 return(REPRINT-2);
725 }
726 stopped++;
727 }
728start:
729 if ((child = dofork(DORETURN0)) == 0) { /* child */
730 dup2(fi, 0);
731 dup2(fo, 1);
732 unlink(tempfile);
733 n = open(tempfile, O_WRONLY0x0001|O_CREAT0x0200|O_EXCL0x0800, 0664);
734 if (n >= 0)
735 dup2(n, 2);
736 closelog();
737 nofile = sysconf(_SC_OPEN_MAX5);
738 for (n = 3; n < nofile; n++)
739 (void)close(n);
740 execv(prog, av);
741 syslog(LOG_ERR3, "cannot execv %s", prog);
742 _exit(2);
743 }
744 serrno = errno(*__errno());
745 (void)close(fi);
746 errno(*__errno()) = serrno;
747 if (child < 0) {
748 child = prchild = tof = 0;
749 syslog(LOG_ERR3, "cannot start child process: %m");
750 return (ERROR-1);
751 }
752 while ((pid = wait(&status)) > 0 && pid != child)
753 ;
754 child = 0;
755 prchild = 0;
756 if (stopped) { /* restart output filter */
757 if (kill(ofilter, SIGCONT19) < 0) {
758 syslog(LOG_ERR3, "cannot restart output filter");
759 exit(1);
760 }
761 }
762 tof = 0;
763
764 /* Copy filter output to "lf" logfile */
765 fd = safe_open(tempfile, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
766 if (fd >= 0) {
767 while ((nread = read(fd, buf, sizeof(buf))) > 0)
768 (void)write(STDERR_FILENO2, buf, nread);
769 (void)close(fd);
770 }
771
772 if (!WIFEXITED(status)(((status) & 0177) == 0)) {
773 syslog(LOG_WARNING4, "%s: filter '%c' terminated (termsig=%d)",
774 printer, format, WTERMSIG(status)(((status) & 0177)));
775 return(ERROR-1);
776 }
777 switch (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff)) {
778 case 0:
779 tof = 1;
780 return(OK0);
781 case 1:
782 return(REPRINT-2);
783 case 2:
784 return(ERROR-1);
785 default:
786 syslog(LOG_WARNING4, "%s: filter '%c' exited (retcode=%d)",
787 printer, format, WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff));
788 return(FILTERERR3);
789 }
790}
791
792/*
793 * Send the daemon control file (cf) and any data files.
794 * Return -1 if a non-recoverable error occurred, 1 if a recoverable error and
795 * 0 if all is well.
796 */
797static int
798sendit(char *file)
799{
800 int fd, i, err = OK0;
801 char *cp, last[BUFSIZ1024];
802
803 /* open control file */
804 fd = safe_open(file, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
805 if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL((void *)0))
806 return(OK0);
807 /*
808 * read the control file for work to do
809 *
810 * file format -- first character in the line is a command
811 * rest of the line is the argument.
812 * commands of interest are:
813 *
814 * a-z -- "file name" name of file to print
815 * U -- "unlink" name of file to remove
816 * (after we print it. (Pass 2 only)).
817 */
818
819 /*
820 * pass 1
821 */
822 while (get_line(cfp)) {
823 again:
824 if (line[0] == 'S') {
825 cp = line+1;
826 fdev = 0;
827 while (*cp >= '0' && *cp <= '9')
828 fdev = fdev * 10 + (*cp++ - '0');
829 cp++;
830 fino = 0;
831 while (*cp >= '0' && *cp <= '9')
832 fino = fino * 10 + (*cp++ - '0');
833 continue;
834 }
835 if (line[0] >= 'a' && line[0] <= 'z') {
836 strlcpy(last, line, sizeof(last));
837 while ((i = get_line(cfp)) != 0)
838 if (strcmp(last, line))
839 break;
840 switch (sendfile('\3', last+1)) {
841 case OK0:
842 if (i)
843 goto again;
844 break;
845 case REPRINT-2:
846 (void)fclose(cfp);
847 return(REPRINT-2);
848 case ACCESS4:
849 sendmail(logname, ACCESS4);
850 case ERROR-1:
851 err = ERROR-1;
852 }
853 break;
854 }
855 }
856 if (err == OK0 && sendfile('\2', file) > 0) {
857 (void)fclose(cfp);
858 return(REPRINT-2);
859 }
860 /*
861 * pass 2
862 */
863 fseek(cfp, 0L, SEEK_SET0);
864 while (get_line(cfp))
865 if (line[0] == 'U' && strchr(line+1, '/') == 0)
866 (void)unlink(line+1);
867 /*
868 * clean-up in case another control file exists
869 */
870 (void)fclose(cfp);
871 (void)unlink(file);
872 return(err);
873}
874
875/*
876 * Send a data file to the remote machine and spool it.
877 * Return positive if we should try resending.
878 */
879static int
880sendfile(int type, char *file)
881{
882 int f, i, amt;
883 struct stat stb;
884 char buf[BUFSIZ1024];
885 int sizerr, resp;
886
887 if (fdev != (dev_t)-1 && fino != (ino_t)-1) {
888 /* symbolic link */
889 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
890 f = safe_open(file, O_RDONLY0x0000, 0);
891 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
892 if (f != -1) {
893 /*
894 * The symbolic link should still point to the same file
895 * or someone is trying to print something he shouldn't.
896 */
897 if (fstat(f, &stb) == -1 ||
898 stb.st_dev != fdev || stb.st_ino != fino) {
899 close(f);
900 return(ACCESS4);
901 }
902 }
903 } else {
904 /* regular file */
905 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
906 f = safe_open(file, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
907 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
908 if (fstat(f, &stb) == -1) {
909 close(f);
910 f = -1;
911 }
912 }
913 if (f == -1)
914 return(ERROR-1);
915 if ((amt = snprintf(buf, sizeof(buf), "%c%lld %s\n", type,
916 (long long)stb.st_size, file)) < 0 || amt >= sizeof(buf))
917 return (ACCESS4); /* XXX hack */
918 for (i = 0; ; i++) {
919 if (write(pfd, buf, amt) != amt ||
920 (resp = response()) < 0 || resp == '\1') {
921 (void)close(f);
922 return(REPRINT-2);
923 } else if (resp == '\0')
924 break;
925 if (i == 0)
926 pstatus("no space on remote; waiting for queue to drain");
927 if (i == 10)
928 syslog(LOG_ALERT1, "%s: can't send to %s; queue full",
929 printer, RM);
930 sleep(5 * 60);
931 }
932 if (i)
933 pstatus("sending to %s", RM);
934 sizerr = 0;
935 for (i = 0; i < stb.st_size; i += BUFSIZ1024) {
936 struct sigaction osa, nsa;
937
938 amt = BUFSIZ1024;
939 if (i + amt > stb.st_size)
940 amt = stb.st_size - i;
941 if (sizerr == 0 && read(f, buf, amt) != amt)
942 sizerr = 1;
943 memset(&nsa, 0, sizeof(nsa));
944 nsa.sa_handler__sigaction_u.__sa_handler = alarmer;
945 sigemptyset(&nsa.sa_mask);
946 nsa.sa_flags = 0;
947 (void)sigaction(SIGALRM14, &nsa, &osa);
948 alarm(wait_time);
949 if (write(pfd, buf, amt) != amt) {
950 alarm(0);
951 (void)sigaction(SIGALRM14, &osa, NULL((void *)0));
952 (void)close(f);
953 return(REPRINT-2);
954 }
955 alarm(0);
956 (void)sigaction(SIGALRM14, &osa, NULL((void *)0));
957 }
958
959 (void)close(f);
960 if (sizerr) {
961 syslog(LOG_INFO6, "%s: %s: changed size", printer, file);
962 /* tell recvjob to ignore this file */
963 (void)write(pfd, "\1", 1);
964 return(ERROR-1);
965 }
966 if (write(pfd, "", 1) != 1 || response())
967 return(REPRINT-2);
968 return(OK0);
969}
970
971/*
972 * Check to make sure there have been no errors and that both programs
973 * are in sync with eachother.
974 * Return non-zero if the connection was lost.
975 */
976static char
977response(void)
978{
979 struct sigaction osa, nsa;
980 char resp;
981
982 memset(&nsa, 0, sizeof(nsa));
983 nsa.sa_handler__sigaction_u.__sa_handler = alarmer;
984 sigemptyset(&nsa.sa_mask);
985 nsa.sa_flags = 0;
986 (void)sigaction(SIGALRM14, &nsa, &osa);
987 alarm(wait_time);
988 if (read(pfd, &resp, 1) != 1) {
989 syslog(LOG_INFO6, "%s: lost connection", printer);
990 resp = -1;
991 }
992 alarm(0);
993 (void)sigaction(SIGALRM14, &osa, NULL((void *)0));
994 return (resp);
995}
996
997/*
998 * Banner printing stuff
999 */
1000static void
1001banner(char *name1, char *name2)
1002{
1003 time_t tvec;
1004
1005 time(&tvec);
1006 if (!SF && !tof)
1007 (void)write(ofd, FF, strlen(FF));
1008 if (SB) { /* short banner only */
1009 if (class[0]) {
1010 (void)write(ofd, class, strlen(class));
1011 (void)write(ofd, ":", 1);
1012 }
1013 (void)write(ofd, name1, strlen(name1));
1014 (void)write(ofd, " Job: ", 7);
1015 (void)write(ofd, name2, strlen(name2));
1016 (void)write(ofd, " Date: ", 8);
1017 (void)write(ofd, ctime(&tvec), 24);
1018 (void)write(ofd, "\n", 1);
1019 } else { /* normal banner */
1020 (void)write(ofd, "\n\n\n", 3);
1021 scan_out(ofd, name1, '\0');
1022 (void)write(ofd, "\n\n", 2);
1023 scan_out(ofd, name2, '\0');
1024 if (class[0]) {
1025 (void)write(ofd, "\n\n\n", 3);
1026 scan_out(ofd, class, '\0');
1027 }
1028 (void)write(ofd, "\n\n\n\n\t\t\t\t\tJob: ", 15);
1029 (void)write(ofd, name2, strlen(name2));
1030 (void)write(ofd, "\n\t\t\t\t\tDate: ", 12);
1031 (void)write(ofd, ctime(&tvec), 24);
1032 (void)write(ofd, "\n", 1);
1033 }
1034 if (!SF)
1035 (void)write(ofd, FF, strlen(FF));
1036 tof = 1;
1037}
1038
1039static char *
1040scnline(int key, char *p, int c)
1041{
1042 int scnwidth;
1043
1044 for (scnwidth = WIDTH8; --scnwidth;) {
1045 key <<= 1;
1046 *p++ = key & 0200 ? c : BACKGND' ';
1047 }
1048 return (p);
1049}
1050
1051#define TRC(q)(((q)-' ')&0177) (((q)-' ')&0177)
1052
1053static void
1054scan_out(int scfd, char *scsp, int dlm)
1055{
1056 char *strp;
1057 int nchrs, j;
1058 char outbuf[LINELEN132+1], *sp, c, cc;
1059 int d, scnhgt;
1060 extern char scnkey[][HEIGHT9]; /* in lpdchar.c */
1061
1062 for (scnhgt = 0; scnhgt++ < HEIGHT9+DROP3; ) {
1063 strp = &outbuf[0];
1064 sp = scsp;
1065 for (nchrs = 0; ; ) {
1066 d = dropit(c = TRC(cc = *sp++)(((cc = *sp++)-' ')&0177));
1067 if ((!d && scnhgt > HEIGHT9) || (scnhgt <= DROP3 && d))
1068 for (j = WIDTH8; --j;)
1069 *strp++ = BACKGND' ';
1070 else
1071 strp = scnline(scnkey[(int)c][scnhgt-1-d],
1072 strp, cc);
1073 if (*sp == dlm || *sp == '\0' ||
1074 nchrs++ >= PW/(WIDTH8+1)-1)
1075 break;
1076 *strp++ = BACKGND' ';
1077 *strp++ = BACKGND' ';
1078 }
1079 while (*--strp == BACKGND' ' && strp >= outbuf)
1080 ;
1081 strp++;
1082 *strp++ = '\n';
1083 (void)write(scfd, outbuf, strp-outbuf);
1084 }
1085}
1086
1087static int
1088dropit(int c)
1089{
1090 switch(c) {
1091
1092 case TRC('_')((('_')-' ')&0177):
1093 case TRC(';')(((';')-' ')&0177):
1094 case TRC(',')(((',')-' ')&0177):
1095 case TRC('g')((('g')-' ')&0177):
1096 case TRC('j')((('j')-' ')&0177):
1097 case TRC('p')((('p')-' ')&0177):
1098 case TRC('q')((('q')-' ')&0177):
1099 case TRC('y')((('y')-' ')&0177):
1100 return (DROP3);
1101
1102 default:
1103 return (0);
1104 }
1105}
1106
1107/*
1108 * sendmail ---
1109 * tell people about job completion
1110 */
1111static void
1112sendmail(char *user, int bombed)
1113{
1114 int i, p[2], s, nofile;
1115 char *cp = NULL((void *)0);
1116 struct stat stb;
1117 FILE *fp;
1118
1119 if (user[0] == '-' || user[0] == '/' || !isprint((unsigned char)user[0]))
1120 return;
1121 pipe(p);
1122 if ((s = dofork(DORETURN0)) == 0) { /* child */
1123 dup2(p[0], 0);
1124 closelog();
1125 nofile = sysconf(_SC_OPEN_MAX5);
1126 for (i = 3; i < nofile; i++)
1127 (void)close(i);
1128 if ((cp = strrchr(_PATH_SENDMAIL"/usr/sbin/sendmail", '/')) != NULL((void *)0))
1129 cp++;
1130 else
1131 cp = _PATH_SENDMAIL"/usr/sbin/sendmail";
1132 execl(_PATH_SENDMAIL"/usr/sbin/sendmail", cp, "-t", (char *)NULL((void *)0));
1133 _exit(0);
1134 } else if (s > 0) { /* parent */
1135 dup2(p[1], 1);
1136 printf("Auto-Submitted: auto-generated\n");
1137 printf("To: %s@%s\n", user, fromhost);
1138 printf("Subject: %s printer job \"%s\"\n", printer,
1139 *jobname ? jobname : "<unknown>");
1140 printf("Reply-To: root@%s\n\n", host);
1141 printf("Your printer job ");
1142 if (*jobname)
1143 printf("(%s) ", jobname);
1144 switch (bombed) {
1145 case OK0:
1146 printf("\ncompleted successfully\n");
1147 cp = "OK";
1148 break;
1149 default:
1150 case FATALERR1:
1151 printf("\ncould not be printed\n");
1152 cp = "FATALERR";
1153 break;
1154 case NOACCT2:
1155 printf("\ncould not be printed without an account on %s\n", host);
1156 cp = "NOACCT";
1157 break;
1158 case FILTERERR3:
1159 cp = "FILTERERR";
1160 if (stat(tempfile, &stb) < 0 || stb.st_size == 0 ||
1161 (fp = fopen(tempfile, "r")) == NULL((void *)0)) {
1162 printf("\nhad some errors and may not have printed\n");
1163 break;
1164 }
1165 printf("\nhad the following errors and may not have printed:\n");
1166 while ((i = getc(fp)(!__isthreaded ? (--(fp)->_r < 0 ? __srget(fp) : (int)(
*(fp)->_p++)) : (getc)(fp))
) != EOF(-1))
1167 putchar(i)(!__isthreaded ? __sputc(i, (&__sF[1])) : (putc)(i, (&
__sF[1])))
;
1168 (void)fclose(fp);
1169 break;
1170 case ACCESS4:
1171 printf("\nwas not printed because it was not linked to the original file\n");
1172 cp = "ACCESS";
1173 }
1174 fflush(stdout(&__sF[1]));
1175 (void)close(1);
1176 } else {
1177 syslog(LOG_ERR3, "fork for sendmail failed: %m");
1178 }
1179 (void)close(p[0]);
1180 (void)close(p[1]);
1181 if (s != -1) {
1182 wait(NULL((void *)0));
1183 syslog(LOG_INFO6,
1184 "mail sent to user %s about job %s on printer %s (%s)",
1185 user, *jobname ? jobname : "<unknown>", printer, cp);
1186 }
1187}
1188
1189/* sleep n milliseconds */
1190static void
1191delay(int n)
1192{
1193 struct timespec tdelay;
1194
1195 if (n <= 0 || n > 10000)
1196 fatal("unreasonable delay period (%d)", n);
1197 tdelay.tv_sec = n / 1000;
1198 tdelay.tv_nsec = n * 1000000 % 1000000000;
1199 nanosleep(&tdelay, NULL((void *)0));
1200}
1201
1202/*
1203 * dofork - fork with retries on failure
1204 */
1205static pid_t
1206dofork(int action)
1207{
1208 struct passwd *pw;
1209 pid_t pid;
1210 int i;
1211
1212 for (i = 0; i < 20; i++) {
1213 if ((pid = fork()) < 0) {
1214 sleep((unsigned)(i*i));
1215 continue;
1216 }
1217 /*
1218 * Child should run as daemon instead of root
1219 */
1220 if (pid == 0) {
1221 (void)close(lfd);
1222 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1223 pw = getpwuid(DU);
1224 if (pw == 0) {
1225 syslog(LOG_ERR3, "uid %ld not in password file",
1226 DU);
1227 break;
1228 }
1229 initgroups(pw->pw_name, pw->pw_gid);
1230 setgid(pw->pw_gid);
1231 setlogin("");
1232 setuid(DU);
1233 }
1234 return (pid);
1235 }
1236 syslog(LOG_ERR3, "can't fork");
1237
1238 switch (action) {
1239 case DORETURN0:
1240 return (-1);
1241 default:
1242 syslog(LOG_ERR3, "bad action (%d) to dofork", action);
1243 /*FALL THRU*/
1244 case DOABORT1:
1245 exit(1);
1246 }
1247 /*NOTREACHED*/
1248}
1249
1250/*
1251 * Kill child processes to abort current job.
1252 */
1253static void
1254abortpr(int signo)
1255{
1256 (void)close(lfd);
1257 (void)unlink(tempfile);
1258 (void)kill(0, SIGINT2);
1259 if (ofilter > 0)
1260 kill(ofilter, SIGCONT19);
1261 while (wait(NULL((void *)0)) > 0)
1262 ;
1263 _exit(0);
1264}
1265
1266static void
1267init(void)
1268{
1269 int status;
1270 char *s;
1271
1272 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1273 status = cgetent(&bp, printcapdb, printer);
1274 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
1275
1276 switch (status) {
1277 case -1:
1278 syslog(LOG_ERR3, "unknown printer: %s", printer);
1279 exit(1);
1280 case -2:
1281 syslog(LOG_ERR3, "can't open printer description file");
1282 exit(1);
1283 case -3:
1284 fatal("potential reference loop detected in printcap file");
1285 default:
1286 break;
1287 }
1288
1289 if (cgetstr(bp, DEFLP"lp", &LP) == -1)
1290 LP = _PATH_DEFDEVLP"/dev/lp";
1291 if (cgetstr(bp, "rp", &RP) == -1)
1292 RP = DEFLP"lp";
1293 if (cgetstr(bp, "lo", &LO) == -1)
1294 LO = DEFLOCK"lock";
1295 if (cgetstr(bp, "st", &ST) == -1)
1296 ST = DEFSTAT"status";
1297 if (cgetstr(bp, "lf", &LF) == -1)
1298 LF = _PATH_CONSOLE"/dev/console";
1299 if (cgetstr(bp, "sd", &SD) == -1)
1300 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
1301 if (cgetnum(bp, "du", &DU) < 0)
1302 DU = DEFUID1;
1303 if (cgetstr(bp, "ff", &FF) == -1)
1304 FF = DEFFF"\f";
1305 if (cgetnum(bp, "pw", &PW) < 0)
1306 PW = DEFWIDTH132;
1307 (void)snprintf(&width[2], sizeof(width) - 2, "%ld", PW);
1308 if (cgetnum(bp, "pl", &PL) < 0)
1309 PL = DEFLENGTH66;
1310 (void)snprintf(&length[2], sizeof(length) - 2, "%ld", PL);
1311 if (cgetnum(bp, "px", &PX) < 0)
1312 PX = 0;
1313 (void)snprintf(&pxwidth[2], sizeof(pxwidth) - 2, "%ld", PX);
1314 if (cgetnum(bp, "py", &PY) < 0)
1315 PY = 0;
1316 (void)snprintf(&pxlength[2], sizeof(pxlength) - 2, "%ld", PY);
1317 cgetstr(bp, "rm", &RM);
1318 if ((s = checkremote()) != NULL((void *)0))
1319 syslog(LOG_WARNING4, "%s", s);
1320
1321 cgetstr(bp, "af", &AF);
1322 cgetstr(bp, "of", &OF);
1323 cgetstr(bp, "if", &IF);
1324 cgetstr(bp, "rf", &RF);
1325 cgetstr(bp, "tf", &TF);
1326 cgetstr(bp, "nf", &NF);
1327 cgetstr(bp, "df", &DF);
1328 cgetstr(bp, "gf", &GF);
1329 cgetstr(bp, "vf", &VF);
1330 cgetstr(bp, "cf", &CF);
1331 cgetstr(bp, "tr", &TR);
1332
1333 RS = (cgetcap(bp, "rs", ':') != NULL((void *)0));
1334 SF = (cgetcap(bp, "sf", ':') != NULL((void *)0));
1335 SH = (cgetcap(bp, "sh", ':') != NULL((void *)0));
1336 SB = (cgetcap(bp, "sb", ':') != NULL((void *)0));
1337 HL = (cgetcap(bp, "hl", ':') != NULL((void *)0));
1338 RW = (cgetcap(bp, "rw", ':') != NULL((void *)0));
1339
1340 cgetnum(bp, "br", &BR);
1341 cgetstr(bp, "ms", &MS);
1342
1343 tof = (cgetcap(bp, "fo", ':') == NULL((void *)0));
1344}
1345
1346/*
1347 * Acquire line printer or remote connection.
1348 * XXX - should push down privs in here
1349 */
1350static void
1351openpr(void)
1352{
1353 int i, nofile;
1354 char *cp;
1355 extern int rflag;
1356
1357 if (!remote && *LP) {
25
Assuming 'remote' is 0
26
Assuming the condition is true
27
Taking true branch
1358 if ((cp = strchr(LP, '@')))
28
Assuming 'cp' is null
29
Taking false branch
1359 opennet(cp);
1360 else
1361 opentty();
30
Calling 'opentty'
1362 } else if (remote) {
1363 openrem();
1364 } else {
1365 syslog(LOG_ERR3, "%s: no line printer device or host name",
1366 printer);
1367 exit(1);
1368 }
1369
1370 /*
1371 * Start up an output filter, if needed.
1372 */
1373 if ((!remote || rflag) && OF) {
1374 int p[2];
1375
1376 pipe(p);
1377 if ((ofilter = dofork(DOABORT1)) == 0) { /* child */
1378 dup2(p[0], 0); /* pipe is std in */
1379 dup2(pfd, 1); /* printer is std out */
1380 closelog();
1381 nofile = sysconf(_SC_OPEN_MAX5);
1382 for (i = 3; i < nofile; i++)
1383 (void)close(i);
1384 if ((cp = strrchr(OF, '/')) == NULL((void *)0))
1385 cp = OF;
1386 else
1387 cp++;
1388 execl(OF, cp, width, length, (char *)NULL((void *)0));
1389 syslog(LOG_ERR3, "%s: %s: %m", printer, OF);
1390 exit(1);
1391 }
1392 (void)close(p[0]); /* close input side */
1393 ofd = p[1]; /* use pipe for output */
1394 } else {
1395 ofd = pfd;
1396 ofilter = 0;
1397 }
1398}
1399
1400/*
1401 * Printer connected directly to the network
1402 * or to a terminal server on the net
1403 */
1404static void
1405opennet(char *cp)
1406{
1407 int i;
1408 int resp, port;
1409 char save_ch;
1410
1411 save_ch = *cp;
1412 *cp = '\0';
1413 port = atoi(LP);
1414 if (port <= 0) {
1415 syslog(LOG_ERR3, "%s: bad port number: %s", printer, LP);
1416 exit(1);
1417 }
1418 *cp++ = save_ch;
1419
1420 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1421 resp = -1;
1422 pfd = getport(cp, port);
1423 if (pfd < 0 && errno(*__errno()) == ECONNREFUSED61)
1424 resp = 1;
1425 else if (pfd >= 0) {
1426 /*
1427 * need to delay a bit for rs232 lines
1428 * to stabilize in case printer is
1429 * connected via a terminal server
1430 */
1431 delay(500);
1432 break;
1433 }
1434 if (i == 1) {
1435 if (resp < 0)
1436 pstatus("waiting for %s to come up", LP);
1437 else
1438 pstatus("waiting for access to printer on %s", LP);
1439 }
1440 sleep(i);
1441 }
1442 pstatus("sending to %s port %d", cp, port);
1443}
1444
1445/*
1446 * Printer is connected to an RS232 port on this host
1447 */
1448static void
1449opentty(void)
1450{
1451 int i;
1452
1453 for (i = 1; ; i = i < 32 ? i << 1 : i) {
31
Loop condition is true. Entering loop body
1454 pfd = open(LP, RW ? O_RDWR0x0002 : O_WRONLY0x0001);
32
Assuming 'RW' is 0
33
'?' condition is false
1455 if (pfd >= 0) {
34
Assuming 'pfd' is >= 0
35
Taking true branch
1456 delay(500);
1457 break;
36
Execution continues on line 1468
1458 }
1459 if (errno(*__errno()) == ENOENT2) {
1460 syslog(LOG_ERR3, "%s: %m", LP);
1461 exit(1);
1462 }
1463 if (i == 1)
1464 pstatus("waiting for %s to become ready (offline ?)",
1465 printer);
1466 sleep(i);
1467 }
1468 if (isatty(pfd))
37
Assuming the condition is true
38
Taking true branch
1469 setty();
39
Calling 'setty'
1470 pstatus("%s is ready and printing", printer);
1471}
1472
1473/*
1474 * Printer is on a remote host
1475 */
1476static void
1477openrem(void)
1478{
1479 int i, n;
1480 int resp;
1481
1482 for (i = 1; ; i = i < 256 ? i << 1 : i) {
1483 resp = -1;
1484 pfd = getport(RM, 0);
1485 if (pfd >= 0) {
1486 if ((n = snprintf(line, sizeof(line), "\2%s\n", RP)) < 0 ||
1487 n >= sizeof(line))
1488 n = sizeof(line) - 1;
1489 if (write(pfd, line, n) == n &&
1490 (resp = response()) == '\0')
1491 break;
1492 (void)close(pfd);
1493 }
1494 if (i == 1) {
1495 if (resp < 0)
1496 pstatus("waiting for %s to come up", RM);
1497 else {
1498 pstatus("waiting for queue to be enabled on %s",
1499 RM);
1500 i = 256;
1501 }
1502 }
1503 sleep(i);
1504 }
1505 pstatus("sending to %s", RM);
1506}
1507
1508static void
1509alarmer(int s)
1510{
1511 /* nothing */
1512}
1513
1514/*
1515 * setup tty lines.
1516 */
1517static void
1518setty(void)
1519{
1520 struct info i;
1521 char **argv, **ap, **ep, *p, *val;
1522
1523 i.fd = pfd;
1524 i.set = i.wset = 0;
1525 if (ioctl(i.fd, TIOCEXCL((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) |
((('t')) << 8) | ((13)))
, (char *)0) < 0
) {
40
Assuming the condition is false
41
Taking false branch
1526 syslog(LOG_ERR3, "%s: ioctl(TIOCEXCL): %m", printer);
1527 exit(1);
1528 }
1529 if (tcgetattr(i.fd, &i.t) < 0) {
42
Assuming the condition is false
43
Taking false branch
1530 syslog(LOG_ERR3, "%s: tcgetattr: %m", printer);
1531 exit(1);
1532 }
1533 if (BR > 0) {
44
Assuming 'BR' is <= 0
45
Taking false branch
1534 cfsetspeed(&i.t, BR);
1535 i.set = 1;
1536 }
1537 if (MS) {
46
Assuming 'MS' is non-null
47
Taking true branch
1538 if (ioctl(i.fd, TIOCGETD((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('t')) << 8) | ((26)))
, &i.ldisc) < 0
) {
48
Assuming the condition is false
49
Taking false branch
1539 syslog(LOG_ERR3, "%s: ioctl(TIOCGETD): %m", printer);
1540 exit(1);
1541 }
1542 if (ioctl(i.fd, TIOCGWINSZ((unsigned long)0x40000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((104)))
, &i.win) < 0
)
50
Assuming the condition is false
51
Taking false branch
1543 syslog(LOG_INFO6, "%s: ioctl(TIOCGWINSZ): %m",
1544 printer);
1545
1546 argv = calloc(256, sizeof(char *));
1547 if (argv == NULL((void *)0)) {
52
Assuming 'argv' is not equal to NULL
53
Taking false branch
1548 syslog(LOG_ERR3, "%s: malloc: %m", printer);
1549 exit(1);
1550 }
1551 p = strdup(MS);
54
Memory is allocated
1552 ap = argv;
1553 ep = argv + 255;
1554 while ((val = strsep(&p, " \t,")) != NULL((void *)0)) {
55
Assuming the condition is true
56
Loop condition is true. Entering loop body
60
Assuming the condition is false
61
Loop condition is false. Execution continues on line 1565
1555 if ((*ap++ = strdup(val)) == NULL((void *)0)) {
57
Assuming the condition is false
58
Taking false branch
1556 syslog(LOG_ERR3, "%s: strdup: %m", printer);
1557 exit(1);
1558 }
1559 if (ap
58.1
'ap' is not equal to 'ep'
== ep) {
59
Taking false branch
1560 syslog(LOG_ERR3, "%s: too many \"ms\" entries",
1561 printer);
1562 exit(1);
1563 }
1564 }
1565 *ap = NULL((void *)0);
62
Potential leak of memory pointed to by 'val'
1566
1567 for (; *argv; ++argv) {
1568 if (ksearch(&argv, &i))
1569 continue;
1570 if (msearch(&argv, &i))
1571 continue;
1572 syslog(LOG_INFO6, "%s: unknown stty flag: %s",
1573 printer, *argv);
1574 }
1575 }
1576
1577 if (i.set && tcsetattr(i.fd, TCSANOW0, &i.t) < 0) {
1578 syslog(LOG_ERR3, "%s: tcsetattr: %m", printer);
1579 exit(1);
1580 }
1581 if (i.wset && ioctl(i.fd, TIOCSWINSZ((unsigned long)0x80000000 | ((sizeof(struct winsize) & 0x1fff
) << 16) | ((('t')) << 8) | ((103)))
, &i.win) < 0)
1582 syslog(LOG_INFO6, "%s: ioctl(TIOCSWINSZ): %m", printer);
1583 return;
1584}
1585
1586static void
1587pstatus(const char *msg, ...)
1588{
1589 int fd, len;
1590 char buf[BUFSIZ1024];
1591 va_list ap;
1592
1593 va_start(ap, msg)__builtin_va_start(ap, msg);
1594 umask(0);
1595 fd = open(ST, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100|O_EXLOCK0x0020, 0660);
1596 if (fd < 0) {
1597 syslog(LOG_ERR3, "%s: %s: %m", printer, ST);
1598 exit(1);
1599 }
1600 ftruncate(fd, 0);
1601 len = vsnprintf(buf, sizeof(buf), msg, ap);
1602 va_end(ap)__builtin_va_end(ap);
1603 if (len < 0) {
1604 (void)close(fd);
1605 return;
1606 }
1607 if (len >= sizeof(buf))
1608 len = sizeof(buf) - 1;
1609 buf[len++] = '\n'; /* replace NUL with newline */
1610 (void)write(fd, buf, len);
1611 (void)close(fd);
1612}