2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) 1983, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 static const char copyright[] =
44 "@(#) Copyright (c) 1983, 1989, 1993\n\
45 The Regents of the University of California. All rights reserved.\n";
50 static char sccsid[] = "@(#)lpr.c 8.4 (Berkeley) 4/28/95";
54 #include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
55 __FBSDID("$FreeBSD$");
58 * lpr -- off line print
60 * Allows multiple printers and printers on remote machines by
61 * using information from a printer data base.
64 #include <sys/param.h>
67 #include <netinet/in.h> /* N_BADMAG uses ntohl() */
86 #include "pathnames.h"
88 static char *cfname; /* daemon control files, linked from tf's */
89 static char *class = local_host; /* class title on header page */
90 static char *dfname; /* data files */
91 static char *fonts[4]; /* troff font names */
92 static char format = 'f'; /* format char for printing files */
93 static int hdr = 1; /* print header or not (default is yes) */
94 static int iflag; /* indentation wanted */
95 static int inchar; /* location to increment char in file names */
96 static int indent; /* amount to indent */
97 static const char *jobname; /* job name on header page */
98 static int mailflg; /* send mail */
99 static int nact; /* number of jobs to act on */
100 static int ncopies = 1; /* # of copies to make */
101 static char *lpr_username; /* person sending the print job(s) */
102 static int qflag; /* q job, but don't exec daemon */
103 static int rflag; /* remove files upon completion */
104 static int sflag; /* symbolic link flag */
105 static int tfd; /* control file descriptor */
106 static char *tfname; /* tmp copy of cf before linking */
107 static char *title; /* pr'ing title */
108 static char *locale; /* pr'ing locale */
109 static int userid; /* user id */
110 static char *Uflag; /* user name specified with -U flag */
111 static char *width; /* width for versatec printing */
112 static char *Zflag; /* extra filter options for LPRng servers */
114 static struct stat statb;
116 static void card(int _c, const char *_p2);
117 static int checkwriteperm(const char *_file, const char *_directory);
118 static void chkprinter(const char *_ptrname, struct printer *_pp);
119 static void cleanup(int _signo);
120 static void copy(const struct printer *_pp, int _f, const char _n[]);
121 static char *itoa(int _i);
122 static const char *linked(const char *_file);
123 int main(int _argc, char *_argv[]);
124 static char *lmktemp(const struct printer *_pp, const char *_id,
126 static void mktemps(const struct printer *_pp);
127 static int nfile(char *_n);
128 static int test(const char *_file);
129 static void usage(void);
134 main(int argc, char *argv[])
138 const char *arg, *cp, *printer;
144 struct stat statb1, statb2;
145 struct printer myprinter, *pp = &myprinter;
151 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
152 signal(SIGHUP, cleanup);
153 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
154 signal(SIGINT, cleanup);
155 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
156 signal(SIGQUIT, cleanup);
157 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
158 signal(SIGTERM, cleanup);
161 gethostname(local_host, sizeof(local_host));
162 openlog("lpd", 0, LOG_LPR);
165 while ((c = getopt(argc, argv,
166 ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:"))
169 case '#': /* n copies */
170 i = strtol(optarg, &p, 10);
172 errx(1, "Bad argument to -#, number expected");
177 case '1': /* troff fonts */
181 fonts[optopt - '1'] = optarg;
184 case 'C': /* classification spec */
189 case 'J': /* job name */
194 case 'P': /* specifiy printer name */
198 case 'L': /* pr's locale */
202 case 'T': /* pr's title line */
206 case 'U': /* user name */
215 case 'c': /* print cifplot output */
216 case 'd': /* print tex output (dvi files) */
217 case 'g': /* print graph(1G) output */
218 case 'l': /* literal output */
219 case 'n': /* print ditroff output */
220 case 't': /* print troff output (cat files) */
221 case 'p': /* print using ``pr'' */
222 case 'v': /* print vplot output */
226 case 'f': /* print fortran output */
230 case 'h': /* nulifiy header page */
234 case 'i': /* indent output */
236 indent = strtol(optarg, &p, 10);
238 errx(1, "Bad argument to -i, number expected");
241 case 'm': /* send mail when done */
245 case 'q': /* just queue job */
249 case 'r': /* remove file when done */
253 case 's': /* try to link files */
257 case 'w': /* versatec page width */
261 case ':': /* catch "missing argument" error */
263 iflag++; /* -i without args is valid */
276 if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
278 chkprinter(printer, pp);
279 if (pp->no_copies && ncopies > 1)
280 errx(1, "multiple copies are not allowed");
281 if (pp->max_copies > 0 && ncopies > pp->max_copies)
282 errx(1, "only %ld copies are allowed", pp->max_copies);
284 * Get the identity of the person doing the lpr using the same
285 * algorithm as lprm. Actually, not quite -- lprm will override
286 * the login name with "root" if the user is running as root;
287 * the daemon actually checks for the string "root" in its
288 * permission checking. Sigh.
292 if (userid != 0 && userid != pp->daemon_user)
293 errx(1, "only privileged users may use the `-U' flag");
294 lpr_username = Uflag; /* -U person doing 'lpr' */
296 lpr_username = getlogin(); /* person doing 'lpr' */
297 if (userid != pp->daemon_user || lpr_username == 0) {
298 if ((pw = getpwuid(userid)) == NULL)
299 errx(1, "Who are you?");
300 lpr_username = pw->pw_name;
305 * Check for restricted group access.
307 if (pp->restrict_grp != NULL && userid != pp->daemon_user) {
308 if ((gptr = getgrnam(pp->restrict_grp)) == NULL)
309 errx(1, "Restricted group specified incorrectly");
310 if (gptr->gr_gid != getgid()) {
311 while (*gptr->gr_mem != NULL) {
312 if ((strcmp(lpr_username, *gptr->gr_mem)) == 0)
316 if (*gptr->gr_mem == NULL)
317 errx(1, "Not a member of the restricted group");
321 * Check to make sure queuing is enabled if userid is not root.
323 lock_file_name(pp, buf, sizeof buf);
324 if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS))
325 errx(1, "Printer queue is disabled");
327 * Initialize the control file.
332 (void) fchown(tfd, pp->daemon_user, -1);
333 /* owned by daemon for protection */
335 card('H', local_host);
336 card('P', lpr_username);
338 if (hdr && !pp->no_header) {
339 if (jobname == NULL) {
343 jobname = ((arg = strrchr(argv[0], '/'))
344 ? arg + 1 : argv[0]);
347 card('L', lpr_username);
349 if (format != 'p' && Zflag != 0)
352 card('I', itoa(indent));
354 card('M', lpr_username);
355 if (format == 't' || format == 'n' || format == 'd')
356 for (i = 0; i < 4; i++)
357 if (fonts[i] != NULL)
358 card('1'+i, fonts[i]);
363 * Our use of `Z' here is incompatible with LPRng's
364 * use. We assume that the only use of our existing
365 * `Z' card is as shown for `p' format (pr) files.
372 else if ((s = setlocale(LC_TIME, "")) != NULL)
377 * Read the files and spool them.
381 else while (argc--) {
382 if (argv[0][0] == '-' && argv[0][1] == '\0') {
388 if ((f = test(arg = *argv++)) < 0)
389 continue; /* file unreasonable */
391 if (sflag && (cp = linked(arg)) != NULL) {
392 (void)snprintf(buf, sizeof(buf), "%ju %ju",
393 (uintmax_t)statb.st_dev, (uintmax_t)statb.st_ino);
396 card('T', title ? title : arg);
397 for (i = 0; i < ncopies; i++)
398 card(format, &dfname[inchar-2]);
399 card('U', &dfname[inchar-2]);
408 printf("%s: %s: not linked, copying instead\n",
413 * The user wants the file removed after it is copied
414 * to the spool area, so see if the file can be moved
415 * instead of copy/unlink'ed. This is much faster and
416 * uses less spool space than copying the file. This
417 * can be very significant when running services like
418 * samba, pcnfs, CAP, et al.
423 * There are several things to check to avoid any
424 * security issues. Some of these are redundant
425 * under BSD's, but are necessary when lpr is built
426 * under some other OS's (which I do do...)
428 if (lstat(arg, &statb1) < 0)
430 if (S_ISLNK(statb1.st_mode))
432 if (link(arg, dfname) != 0)
436 * Make sure the user hasn't tried to trick us via
437 * any race conditions
439 if (lstat(dfname, &statb2) < 0)
441 if (statb1.st_dev != statb2.st_dev)
443 if (statb1.st_ino != statb2.st_ino)
446 * Skip if the file already had multiple hard links,
447 * because changing the owner and access-bits would
448 * change ALL versions of the file
450 if (statb2.st_nlink > 2)
453 * If we can access and remove the original file
454 * without special setuid-ness then this method is
455 * safe. Otherwise, abandon the move and fall back
456 * to the (usual) copy method.
459 ret = access(dfname, R_OK);
466 * Unlink of user file was successful. Change the
467 * owner and permissions, add entries to the control
468 * file, and skip the file copying step.
470 chown(dfname, pp->daemon_user, getegid());
471 chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
474 card('T', title ? title : arg);
475 for (i = 0; i < ncopies; i++)
476 card(format, &dfname[inchar-2]);
477 card('U', &dfname[inchar-2]);
484 PRIV_END /* restore old uid */
487 if ((i = open(arg, O_RDONLY)) < 0) {
488 printf("%s: cannot open %s\n", progname, arg);
492 if (f && unlink(arg) < 0)
493 printf("%s: %s: not removed\n", progname, arg);
501 * Touch the control file to fix position in the queue.
504 if ((tfd = open(tfname, O_RDWR)) >= 0) {
507 if (read(tfd, &touch_c, 1) == 1 &&
508 lseek(tfd, (off_t)0, 0) == 0 &&
509 write(tfd, &touch_c, 1) != 1) {
510 printf("%s: cannot touch %s\n", progname,
517 if (link(tfname, cfname) < 0) {
518 printf("%s: cannot rename %s\n", progname, cfname);
524 if (qflag) /* just q things up */
526 if (!startdaemon(pp))
527 printf("jobs queued, but cannot start daemon.\n");
536 * Create the file n and copy from file descriptor f.
539 copy(const struct printer *pp, int f, const char n[])
541 register int fd, i, nr, nc;
545 card('T', title ? title : n);
546 for (i = 0; i < ncopies; i++)
547 card(format, &dfname[inchar-2]);
548 card('U', &dfname[inchar-2]);
552 while ((i = read(f, buf, BUFSIZ)) > 0) {
553 if (write(fd, buf, i) != i) {
554 printf("%s: %s: temp file write error\n", progname, n);
561 if (pp->max_blocks > 0 && nr > pp->max_blocks) {
562 printf("%s: %s: copy file is too large\n",
570 printf("%s: %s: empty input file\n", progname,
577 * Try and link the file to dfname. Return a pointer to the full
578 * path name if successful.
581 linked(const char *file)
584 static char buf[MAXPATHLEN];
588 if (getcwd(buf, sizeof(buf)) == NULL)
590 while (file[0] == '.') {
596 if (file[2] == '/') {
597 if ((cp = strrchr(buf, '/')) != NULL)
605 strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
606 strncat(buf, file, sizeof(buf) - strlen(buf) - 1);
610 ret = symlink(file, dfname);
612 return(ret ? NULL : file);
616 * Put a line into the control file.
619 card(int c, const char *p2)
622 register char *p1 = buf;
626 while ((c = *p2++) != '\0' && len < sizeof(buf)) {
627 *p1++ = (c == '\n') ? ' ' : c;
631 write(tfd, buf, len);
635 * Create a new file in the spool directory.
641 int oldumask = umask(0); /* should block signals */
644 f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
645 (void) umask(oldumask);
647 printf("%s: cannot create %s\n", progname, n);
650 if (fchown(f, userid, -1) < 0) {
651 printf("%s: cannot chown %s\n", progname, n);
652 cleanup(0); /* cleanup does exit */
655 if (++n[inchar] > 'z') {
656 if (++n[inchar-2] == 't') {
657 printf("too many files - break up the job\n");
661 } else if (n[inchar] == '[')
667 * Cleanup after interrupts and errors.
670 cleanup(int signo __unused)
674 signal(SIGHUP, SIG_IGN);
675 signal(SIGINT, SIG_IGN);
676 signal(SIGQUIT, SIG_IGN);
677 signal(SIGTERM, SIG_IGN);
683 while (tfname[i]-- != 'A');
687 while (cfname[i]-- != 'A');
692 while (dfname[i]-- != 'A');
694 } while (dfname[i-2]-- != 'd');
699 * Test to see if this is a printable file.
700 * Return -1 if it is not, 0 if its printable, and 1 if
701 * we should remove it after printing.
704 test(const char *file)
711 if (access(file, 4) < 0) {
712 printf("%s: cannot access %s\n", progname, file);
715 if (stat(file, &statb) < 0) {
716 printf("%s: cannot stat %s\n", progname, file);
719 if ((statb.st_mode & S_IFMT) == S_IFDIR) {
720 printf("%s: %s is a directory\n", progname, file);
723 if (statb.st_size == 0) {
724 printf("%s: %s is an empty file\n", progname, file);
727 if ((fd = open(file, O_RDONLY)) < 0) {
728 printf("%s: cannot open %s\n", progname, file);
732 * XXX Shall we add a similar test for ELF?
734 if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
736 printf("%s: %s is an executable program", progname, file);
742 * aside: note that 'cp' is technically a 'const char *'
743 * (because it points into 'file'), even though strrchr
744 * returns a value of type 'char *'.
746 if ((cp = strrchr(file, '/')) == NULL) {
747 if (checkwriteperm(file,".") == 0)
751 fd = checkwriteperm(file,"/");
753 /* strlcpy will change the '/' to '\0' */
754 dlen = cp - file + 1;
755 dirpath = malloc(dlen);
756 strlcpy(dirpath, file, dlen);
757 fd = checkwriteperm(file, dirpath);
763 printf("%s: %s: is not removable by you\n", progname, file);
768 printf(" and is unprintable\n");
774 checkwriteperm(const char *file, const char *directory)
777 if (access(directory, W_OK) == 0) {
778 stat(directory, &stats);
779 if (stats.st_mode & S_ISVTX) {
781 if(stats.st_uid == userid) {
790 * itoa - integer to string conversion
795 static char b[10] = "########";
806 * Perform lookup for printer name or abbreviation --
809 chkprinter(const char *ptrname, struct printer *pp)
814 status = getprintcap(ptrname, pp);
818 errx(1, "%s: %s", ptrname, pcaperr(status));
819 case PCAPERR_NOTFOUND:
820 errx(1, "%s: unknown printer", ptrname);
822 warnx("%s: unresolved tc= reference(s)", ptrname);
827 * Tell the user what we wanna get.
832 fprintf(stderr, "%s\n",
833 "usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]\n"
834 "\t[-Z daemon-options] [-i[numcols]] [-i[numcols]] [-1234 font]\n"
835 "\t[-L locale] [-wnum] [-cdfghlnmprstv] [name ...]");
841 * Make the temp files.
844 mktemps(const struct printer *pp)
846 register int len, fd, n;
850 (void) snprintf(buf, sizeof(buf), "%s/.seq", pp->spool_dir);
852 if ((fd = open(buf, O_RDWR|O_CREAT, 0664)) < 0) {
853 printf("%s: cannot create %s\n", progname, buf);
856 if (flock(fd, LOCK_EX)) {
857 printf("%s: cannot lock %s\n", progname, buf);
862 if ((len = read(fd, buf, sizeof(buf))) > 0) {
863 for (cp = buf; len--; ) {
864 if (*cp < '0' || *cp > '9')
866 n = n * 10 + (*cp++ - '0');
869 len = strlen(pp->spool_dir) + strlen(local_host) + 8;
870 tfname = lmktemp(pp, "tf", n, len);
871 cfname = lmktemp(pp, "cf", n, len);
872 dfname = lmktemp(pp, "df", n, len);
873 inchar = strlen(pp->spool_dir) + 3;
875 (void) lseek(fd, (off_t)0, 0);
876 snprintf(buf, sizeof(buf), "%03d\n", n);
877 (void) write(fd, buf, strlen(buf));
878 (void) close(fd); /* unlocks as well */
882 * Make a temp file name.
885 lmktemp(const struct printer *pp, const char *id, int num, int len)
889 if ((s = malloc(len)) == NULL)
890 errx(1, "out of memory");
891 (void) snprintf(s, len, "%s/%sA%03d%s", pp->spool_dir, id, num,