diff options
Diffstat (limited to 'usr.sbin')
28 files changed, 563 insertions, 362 deletions
diff --git a/usr.sbin/lpr/SMM.doc/0.t b/usr.sbin/lpr/SMM.doc/0.t index fa37273edf2..ef3353c53f3 100644 --- a/usr.sbin/lpr/SMM.doc/0.t +++ b/usr.sbin/lpr/SMM.doc/0.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 0.t,v 1.2 1997/01/17 15:54:15 millert Exp $ +.\" $OpenBSD: 0.t,v 1.3 2002/06/08 01:53:42 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -35,9 +35,9 @@ .\" .if n .ND .TL -4.3BSD Line Printer Spooler Manual -.EH 'SMM:7-%''4.3BSD Line Printer Spooler Manual' -.OH '4.3BSD Line Printer Spooler Manual''SMM:7-%' +OpenBSD Line Printer Spooler Manual +.EH 'SMM:7-%''OpenBSD Line Printer Spooler Manual' +.OH 'OpenBSD Line Printer Spooler Manual''SMM:7-%' .AU Ralph Campbell .AI @@ -47,20 +47,16 @@ Department of Electrical Engineering and Computer Science University of California, Berkeley Berkeley, CA 94720 .AB -.FS -* UNIX is a trademark of Bell Laboratories. -.FE This document describes the structure and installation procedure -for the line printer spooling system -developed for the 4.3BSD version -of the UNIX* operating system. +for the line printer spooling system included with the OpenBSD +operating system. .de D? .ie \\n(.$>1 Revised \\$1 \\$2 \\$3 .el DRAFT of \n(mo/\n(dy/\n(yr .. .sp 2 .LP -.D? June 8, 1993 +.D? May 31, 2002 .AE .de IR \fI\\$1\fP\\$2 diff --git a/usr.sbin/lpr/SMM.doc/2.t b/usr.sbin/lpr/SMM.doc/2.t index 9006ed037cf..c093bbc2cec 100644 --- a/usr.sbin/lpr/SMM.doc/2.t +++ b/usr.sbin/lpr/SMM.doc/2.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 2.t,v 1.3 2002/05/18 23:03:04 millert Exp $ +.\" $OpenBSD: 2.t,v 1.4 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -51,7 +51,7 @@ database restarting any printers that have jobs. In normal operation .I lpd listens for service requests on multiple sockets, -one in the UNIX domain (named ``/var/run/printer'') for +one in the LOCAL domain (named ``/var/run/printer'') for local requests, and one in the Internet domain (under the ``printer'' service specification) for requests for printer access from off machine; @@ -67,7 +67,7 @@ Clients communicate with using a simple transaction oriented protocol. Authentication of remote clients is done based on the ``privilege port'' scheme employed by -\fIrshd\fP\|(8C) and \fIrcmd\fP\|(3X). +\fIrshd\fP\|(8) and \fIrcmd\fP\|(3). The following table shows the requests understood by .IR lpd . diff --git a/usr.sbin/lpr/SMM.doc/3.t b/usr.sbin/lpr/SMM.doc/3.t index 9fa0c94581f..0b1ea2d5973 100644 --- a/usr.sbin/lpr/SMM.doc/3.t +++ b/usr.sbin/lpr/SMM.doc/3.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 3.t,v 1.2 1997/01/17 15:54:16 millert Exp $ +.\" $OpenBSD: 3.t,v 1.3 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -42,34 +42,26 @@ remove files other than their own. The strategy used to maintain protected spooling areas is as follows: .IP \(bu 3 -The spooling area is writable only by a \fIdaemon\fP user -and \fIdaemon\fP group. +The spooling area is writable only by \fIroot\fP and +and the \fIdaemon\fP group. .IP \(bu 3 -The \fIlpr\fP program runs set-user-id to \fIroot\fP and -set-group-id to group \fIdaemon\fP. The \fIroot\fP access permits -reading any file required. Accessibility is verified -with an \fIaccess\fP\|(2) call. The group ID -is used in setting up proper ownership of files -in the spooling area for \fIlprm\fP. +The \fIlpr\fP program runs set-user-id to user \fIdaemon\fP and +set-group-id to group \fIdaemon\fP. .IP \(bu 3 -Control files in a spooling area are made with \fIdaemon\fP +The utility programs, +\fIlpc\fP, \fIlpq\fP and \fIlprm\fP run set-group-id to group \fIdaemon\fP +to access spool files. +.IP \(bu 3 +Control and data files in a spooling area are made with \fIdaemon\fP ownership and group ownership \fIdaemon\fP. Their mode is 0660. -This insures control files are not modified by a user +This ensures control files are not modified by a user and that no user can remove files except through \fIlprm\fP. .IP \(bu 3 -The spooling programs, -\fIlpd\fP, \fIlpq\fP, and \fIlprm\fP run set-user-id to \fIroot\fP -and set-group-id to group \fIdaemon\fP to access spool files and printers. -.IP \(bu 3 -The printer server, \fIlpd\fP, -uses the same verification procedures as \fIrshd\fP\|(8C) -in authenticating remote clients. The host on which a client -resides must be present in the file /etc/hosts.equiv or /etc/hosts.lpd and -the request message must come from a reserved port number. -.PP -In practice, none of \fIlpd\fP, \fIlpq\fP, or -\fIlprm\fP would have to run as user \fIroot\fP if remote -spooling were not supported. In previous incarnations of -the printer system \fIlpd\fP ran set-user-id to \fIdaemon\fP, -set-group-id to group \fIspooling\fP, and \fIlpq\fP and \fIlprm\fP ran -set-group-id to group \fIspooling\fP. +The printer server, \fIlpd\fP, runs as \fIroot\fP but spends most +of its time with the effective user-id set to \fIdaemon\fP and the +effective group-id set to \fIdaemon\fP. As a result, spool files +it creates belong to user and group \fIdaemon\fP. \fILpd\fP uses +the same verification procedures as \fIrshd\fP\|(8) in authenticating +remote clients. The host on which a client resides must be present +in the file /etc/hosts.equiv or /etc/hosts.lpd and the request +message must come from a reserved port number. diff --git a/usr.sbin/lpr/SMM.doc/4.t b/usr.sbin/lpr/SMM.doc/4.t index 61f50513ca2..ac25492a897 100644 --- a/usr.sbin/lpr/SMM.doc/4.t +++ b/usr.sbin/lpr/SMM.doc/4.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 4.t,v 1.3 2002/05/18 23:03:04 millert Exp $ +.\" $OpenBSD: 4.t,v 1.4 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -36,10 +36,10 @@ .NH 1 Setting up .PP -The 4.3BSD release comes with the necessary programs +OpenBSD comes with the necessary programs installed and with the default line printer queue created. If the system must be modified, the -makefile in the directory /usr/src/usr.sbin/lpr +Makefile in the directory /usr/src/usr.sbin/lpr should be used in recompiling and reinstalling the necessary programs. .PP @@ -65,11 +65,11 @@ Printers on serial lines When a printer is connected via a serial communication line it must have the proper baud rate and terminal modes set. The following example is for a DecWriter III printer connected -locally via a 1200 baud serial line. +locally via a 9600 baud serial line. .DS .DT lp|LA-180 DecWriter III:\e - :lp=/dev/lp:br#1200:fs#06320:\e + :lp=/dev/lp:br#9600:ms=onlcr,oxtabs,-parity:\e :tr=\ef:of=/usr/libexec/lpr/lpf:lf=/var/log/lpd-errs: .DE The @@ -79,8 +79,9 @@ be left out since ``/dev/lp'' is the default. The .B br entry sets the baud rate for the tty line and the -.B fs -entry sets CRMOD, no parity, and XTABS (see \fItty\fP\|(4)). +.B ms +entry sets NL to CR-NL mapping, expansion of tabs to spaces, +and disables parity (see \fIstty\fP\|(1)). The .B tr entry indicates that a form-feed should be printed when the queue @@ -162,7 +163,7 @@ used in printing \fItroff\fP\|(1) output. This filter is needed to set the device into print mode for text, and plot mode for printing .I troff -files and raster images (see \fIva\fP\|(4V)). +files and raster images (see \fIva\fP\|(4)). Note that the page length is set to 58 lines by the .B pl entry for 8.5" by 11" fan-fold paper. diff --git a/usr.sbin/lpr/SMM.doc/5.t b/usr.sbin/lpr/SMM.doc/5.t index 213eac8d3a5..baa639c0e08 100644 --- a/usr.sbin/lpr/SMM.doc/5.t +++ b/usr.sbin/lpr/SMM.doc/5.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 5.t,v 1.2 1997/01/17 15:54:17 millert Exp $ +.\" $OpenBSD: 5.t,v 1.3 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -36,7 +36,7 @@ .NH 1 Output filter specifications .PP -The filters supplied with 4.3BSD +The filters supplied with OpenBSD handle printing and accounting for most common line printers, the Benson-Varian, the wide (36") and narrow (11") Versatec printer/plotters. For other devices or accounting diff --git a/usr.sbin/lpr/SMM.doc/6.t b/usr.sbin/lpr/SMM.doc/6.t index 22f24347feb..bac580f19f8 100644 --- a/usr.sbin/lpr/SMM.doc/6.t +++ b/usr.sbin/lpr/SMM.doc/6.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 6.t,v 1.2 1997/01/17 15:54:18 millert Exp $ +.\" $OpenBSD: 6.t,v 1.3 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -94,3 +94,13 @@ places jobs at the top of a printer queue. This can be used to reorder high priority jobs since .I lpr only provides first-come-first-serve ordering of jobs. +.LP +\fBup\fP and \fBdown\fP +.IP +\fIUp\fP and \fIdown\fP combine the functionality of \fIenable\fP +and \fIstart\fP with \fIstart\fP and \fIstop\fP. \fIUp\fP is +equivalent to issuing the \fIstart\fP and \fIenable\fP commands, +whereas \fIdown\fP is equivalent to issuing the \fIstop\fP and +\fIdisable\fP commands. \fIDown\fP also takes an optional message +that will be written to the printer's status file. This allows the +administrator to indicate to users why the printer is out of service. diff --git a/usr.sbin/lpr/SMM.doc/7.t b/usr.sbin/lpr/SMM.doc/7.t index f7a85808285..2e83cd5f2e8 100644 --- a/usr.sbin/lpr/SMM.doc/7.t +++ b/usr.sbin/lpr/SMM.doc/7.t @@ -1,4 +1,4 @@ -.\" $OpenBSD: 7.t,v 1.3 2002/05/18 23:03:04 millert Exp $ +.\" $OpenBSD: 7.t,v 1.4 2002/06/08 01:53:43 millert Exp $ .\" .\" Copyright (c) 1983, 1993 .\" The Regents of the University of California. All rights reserved. @@ -74,7 +74,7 @@ Usually it is enough to get a super-user to type the following to restart .IR lpd . .DS -% /usr/lib/lpd +% /usr/sbin/lpd .DE You can also check the state of the master printer daemon with the following. .DS @@ -83,10 +83,10 @@ You can also check the state of the master printer daemon with the following. .IP Another possibility is that the .I lpr -program is not set-user-id to \fIroot\fP, set-group-id to group \fIdaemon\fP. +program is not set-user-id to \fIdaemon\fP, set-group-id to group \fIdaemon\fP. This can be checked with .DS -% ls \-lg /usr/bin/lpr +% ls \-l /usr/bin/lpr .DE .SH lpr: \fIprinter\fP\|: printer queue is disabled diff --git a/usr.sbin/lpr/SMM.doc/spell.ok b/usr.sbin/lpr/SMM.doc/spell.ok index bf31319943d..c7120549b5f 100644 --- a/usr.sbin/lpr/SMM.doc/spell.ok +++ b/usr.sbin/lpr/SMM.doc/spell.ok @@ -34,7 +34,7 @@ lpd.lock lpf lpf:lf lprgroup -makefile +Makefile mx offline pl diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c index b27da16cd8d..1772d30b7c9 100644 --- a/usr.sbin/lpr/common_source/common.c +++ b/usr.sbin/lpr/common_source/common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: common.c,v 1.17 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: common.c,v 1.18 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: common.c,v 1.21 2000/08/09 14:28:50 itojun Exp $ */ /* @@ -43,7 +43,7 @@ #if 0 static const char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: common.c,v 1.17 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: common.c,v 1.18 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -58,6 +58,7 @@ static const char rcsid[] = "$OpenBSD: common.c,v 1.17 2002/05/20 23:13:50 mille #include <dirent.h> #include <errno.h> +#include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> @@ -163,11 +164,15 @@ retry: for (r = res; r; r = r->ai_next) { trial++; retryport: - seteuid(euid); + PRIV_START; s = rresvport_af(&lport, r->ai_family); - seteuid(uid); - if (s < 0) - return(-1); + PRIV_END; + if (s < 0) { + /* fall back to non-privileged port */ + if (errno != EACCES || + (s = socket(r->ai_family, SOCK_STREAM, 0)) < 0) + return(-1); + } siginterrupt(SIGINT, 1); if (connect(s, r->ai_addr, r->ai_addrlen) < 0) { error = errno; @@ -246,9 +251,9 @@ getq(namelist) struct stat stbuf; DIR *dirp; - seteuid(euid); + PRIV_START; dirp = opendir(SD); - seteuid(uid); + PRIV_END; if (dirp == NULL) return(-1); if (fstat(dirp->dd_fd, &stbuf) < 0) @@ -267,12 +272,12 @@ getq(namelist) while ((d = readdir(dirp)) != NULL) { if (d->d_name[0] != 'c' || d->d_name[1] != 'f') continue; /* daemon control files only */ - seteuid(euid); + PRIV_START; if (stat(d->d_name, &stbuf) < 0) { - seteuid(uid); + PRIV_END; continue; /* Doesn't exist */ } - seteuid(uid); + PRIV_END; q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1); if (q == NULL) goto errdone; @@ -340,9 +345,14 @@ checkremote(void) remote = 0; /* assume printer is local on failure */ - if (RM == NULL) + if (RM == NULL || *RM == '\0') return NULL; + /* XXX */ + remote = 1; + return NULL; /* XXX -- for local testing only! */ + /* XXX */ + /* get the local interface addresses */ siginterrupt(SIGINT, 1); if (getifaddrs(&ifap) < 0) { @@ -452,3 +462,28 @@ fatal(const char *msg, ...) (void)putchar('\n'); exit(1); } + +int +safe_open(const char *path, int flags, mode_t mode) +{ + int fd, serrno; + struct stat stbuf; + + if ((fd = open(path, flags|O_NONBLOCK, mode)) < 0 || + fstat(fd, &stbuf) < 0) { + if (fd >= 0) { + serrno = errno; + close(fd); + errno = serrno; + } + return (-1); + } + if (!S_ISREG(stbuf.st_mode)) { + close(fd); + errno = EACCES; + return (-1); + } + if (mode) + (void)fchmod(fd, mode); + return (fd); +} diff --git a/usr.sbin/lpr/common_source/common_vars.c b/usr.sbin/lpr/common_source/common_vars.c index 241bfad642e..2b874166af2 100644 --- a/usr.sbin/lpr/common_source/common_vars.c +++ b/usr.sbin/lpr/common_source/common_vars.c @@ -1,4 +1,4 @@ -/* $OpenBSD: common_vars.c,v 1.1 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: common_vars.c,v 1.2 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: common.c,v 1.15 1999/09/26 10:32:27 mrg Exp $ */ /* @@ -40,7 +40,7 @@ */ #ifndef lint -static const char rcsid[] = "$OpenBSD: common_vars.c,v 1.1 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: common_vars.c,v 1.2 2002/06/08 01:53:43 millert Exp $"; #endif /* not lint */ #include <sys/param.h> @@ -53,5 +53,6 @@ char host[MAXHOSTNAMELEN+1]; /* host machine name */ char *from = host; /* client's machine name */ char *printcapdb[2] = { _PATH_PRINTCAP, 0 }; char *bp; /* pointer into printcap buffer. */ -uid_t uid, euid; /* real and effective uids */ u_int wait_time = 300; /* time out after 5 minutes by default */ +uid_t real_uid, effective_uid; +gid_t real_gid, effective_gid; diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c index 67dea6390de..a58abcb56b8 100644 --- a/usr.sbin/lpr/common_source/displayq.c +++ b/usr.sbin/lpr/common_source/displayq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: displayq.c,v 1.17 2002/05/28 18:16:03 millert Exp $ */ +/* $OpenBSD: displayq.c,v 1.18 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: displayq.c,v 1.21 2001/08/30 00:51:50 itojun Exp $ */ /* @@ -38,23 +38,25 @@ #if 0 static const char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: displayq.c,v 1.17 2002/05/28 18:16:03 millert Exp $"; +static const char rcsid[] = "$OpenBSD: displayq.c,v 1.18 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ #include <sys/param.h> -#include <sys/stat.h> #include <sys/file.h> - -#include <signal.h> -#include <fcntl.h> #include <sys/ioctl.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> #include <dirent.h> -#include <unistd.h> +#include <fcntl.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <ctype.h> +#include <unistd.h> + #include "lp.h" #include "lp.local.h" #include "pathnames.h" @@ -139,25 +141,24 @@ displayq(int format) * Print out local queue * Find all the control files in the spooling directory */ - seteuid(euid); + PRIV_START; if (chdir(SD) < 0) fatal("cannot chdir to spooling directory"); - seteuid(uid); + PRIV_END; if ((nitems = getq(&queue)) < 0) fatal("cannot examine spooling area\n"); - seteuid(euid); + PRIV_START; ret = stat(LO, &statb); - seteuid(uid); + PRIV_END; if (ret >= 0) { if (statb.st_mode & 0100) { if (remote) printf("%s: ", host); printf("Warning: %s is down: ", printer); - seteuid(euid); - fd = open(ST, O_RDONLY); - seteuid(uid); - if (fd >= 0) { - (void)flock(fd, LOCK_SH); + PRIV_START; + fd = safe_open(ST, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd >= 0 && flock(fd, LOCK_SH) == 0) { while ((i = read(fd, line, sizeof(line))) > 0) (void)fwrite(line, 1, i, stdout); (void)close(fd); /* unlocks as well */ @@ -172,12 +173,14 @@ displayq(int format) } if (nitems) { - seteuid(euid); - fp = fopen(LO, "r"); - seteuid(uid); - if (fp == NULL) + PRIV_START; + fd = safe_open(LO, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); nodaemon(); - else { + } else { /* get daemon pid */ cp = current; ecp = cp + sizeof(current) - 1; @@ -190,11 +193,11 @@ displayq(int format) if (i <= 0) { ret = -1; } else { - seteuid(euid); + PRIV_START; ret = kill(i, 0); - seteuid(uid); + PRIV_END; } - if (ret < 0) { + if (ret < 0 && errno != EPERM) { nodaemon(); } else { /* read current file name */ @@ -210,11 +213,10 @@ displayq(int format) */ if (remote) printf("%s: ", host); - seteuid(euid); - fd = open(ST, O_RDONLY); - seteuid(uid); - if (fd >= 0) { - (void)flock(fd, LOCK_SH); + PRIV_START; + fd = safe_open(ST, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd >= 0 && flock(fd, LOCK_SH) == 0) { while ((i = read(fd, line, sizeof(line))) > 0) (void)fwrite(line, 1, i, stdout); (void)close(fd); /* unlocks as well */ @@ -331,17 +333,21 @@ header(void) void inform(char *cf) { - int j; - FILE *cfp; + int fd, j; + FILE *cfp = NULL; /* * There's a chance the control file has gone away * in the meantime; if this is the case just keep going */ - seteuid(euid); - if ((cfp = fopen(cf, "r")) == NULL) + PRIV_START; + fd = safe_open(cf, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); return; - seteuid(uid); + } if (rank < 0) rank = 0; @@ -465,10 +471,10 @@ dump(char *nfile, char *file, int copies) printf("%s", nfile); col += n+fill; } - seteuid(euid); + PRIV_START; if (*file && !stat(file, &lbuf)) totsize += copies * lbuf.st_size; - seteuid(uid); + PRIV_END; } /* diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h index 9a3cedb372a..2734028e37d 100644 --- a/usr.sbin/lpr/common_source/lp.h +++ b/usr.sbin/lpr/common_source/lp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lp.h,v 1.9 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: lp.h,v 1.10 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: lp.h,v 1.14 2000/04/16 14:43:58 mrg Exp $ */ /* @@ -92,7 +92,8 @@ extern int remote; /* true if sending files to a remote host */ extern char *printcapdb[]; /* printcap database array */ extern u_int wait_time; /* time to wait for remote responses */ -extern uid_t uid, euid; /* real and effective user id's */ +extern uid_t real_uid, effective_uid; +extern gid_t real_gid, effective_gid; extern volatile sig_atomic_t gotintr; @@ -104,6 +105,23 @@ struct queue { char q_name[MAXNAMLEN+1]; /* control file name */ }; +/* + * Macros to raise/lower permissions. + */ +#define PRIV_START do { \ + int save_errno = errno; \ + (void)seteuid(effective_uid); \ + (void)setegid(effective_gid); \ + errno = save_errno; \ +} while (0) + +#define PRIV_END do { \ + int save_errno = errno; \ + (void)setegid(real_gid); \ + (void)seteuid(real_uid); \ + errno = save_errno; \ +} while (0) + #include <sys/cdefs.h> __BEGIN_DECLS @@ -125,7 +143,6 @@ int inlist(char *, char *); int iscf(struct dirent *); int isowner(char *, char *); void ldump(char *, char *, int); -int lockchk(char *); void prank(int); void process(char *); void rmjob(void); @@ -134,4 +151,5 @@ void show(char *, char *, int); int startdaemon(char *); void nodaemon(void); void delay(int); +int safe_open(const char *, int, mode_t); __END_DECLS diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c index c3712e246a8..1e7f13dbd56 100644 --- a/usr.sbin/lpr/common_source/rmjob.c +++ b/usr.sbin/lpr/common_source/rmjob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rmjob.c,v 1.13 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: rmjob.c,v 1.14 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: rmjob.c,v 1.16 2000/04/16 14:43:58 mrg Exp $ */ /* @@ -38,7 +38,7 @@ #if 0 static const char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: rmjob.c,v 1.13 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: rmjob.c,v 1.14 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -46,6 +46,7 @@ static const char rcsid[] = "$OpenBSD: rmjob.c,v 1.13 2002/05/20 23:13:50 miller #include <signal.h> #include <errno.h> +#include <fcntl.h> #include <dirent.h> #include <unistd.h> #include <stdlib.h> @@ -76,6 +77,7 @@ static char current[NAME_MAX]; /* active control file name */ static void do_unlink(char *); static void alarmer(int); +static int lockchk(char *); void rmjob(void) @@ -122,23 +124,24 @@ rmjob(void) person = root; } - seteuid(euid); + PRIV_START; if (chdir(SD) < 0) fatal("cannot chdir to spool directory"); if ((nitems = scandir(".", &files, iscf, NULL)) < 0) fatal("cannot access spool directory"); - seteuid(uid); + PRIV_END; if (nitems) { /* - * Check for an active printer daemon (in which case we - * kill it if it is reading our file) then remove stuff - * (after which we have to restart the daemon). + * Check for an active printer daemon. If one is running + * and it is reading our file, kill it, then remove stuff. + * Lastly, restart the daemon if it is not (or no longer) + * running. */ if (lockchk(LO) && chk(current)) { - seteuid(euid); + PRIV_START; assasinated = kill(cur_daemon, SIGINT) == 0; - seteuid(uid); + PRIV_END; if (!assasinated) fatal("cannot kill printer daemon"); } @@ -159,23 +162,27 @@ rmjob(void) /* * Process a lock file: collect the pid of the active - * daemon and the file name of the active spool entry. + * daemon and the file name of the active spool entry. * Return boolean indicating existence of a lock file. */ -int +static int lockchk(char *s) { - FILE *fp; - int i, n; - - seteuid(euid); - if ((fp = fopen(s, "r")) == NULL) { + FILE *fp = NULL; + int fd, i, n; + + /* NOTE: lock file is owned by root, not the user. */ + PRIV_START; + fd = safe_open(s, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); if (errno == EACCES) fatal("can't access lock file"); else return(0); } - seteuid(uid); if (!getline(fp)) { (void)fclose(fp); return(0); /* no daemon present */ @@ -203,14 +210,19 @@ lockchk(char *s) void process(char *file) { - FILE *cfp; + FILE *cfp = NULL; + int fd; if (!chk(file)) return; - seteuid(euid); - if ((cfp = fopen(file, "r")) == NULL) + PRIV_START; + fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); fatal("cannot open %s", file); - seteuid(uid); + } while (getline(cfp)) { switch (line[0]) { case 'U': /* unlink associated files */ @@ -230,9 +242,9 @@ do_unlink(char *file) if (from != host) printf("%s: ", host); - seteuid(euid); + PRIV_START; ret = unlink(file); - seteuid(uid); + PRIV_END; printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file); } @@ -242,9 +254,9 @@ do_unlink(char *file) int chk(char *file) { - int *r, n; + int *r, n, fd; char **u, *cp; - FILE *cfp; + FILE *cfp = NULL; /* * Check for valid cf file name (mostly checking current). @@ -258,10 +270,14 @@ chk(char *file) /* * get the owner's name from the control file. */ - seteuid(euid); - if ((cfp = fopen(file, "r")) == NULL) + PRIV_START; + fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); return(0); - seteuid(uid); + } while (getline(cfp)) { if (line[0] == 'P') break; diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c index 8a25bfdcbd0..cf4e868cf17 100644 --- a/usr.sbin/lpr/common_source/startdaemon.c +++ b/usr.sbin/lpr/common_source/startdaemon.c @@ -1,4 +1,4 @@ -/* $OpenBSD: startdaemon.c,v 1.7 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: startdaemon.c,v 1.8 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: startdaemon.c,v 1.10 1998/07/18 05:04:39 lukem Exp $ */ /* @@ -38,7 +38,7 @@ #if 0 static const char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94"; #else -static const char rcsid[] = "$OpenBSD: startdaemon.c,v 1.7 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: startdaemon.c,v 1.8 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -53,13 +53,13 @@ static const char rcsid[] = "$OpenBSD: startdaemon.c,v 1.7 2002/05/20 23:13:50 m #include <unistd.h> #include <string.h> #include <signal.h> + #include "lp.h" #include "pathnames.h" /* * Tell the printer daemon that there are new files in the spool directory. */ - int startdaemon(char *printer) { @@ -79,23 +79,23 @@ startdaemon(char *printer) #ifndef SUN_LEN #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif - seteuid(euid); siginterrupt(SIGINT, 1); + PRIV_START; if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { if (errno == EINTR && gotintr) { + PRIV_END; siginterrupt(SIGINT, 0); - seteuid(uid); close(s); return(0); } + PRIV_END; siginterrupt(SIGINT, 0); - seteuid(uid); perror("connect"); (void)close(s); return(0); } + PRIV_END; siginterrupt(SIGINT, 0); - seteuid(uid); n = snprintf(buf, sizeof(buf), "\1%s\n", printer); if (n >= sizeof(buf) || n == -1) { close(s); diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c index 86608fe3bda..005fa0caeb0 100644 --- a/usr.sbin/lpr/lpc/cmds.c +++ b/usr.sbin/lpr/lpc/cmds.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmds.c,v 1.16 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: cmds.c,v 1.17 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: cmds.c,v 1.12 1997/10/05 15:12:06 mrg Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: cmds.c,v 1.16 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: cmds.c,v 1.17 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -73,8 +73,6 @@ static const char rcsid[] = "$OpenBSD: cmds.c,v 1.16 2002/05/20 23:13:50 millert #include "extern.h" #include "pathnames.h" -extern uid_t uid, euid; - static void abortpr(int); static void cleanpr(void); static void disablepr(void); @@ -145,22 +143,25 @@ abortpr(int dis) (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); printf("%s:\n", printer); + PRIV_START; /* * Turn on the owner execute bit of the lock file to disable printing. */ if (dis) { - seteuid(euid); if (stat(line, &stbuf) >= 0) { - if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) + stbuf.st_mode |= S_IXUSR; + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot disable printing\n"); else { upstat("printing disabled\n"); printf("\tprinting disabled\n"); } } else if (errno == ENOENT) { - if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) + if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, + 0760)) < 0) printf("\tcannot create lock file\n"); else { + (void)fchown(fd, DEFUID, -1); (void)close(fd); upstat("printing disabled\n"); printf("\tprinting disabled\n"); @@ -175,7 +176,10 @@ abortpr(int dis) /* * Kill the current daemon to stop printing now. */ - if ((fp = fopen(line, "r")) == NULL) { + fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0); + if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); printf("\tcannot open lock file\n"); goto out; } @@ -193,11 +197,11 @@ abortpr(int dis) } else printf("\tdaemon (pid %d) killed\n", pid); out: - seteuid(uid); + PRIV_END; } /* - * Write a message into the status file. + * Write a message into the status file (assumes PRIV_START already called) */ static void upstat(char *msg) @@ -208,12 +212,12 @@ upstat(char *msg) if (cgetstr(bp, "st", &ST) == -1) ST = DEFSTAT; (void)snprintf(statfile, sizeof(statfile), "%s/%s", SD, ST); - umask(0); - fd = open(statfile, O_WRONLY|O_CREAT, 0664); + fd = safe_open(statfile, O_WRONLY|O_CREAT|O_NOFOLLOW, 0660); if (fd < 0 || flock(fd, LOCK_EX) < 0) { printf("\tcannot create status file\n"); return; } + (void)fchown(fd, DEFUID, -1); (void)ftruncate(fd, 0); if (msg == (char *)NULL) (void)write(fd, "\n", 1); @@ -324,9 +328,9 @@ cleanpr(void) return; } - seteuid(euid); + PRIV_START; nitems = scandir(SD, &queue, doselect, sortq); - seteuid(uid); + PRIV_END; if (nitems < 0) { printf("\tcannot examine spool directory\n"); return; @@ -370,12 +374,12 @@ cleanpr(void) static void unlinkf(char *name) { - seteuid(euid); + PRIV_START; if (unlink(name) < 0) printf("\tcannot remove %s\n", name); else printf("\tremoved %s\n", name); - seteuid(uid); + PRIV_END; } /* @@ -435,14 +439,15 @@ enablepr(void) /* * Turn off the group execute bit of the lock file to enable queuing. */ - seteuid(euid); + PRIV_START; if (stat(line, &stbuf) >= 0) { - if (chmod(line, stbuf.st_mode & 0767) < 0) + stbuf.st_mode &= ~S_IXGRP; + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot enable queuing\n"); else printf("\tqueuing enabled\n"); } - seteuid(uid); + PRIV_END; } /* @@ -502,22 +507,24 @@ disablepr(void) /* * Turn on the group execute bit of the lock file to disable queuing. */ - seteuid(euid); + PRIV_START; if (stat(line, &stbuf) >= 0) { - if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0) + stbuf.st_mode |= S_IXGRP; + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot disable queuing\n"); else printf("\tqueuing disabled\n"); } else if (errno == ENOENT) { - if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0) + if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0670)) < 0) printf("\tcannot create lock file\n"); else { + (void)fchown(fd, DEFUID, -1); (void)close(fd); printf("\tqueuing disabled\n"); } } else printf("\tcannot stat lock file\n"); - seteuid(uid); + PRIV_END; } /* @@ -581,20 +588,22 @@ putmsg(int argc, char **argv) * turn on the owner execute bit of the lock file to disable printing. */ (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); - seteuid(euid); + PRIV_START; if (stat(line, &stbuf) >= 0) { - if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0) + stbuf.st_mode |= (S_IXGRP|S_IXUSR); + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot disable queuing\n"); else printf("\tprinter and queuing disabled\n"); } else if (errno == ENOENT) { - if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0) + if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0770)) < 0) printf("\tcannot create lock file\n"); else { + (void)fchown(fd, DEFUID, -1); (void)close(fd); printf("\tprinter and queuing disabled\n"); } - seteuid(uid); + PRIV_END; return; } else printf("\tcannot stat lock file\n"); @@ -602,13 +611,14 @@ putmsg(int argc, char **argv) * Write the message into the status file. */ (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); - fd = open(line, O_WRONLY|O_CREAT, 0664); + fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0660); if (fd < 0 || flock(fd, LOCK_EX) < 0) { printf("\tcannot create status file\n"); - seteuid(uid); + PRIV_END; return; } - seteuid(uid); + PRIV_END; + (void)fchown(fd, DEFUID, -1); (void)ftruncate(fd, 0); if (argc <= 0) { (void)write(fd, "\n", 1); @@ -737,19 +747,24 @@ startpr(int enable) /* * Turn off the owner execute bit of the lock file to enable printing. + * If we are marking the printer "up" also turn off group execute bit. */ - seteuid(euid); + PRIV_START; if (enable && stat(line, &stbuf) >= 0) { - if (chmod(line, stbuf.st_mode & (enable==2 ? 0666 : 0677)) < 0) + if (enable == 2) + stbuf.st_mode &= ~(S_IXUSR|S_IXGRP); + else + stbuf.st_mode &= ~S_IXUSR; + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot enable printing\n"); else printf("\tprinting enabled\n"); } + PRIV_END; if (!startdaemon(printer)) printf("\tcouldn't start daemon\n"); else printf("\tdaemon started\n"); - seteuid(uid); } /* @@ -809,7 +824,10 @@ prstat(void) ST = DEFSTAT; printf("%s:\n", printer); (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); - if (stat(line, &stbuf) >= 0) { + PRIV_START; + i = stat(line, &stbuf); + PRIV_END; + if (i >= 0) { printf("\tqueuing is %s\n", (stbuf.st_mode & 010) ? "disabled" : "enabled"); printf("\tprinting is %s\n", @@ -818,7 +836,10 @@ prstat(void) printf("\tqueuing is enabled\n"); printf("\tprinting is enabled\n"); } - if ((dirp = opendir(SD)) == NULL) { + PRIV_START; + dirp = opendir(SD); + PRIV_END; + if (dirp == NULL) { printf("\tcannot examine spool directory\n"); return; } @@ -834,7 +855,9 @@ prstat(void) printf("\t1 entry in spool area\n"); else printf("\t%d entries in spool area\n", i); - fd = open(line, O_RDONLY); + PRIV_START; + fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { (void)close(fd); /* unlocks as well */ printf("\tprinter idle\n"); @@ -842,7 +865,9 @@ prstat(void) } (void)close(fd); (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); - fd = open(line, O_RDONLY); + PRIV_START; + fd = safe_open(line, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; if (fd >= 0) { (void)flock(fd, LOCK_SH); if (fstat(fd, &stbuf) == 0 && stbuf.st_size > 0) { @@ -913,25 +938,27 @@ stoppr(void) /* * Turn on the owner execute bit of the lock file to disable printing. */ - seteuid(euid); + PRIV_START; if (stat(line, &stbuf) >= 0) { - if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) + stbuf.st_mode |= S_IXUSR; + if (chmod(line, stbuf.st_mode & 0777) < 0) printf("\tcannot disable printing\n"); else { upstat("printing disabled\n"); printf("\tprinting disabled\n"); } } else if (errno == ENOENT) { - if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) + if ((fd = safe_open(line, O_WRONLY|O_CREAT|O_NOFOLLOW, 0760)) < 0) printf("\tcannot create lock file\n"); else { + (void)fchown(fd, DEFUID, -1); (void)close(fd); upstat("printing disabled\n"); printf("\tprinting disabled\n"); } } else printf("\tcannot stat lock file\n"); - seteuid(uid); + PRIV_END; } struct queue **queue; @@ -971,12 +998,12 @@ topq(int argc, char **argv) LO = DEFLOCK; printf("%s:\n", printer); - seteuid(euid); + PRIV_START; if (chdir(SD) < 0) { printf("\tcannot chdir to %s\n", SD); goto out; } - seteuid(uid); + PRIV_END; nitems = getq(&queue); if (nitems == 0) return; @@ -1000,12 +1027,14 @@ topq(int argc, char **argv) * Turn on the public execute bit of the lock file to * get lpd to rebuild the queue after the current job. */ - seteuid(euid); - if (changed && stat(LO, &stbuf) >= 0) - (void)chmod(LO, (stbuf.st_mode & 0777) | 01); + PRIV_START; + if (changed && stat(LO, &stbuf) >= 0) { + stbuf.st_mode |= S_IXOTH; + (void)chmod(LO, stbuf.st_mode & 0777); + } out: - seteuid(uid); + PRIV_END; } /* @@ -1020,9 +1049,9 @@ touch(struct queue *q) tvp[0].tv_sec = tvp[1].tv_sec = --mtime; tvp[0].tv_usec = tvp[1].tv_usec = 0; - seteuid(euid); + PRIV_START; ret = utimes(q->q_name, tvp); - seteuid(uid); + PRIV_END; return (ret); } @@ -1034,7 +1063,7 @@ int doarg(char *job) { struct queue **qq; - int jobnum, n; + int jobnum, fd, n; char *cp, *machine; int cnt = 0; FILE *fp; @@ -1079,11 +1108,14 @@ doarg(char *job) * Process item consisting of owner's name (example: henry). */ for (qq = queue + nitems; --qq >= queue; ) { - seteuid(euid); - fp = fopen((*qq)->q_name, "r"); - seteuid(uid); - if (fp == NULL) + PRIV_START; + fd = safe_open((*qq)->q_name, O_RDONLY|O_NOFOLLOW, 0); + PRIV_END; + if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) { + if (fd >= 0) + close(fd); continue; + } while (getline(fp) > 0) if (line[0] == 'P') break; diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8 index b4781c1847a..c663e0b5daf 100644 --- a/usr.sbin/lpr/lpc/lpc.8 +++ b/usr.sbin/lpr/lpc/lpc.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: lpc.8,v 1.10 2002/05/20 23:13:50 millert Exp $ +.\" $OpenBSD: lpc.8,v 1.11 2002/06/08 01:53:43 millert Exp $ .\" $NetBSD: lpc.8,v 1.14 2002/01/19 03:22:19 wiz Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 @@ -112,7 +112,7 @@ in the printer status file. The message doesn't need to be quoted, the remaining arguments are treated like .Xr echo 1 . -This is normally used to take a printer down and let others know why +This is normally used to take a printer down and let users know why. .Xr lpq 1 will indicate the printer is down and print the status message. .Pp diff --git a/usr.sbin/lpr/lpc/lpc.c b/usr.sbin/lpr/lpc/lpc.c index adaf078440e..bbd41c4833c 100644 --- a/usr.sbin/lpr/lpc/lpc.c +++ b/usr.sbin/lpr/lpc/lpc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lpc.c,v 1.13 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: lpc.c,v 1.14 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: lpc.c,v 1.11 2001/11/14 03:01:15 enami Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: lpc.c,v 1.13 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: lpc.c,v 1.14 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -94,11 +94,13 @@ main(int argc, char **argv) { struct cmd *c; - euid = geteuid(); - uid = getuid(); - seteuid(uid); - openlog("lpc", 0, LOG_LPR); + effective_uid = geteuid(); + real_uid = getuid(); + effective_gid = getegid(); + real_gid = getgid(); + PRIV_END; /* be safe */ + openlog("lpc", 0, LOG_LPR); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { @@ -109,7 +111,7 @@ main(int argc, char **argv) printf("?Invalid command\n"); exit(1); } - if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) { + if (c->c_priv && real_uid && ingroup(LPR_OPER) == 0) { printf("?Privileged command\n"); exit(1); } diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile index 5698aed8d73..5d64e87885e 100644 --- a/usr.sbin/lpr/lpd/Makefile +++ b/usr.sbin/lpr/lpd/Makefile @@ -1,11 +1,13 @@ # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $OpenBSD: Makefile,v 1.3 2002/05/20 23:13:50 millert Exp $ +# $OpenBSD: Makefile,v 1.4 2002/06/08 01:53:43 millert Exp $ PROG= lpd CFLAGS+=-I${.CURDIR}/../common_source MAN= lpd.8 SRCS= lpd.c printjob.c recvjob.c displayq.c rmjob.c startdaemon.c \ lpdchar.c common.c key.c modes.c ttcompat.c common_vars.c +BINGRP= daemon +BINMODE=2550 .PATH: ${.CURDIR}/../common_source .include "../../Makefile.inc" diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c index fe6034e3113..e731fda086b 100644 --- a/usr.sbin/lpr/lpd/lpd.c +++ b/usr.sbin/lpr/lpd/lpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lpd.c,v 1.32 2002/05/28 18:17:22 millert Exp $ */ +/* $OpenBSD: lpd.c,v 1.33 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: lpd.c,v 1.33 2002/01/21 14:42:29 wiz Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; #else -static const char rcsid[] = "$OpenBSD: lpd.c,v 1.32 2002/05/28 18:17:22 millert Exp $"; +static const char rcsid[] = "$OpenBSD: lpd.c,v 1.33 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -66,16 +66,18 @@ static const char rcsid[] = "$OpenBSD: lpd.c,v 1.32 2002/05/28 18:17:22 millert * remove jobs from the queue. * * Strategy to maintain protected spooling area: - * 1. Spooling area is writable only by daemon and spooling group - * 2. lpr runs setuid root and setgrp spooling group; it uses - * root to access any file it wants (verifying things before - * with an access call) and group id to know how it should - * set up ownership of files in the spooling area. - * 3. Files in spooling area are owned by root, group spooling - * group, with mode 660. - * 4. lpd, lpq and lprm run setuid daemon and setgrp spooling group to - * access files and printer. Users can't get to anything - * w/o help of lpq and lprm programs. + * 1. Spooling area is writable only by root and the group daemon. + * 2. Files in spooling area are owned by user daemon, group daemon, + * and are mode 660. + * 3. lpd runs as root but spends most of its time with its effective + * uid and gid set to the uid/gid specified in the passwd entry for + * DEFUID (1, aka daemon). + * 4. lpr runs setuid daemon and setgrp daemon; it opens + * files to be printed with its real uid/gid and writes to + * the spool dir with its effective uid/gid (i.e. daemon). + * 5. lpc, lpr and lprm run setgrp daemon. + * + * Users can't touch the spool w/o the help of one of the lp* programs. */ #include <sys/param.h> @@ -94,6 +96,7 @@ static const char rcsid[] = "$OpenBSD: lpd.c,v 1.32 2002/05/28 18:17:22 millert #include <errno.h> #include <fcntl.h> #include <netdb.h> +#include <pwd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -137,6 +140,7 @@ int main(int argc, char **argv) { fd_set defreadfds; + struct passwd *pw; struct sockaddr_un un, fromunix; struct sockaddr_storage frominet; sigset_t mask, omask; @@ -148,14 +152,24 @@ main(int argc, char **argv) const char *port = "printer"; char *cp; - euid = geteuid(); /* these shouldn't be different */ - uid = getuid(); - options = check_options = 0; - gethostname(host, sizeof(host)); - - if (euid != 0) + if (geteuid() != 0) errx(1, "must run as root"); + /* + * We want to run with euid of daemon most of the time. + */ + if ((pw = getpwuid(DEFUID)) == NULL) + errx(1, "daemon uid (%d) not in password file", DEFUID); + real_uid = pw->pw_uid; + real_gid = pw->pw_gid; + effective_uid = 0; + effective_gid = getegid(); + PRIV_END; /* run as daemon for most things */ + + check_options = LPD_NOPORTCHK; /* XXX - lp* not setuid root */ + options = 0; + gethostname(host, sizeof(host)); + while ((i = getopt(argc, argv, "b:cdln:rsw:W")) != -1) { switch (i) { case 'b': @@ -240,7 +254,9 @@ main(int argc, char **argv) openlog("lpd", LOG_PID, LOG_LPR); syslog(LOG_INFO, "restarted"); (void)umask(0); + PRIV_START; lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644); + PRIV_END; if (lfd < 0) { if (errno == EWOULDBLOCK) /* active daemon present */ exit(0); @@ -262,7 +278,9 @@ main(int argc, char **argv) * Restart all the printers. */ startup(); + PRIV_START; (void)unlink(_PATH_SOCKETNAME); + PRIV_END; funix = socket(AF_LOCAL, SOCK_STREAM, 0); if (funix < 0) { syslog(LOG_ERR, "socket: %m"); @@ -287,10 +305,12 @@ main(int argc, char **argv) #ifndef SUN_LEN #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif + PRIV_START; if (bind(funix, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) { syslog(LOG_ERR, "ubind: %m"); exit(1); } + PRIV_END; (void)umask(0); sigprocmask(SIG_SETMASK, &omask, NULL); FD_ZERO(&defreadfds); @@ -438,6 +458,7 @@ mcleanup(int signo) if (lflag) syslog_r(LOG_INFO, &sdata, "exiting"); + PRIV_START; unlink(_PATH_SOCKETNAME); unlink(_PATH_MASTERLOCK); _exit(0); @@ -584,8 +605,7 @@ doit(void) static void startup(void) { - char *buf; - char *cp; + char *buf, *cp; /* * Restart the daemons. @@ -622,6 +642,7 @@ startup(void) /* * Make sure there's some work to do before forking off a child + * XXX - could be common w/ lpq */ static int ckqueue(char *cap) @@ -632,13 +653,14 @@ ckqueue(char *cap) if (cgetstr(cap, "sd", &spooldir) == -1) spooldir = _PATH_DEFSPOOL; - if ((dirp = opendir(spooldir)) == NULL) + dirp = opendir(spooldir); + if (dirp == NULL) return (-1); while ((d = readdir(dirp)) != NULL) { - if (d->d_name[0] != 'c' || d->d_name[1] != 'f') - continue; /* daemon control files only */ - closedir(dirp); - return (1); /* found something */ + if (d->d_name[0] == 'c' && d->d_name[1] == 'f') { + closedir(dirp); + return (1); /* found a cf file */ + } } closedir(dirp); return (0); @@ -710,7 +732,9 @@ chkhost(struct sockaddr *f, int check_opts) if (good == 0) fatal("address for your hostname (%s) not matched", host); setproctitle("serving %s", from); + PRIV_START; hostf = fopen(_PATH_HOSTSEQUIV, "r"); + PRIV_END; again: if (hostf) { if (__ivaliduser_sa(hostf, f, f->sa_len, DUMMY, DUMMY) == 0) { @@ -721,7 +745,9 @@ again: } if (first == 1) { first = 0; + PRIV_START; hostf = fopen(_PATH_HOSTSLPD, "r"); + PRIV_END; goto again; } fatal("Your host does not have line printer access"); @@ -796,7 +822,10 @@ socksetup(int af, int options, const char *port) close (*s); continue; } - if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) { + PRIV_START; + error = bind(*s, r->ai_addr, r->ai_addrlen); + PRIV_END; + if (error < 0) { syslog(LOG_DEBUG, "bind(): %m"); close (*s); continue; diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c index a1578c9e43a..8e0bce7da8e 100644 --- a/usr.sbin/lpr/lpd/printjob.c +++ b/usr.sbin/lpr/lpd/printjob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printjob.c,v 1.32 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: printjob.c,v 1.33 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: printjob.c,v 1.31 2002/01/21 14:42:30 wiz Exp $ */ /* @@ -72,6 +72,7 @@ static const char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; #include <stdlib.h> #include <stdarg.h> #include <ctype.h> + #include "lp.h" #include "lp.local.h" #include "pathnames.h" @@ -94,13 +95,13 @@ static const char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; static dev_t fdev; /* device of file pointed to by symlink */ static ino_t fino; /* inode of file pointed to by symlink */ static FILE *cfp; /* control file */ -static int child; /* id of any filters */ +static pid_t child; /* pid of any filters */ static int lfd; /* lock file descriptor */ static int ofd; /* output filter file descriptor */ -static int ofilter; /* id of output filter, if any */ +static pid_t ofilter; /* pid of output filter, if any */ static int pfd; /* prstatic inter file descriptor */ -static int pid; /* pid of lpd process */ -static int prchild; /* id of pr process */ +static pid_t pid; /* pid of lpd process */ +static pid_t prchild; /* pid of pr process */ static char title[80]; /* ``pr'' title */ static int tof; /* true if at top of form */ @@ -118,7 +119,7 @@ static char width[10] = "-w"; /* page width in static characters */ static void abortpr(int); static void banner(char *, char *); -static int dofork(int); +static pid_t dofork(int); static int dropit(int); static void init(void); static void openpr(void); @@ -144,18 +145,27 @@ printjob(void) struct stat stb; struct queue *q, **qp; struct queue **queue; - int i, nitems; + int i, fd, nitems; off_t pidoff; int errcnt, count = 0; init(); /* set up capabilities */ (void)write(STDOUT_FILENO, "", 1); /* ack that daemon is started */ - (void)close(STDERR_FILENO); /* set up log file */ - if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { + PRIV_START; + fd = open(LF, O_WRONLY|O_APPEND, 0664); /* set up log file */ + PRIV_END; + if (fd < 0) { syslog(LOG_ERR, "%s: %m", LF); - (void)open(_PATH_DEVNULL, O_WRONLY); + if ((fd = open(_PATH_DEVNULL, O_WRONLY)) < 0) + exit(1); + } + if (fd != STDERR_FILENO) { + if (dup2(fd, STDERR_FILENO) < 0) { + syslog(LOG_ERR, "dup2: %m"); + exit(1); + } + close(fd); } - setgid(getegid()); pid = getpid(); /* for use with lprm */ setpgrp(0, pid); signal(SIGHUP, abortpr); @@ -163,28 +173,23 @@ printjob(void) signal(SIGQUIT, abortpr); signal(SIGTERM, abortpr); - (void)mktemp(tempfile); /* safe */ - - /* - * uses short form file names - */ + /* so we can use short form file names */ if (chdir(SD) < 0) { syslog(LOG_ERR, "%s: %m", SD); exit(1); } - if (stat(LO, &stb) == 0 && (stb.st_mode & S_IXUSR)) - exit(0); /* printing disabled */ - lfd = open(LO, O_WRONLY|O_CREAT, 0644); + + (void)mktemp(tempfile); /* safe */ + + lfd = safe_open(LO, O_WRONLY|O_CREAT|O_NOFOLLOW|O_EXLOCK, 0640); if (lfd < 0) { - syslog(LOG_ERR, "%s: %s: %m", printer, LO); - exit(1); - } - if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { if (errno == EWOULDBLOCK) /* active daemon present */ exit(0); syslog(LOG_ERR, "%s: %s: %m", printer, LO); exit(1); } + if (fstat(lfd, &stb) == 0 && (stb.st_mode & S_IXUSR)) + exit(0); /* printing disabled */ ftruncate(lfd, 0); /* * write process id for others to know @@ -208,10 +213,14 @@ printjob(void) if (nitems == 0) /* no work to do */ exit(0); if (stb.st_mode & S_IXOTH) { /* reset queue flag */ - if (fchmod(lfd, stb.st_mode & 0776) < 0) + stb.st_mode &= ~S_IXOTH; + if (fchmod(lfd, stb.st_mode & 0777) < 0) syslog(LOG_ERR, "%s: %s: %m", printer, LO); } + PRIV_START; openpr(); /* open printer or remote */ + PRIV_END; + again: /* * we found something to do now do it -- @@ -246,7 +255,8 @@ again: if (stb.st_mode & S_IXOTH) { for (free((char *) q); nitems--; free((char *) q)) q = *qp++; - if (fchmod(lfd, stb.st_mode & 0776) < 0) + stb.st_mode &= ~S_IXOTH; + if (fchmod(lfd, stb.st_mode & 0777) < 0) syslog(LOG_WARNING, "%s: %s: %m", printer, LO); break; @@ -267,16 +277,20 @@ again: (void)close(pfd); /* close printer */ if (ftruncate(lfd, pidoff) < 0) syslog(LOG_WARNING, "%s: %s: %m", printer, LO); + PRIV_START; openpr(); /* try to reopen printer */ + PRIV_END; goto restart; } else { syslog(LOG_WARNING, "%s: job could not be %s (%s)", printer, remote ? "sent to remote host" : "printed", q->q_name); if (i == REPRINT) { /* ensure we don't attempt this job again */ + PRIV_START; (void)unlink(q->q_name); q->q_name[0] = 'd'; (void)unlink(q->q_name); + PRIV_END; if (logname[0]) sendmail(logname, FATALERR); } @@ -323,15 +337,18 @@ char ifonts[4][40] = { static int printit(char *file) { - int i; + int i, fd; char *cp; int bombed = OK; /* * open control file; ignore if no longer there. */ - if ((cfp = fopen(file, "r")) == NULL) { + fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0); + if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) { syslog(LOG_INFO, "%s: %s: %m", printer, file); + if (fd >= 0) + close(fd); return(OK); } /* @@ -521,14 +538,19 @@ pass2: static int print(int format, char *file) { - FILE *fp; - int status, serrno; + ssize_t nread; struct stat stb; + pid_t pid; char *prog, *av[15], buf[BUFSIZ]; - int n, fi, fo, pid, p[2], stopped = 0, nofile; + int fd, status, serrno; + int n, fi, fo, p[2], stopped = 0, nofile; - if (lstat(file, &stb) < 0 || (fi = open(file, O_RDONLY)) < 0) + PRIV_START; + if (lstat(file, &stb) < 0 || (fi = safe_open(file, O_RDONLY, 0)) < 0) { + PRIV_END; return(ERROR); + } + PRIV_END; /* * Check to see if data file is a symbolic link. If so, it should * still point to the same file or someone is trying to print @@ -590,7 +612,7 @@ print(int format, char *file) * For now, treat this as a plain-text file, and assume * the standard LPF_INPUT filter will recognize that it * is postscript and know what to do with it. These - * 'o'-file requests could come from MacOS 10.1 systems. + * 'o'-file requests could come from MacOS X systems. */ /* FALLTHROUGH */ case 'f': /* print plain text file */ @@ -618,7 +640,7 @@ print(int format, char *file) case 'n': /* print ditroff output */ case 'd': /* print tex output */ (void)unlink(".railmag"); - if ((fo = creat(".railmag", FILMOD)) < 0) { + if ((fo = open(".railmag", O_CREAT|O_WRONLY|O_EXCL, FILMOD)) < 0) { syslog(LOG_ERR, "%s: cannot create .railmag", printer); (void)unlink(".railmag"); } else { @@ -697,7 +719,7 @@ start: dup2(fi, 0); dup2(fo, 1); unlink(tempfile); - n = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0664); + n = open(tempfile, O_WRONLY|O_CREAT|O_EXCL, 0664); if (n >= 0) dup2(n, 2); closelog(); @@ -729,10 +751,11 @@ start: tof = 0; /* Copy filter output to "lf" logfile */ - if ((fp = fopen(tempfile, "r")) != NULL) { - while (fgets(buf, sizeof(buf), fp)) - fputs(buf, stderr); - fclose(fp); + fd = safe_open(tempfile, O_RDONLY|O_NOFOLLOW, 0); + if (fd >= 0) { + while ((nread = read(fd, buf, sizeof(buf))) > 0) + (void)write(STDERR_FILENO, buf, nread); + close(fd); } if (!WIFEXITED(status)) { @@ -750,7 +773,7 @@ start: return(ERROR); default: syslog(LOG_WARNING, "%s: filter '%c' exited (retcode=%d)", - printer, format, WEXITSTATUS(status)); + printer, format, WEXITSTATUS(status)); return(FILTERERR); } } @@ -763,13 +786,12 @@ start: static int sendit(char *file) { - int i, err = OK; + int fd, i, err = OK; char *cp, last[BUFSIZ]; - /* - * open control file - */ - if ((cfp = fopen(file, "r")) == NULL) + /* open control file */ + fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0); + if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) return(OK); /* * read the control file for work to do @@ -853,8 +875,12 @@ sendfile(int type, char *file) char buf[BUFSIZ]; int sizerr, resp; - if (lstat(file, &stb) < 0 || (f = open(file, O_RDONLY)) < 0) + PRIV_START; + if (lstat(file, &stb) < 0 || (f = safe_open(file, O_RDONLY, 0)) < 0) { + PRIV_END; return(ERROR); + } + PRIV_END; /* * Check to see if data file is a symbolic link. If so, it should * still point to the same file or someone is trying to print something @@ -1140,11 +1166,12 @@ sendmail(char *user, int bombed) /* * dofork - fork with retries on failure */ -static int +static pid_t dofork(int action) { - int i, pid; struct passwd *pw; + pid_t pid; + int i; for (i = 0; i < 20; i++) { if ((pid = fork()) < 0) { @@ -1155,6 +1182,7 @@ dofork(int action) * Child should run as daemon instead of root */ if (pid == 0) { + PRIV_START; pw = getpwuid(DU); if (pw == 0) { syslog(LOG_ERR, "uid %ld not in password file", @@ -1279,6 +1307,7 @@ init(void) /* * Acquire line printer or remote connection. + * XXX - should push down privs in here */ static void openpr(void) @@ -1477,7 +1506,7 @@ static void setty(void) { struct info i; - char **argv, **ap, *p, *val; + char **argv, **ap, **ep, *p, *val; i.fd = pfd; i.set = i.wset = 0; @@ -1514,19 +1543,26 @@ setty(void) syslog(LOG_INFO, "%s: ioctl(TIOCGWINSZ): %m", printer); - argv = (char **)calloc(256, sizeof(char *)); + argv = (char **)malloc(256 * sizeof(char *)); if (argv == NULL) { - syslog(LOG_ERR, "%s: calloc: %m", printer); + syslog(LOG_ERR, "%s: malloc: %m", printer); exit(1); } p = strdup(MS); ap = argv; + ep = argv + 255; while ((val = strsep(&p, " \t,")) != NULL) { if ((*ap++ = strdup(val)) == NULL) { syslog(LOG_ERR, "%s: strdup: %m", printer); exit(1); } + if (ap == ep) { + syslog(LOG_ERR, "%s: too many \"ms\" entries", + printer); + exit(1); + } } + *ap = NULL; for (; *argv; ++argv) { if (ksearch(&argv, &i)) @@ -1573,8 +1609,8 @@ pstatus(const char *msg, ...) va_start(ap, msg); umask(0); - fd = open(ST, O_WRONLY|O_CREAT, 0664); - if (fd < 0 || flock(fd, LOCK_EX) < 0) { + fd = open(ST, O_WRONLY|O_CREAT|O_NOFOLLOW|O_EXLOCK, 0660); + if (fd < 0) { syslog(LOG_ERR, "%s: %s: %m", printer, ST); exit(1); } diff --git a/usr.sbin/lpr/lpd/recvjob.c b/usr.sbin/lpr/lpd/recvjob.c index 2d2d9b0c0cc..4962d4175ec 100644 --- a/usr.sbin/lpr/lpd/recvjob.c +++ b/usr.sbin/lpr/lpd/recvjob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: recvjob.c,v 1.20 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: recvjob.c,v 1.21 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: recvjob.c,v 1.14 2001/12/04 22:52:44 christos Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95"; #else -static const char rcsid[] = "$OpenBSD: recvjob.c,v 1.20 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: recvjob.c,v 1.21 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -113,10 +113,12 @@ recvjob(void) LO = DEFLOCK; (void)close(2); /* set up log file */ + PRIV_START; if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) { syslog(LOG_ERR, "%s: %m", LF); (void)open(_PATH_DEVNULL, O_WRONLY); } + PRIV_END; if (chdir(SD) < 0) frecverr("%s: %s: %m", printer, SD); @@ -128,6 +130,7 @@ recvjob(void) } } else if (stat(SD, &stb) < 0) frecverr("%s: %s: %m", printer, SD); + minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */ signal(SIGTERM, rcleanup); signal(SIGPIPE, rcleanup); @@ -191,12 +194,22 @@ readjob(void) (void)write(STDOUT_FILENO, "\2", 1); continue; } + /* + * XXX + * We blindly believe what the remote host puts + * for the path to the df file. In general this + * is OK since we don't allow paths with '/' in + * them. Still, it would be better to sanity + * check the cf file sent to us and make the + * df name match the cf name we used. That way + * we avoid any possible collisions. + */ if (!readfile(tfname, size)) { rcleanup(0); continue; } if (link(tfname, cp) < 0) - frecverr("%s: %m", tfname); + frecverr("link %s %s: %m", tfname, cp); (void)unlink(tfname); tfname[0] = '\0'; nfiles++; @@ -233,8 +246,7 @@ readfile(char *file, int size) int i, j, amt; int fd, err; - fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD); - if (fd < 0) + if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, FILMOD)) < 0) frecverr("readfile: %s: illegal path name: %m", file); ack(); err = 0; @@ -311,7 +323,7 @@ read_number(char *fn) if ((fp = fopen(fn, "r")) == NULL) return (0); - if (fgets(lin, 80, fp) == NULL) { + if (fgets(lin, sizeof(lin), fp) == NULL) { fclose(fp); return (0); } diff --git a/usr.sbin/lpr/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile index 79e229243dd..dcf9ec818a7 100644 --- a/usr.sbin/lpr/lpq/Makefile +++ b/usr.sbin/lpr/lpq/Makefile @@ -1,12 +1,11 @@ # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $OpenBSD: Makefile,v 1.3 2002/05/20 23:13:50 millert Exp $ +# $OpenBSD: Makefile,v 1.4 2002/06/08 01:53:43 millert Exp $ PROG= lpq CFLAGS+=-I${.CURDIR}/../common_source SRCS= lpq.c displayq.c common.c common_vars.c -BINOWN= root BINGRP= daemon -BINMODE=6555 +BINMODE=2555 BINDIR= /usr/bin .PATH: ${.CURDIR}/../common_source diff --git a/usr.sbin/lpr/lpq/lpq.c b/usr.sbin/lpr/lpq/lpq.c index bc90790276d..1ca80fdd1cb 100644 --- a/usr.sbin/lpr/lpq/lpq.c +++ b/usr.sbin/lpr/lpq/lpq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lpq.c,v 1.12 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: lpq.c,v 1.13 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: lpq.c,v 1.9 1999/12/07 14:54:47 mrg Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95"; #else -static const char rcsid[] = "$OpenBSD: lpq.c,v 1.12 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: lpq.c,v 1.13 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -64,6 +64,7 @@ static const char rcsid[] = "$OpenBSD: lpq.c,v 1.12 2002/05/20 23:13:50 millert #include <ctype.h> #include <dirent.h> #include <err.h> +#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> @@ -90,9 +91,11 @@ main(int argc, char **argv) char *buf, *cp; long l; - euid = geteuid(); - uid = getuid(); - seteuid(uid); + effective_uid = geteuid(); + real_uid = getuid(); + effective_gid = getegid(); + real_gid = getgid(); + PRIV_END; /* be safe */ if (gethostname(host, sizeof(host)) != 0) err(1, "gethostname"); @@ -162,6 +165,7 @@ main(int argc, char **argv) exit(0); } +/* XXX - could be common w/ lpd */ static int ckqueue(char *cap) { diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile index c53d3fcfed2..4bc5e2b9b89 100644 --- a/usr.sbin/lpr/lpr/Makefile +++ b/usr.sbin/lpr/lpr/Makefile @@ -1,10 +1,10 @@ # from: @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $OpenBSD: Makefile,v 1.3 2002/05/20 23:13:50 millert Exp $ +# $OpenBSD: Makefile,v 1.4 2002/06/08 01:53:43 millert Exp $ PROG= lpr CFLAGS+=-I${.CURDIR}/../common_source SRCS= lpr.c startdaemon.c common.c common_vars.c -BINOWN= root +BINOWN= daemon BINGRP= daemon BINMODE=6555 BINDIR= /usr/bin diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c index 348a38b94d9..fbcd36e70fb 100644 --- a/usr.sbin/lpr/lpr/lpr.c +++ b/usr.sbin/lpr/lpr/lpr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lpr.c,v 1.25 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: lpr.c,v 1.26 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: lpr.c,v 1.19 2000/10/11 20:23:52 is Exp $ */ /* @@ -50,7 +50,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)lpr.c 8.4 (Berkeley) 4/28/95"; #else -static const char rcsid[] = "$OpenBSD: lpr.c,v 1.25 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: lpr.c,v 1.26 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -66,6 +66,7 @@ static const char rcsid[] = "$OpenBSD: lpr.c,v 1.25 2002/05/20 23:13:50 millert #include <sys/file.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> #include <a.out.h> #include <signal.h> @@ -103,7 +104,6 @@ static int sflag; /* symbolic link flag */ static int tfd; /* control file descriptor */ static char *tfname; /* tmp copy of cf before linking */ static char *title; /* pr'ing title */ -static int userid; /* user id */ static char *width; /* width for versatec printing */ static struct stat statb; @@ -132,9 +132,11 @@ main(int argc, char **argv) int i, f, ch; struct stat stb; - euid = geteuid(); - uid = getuid(); - seteuid(uid); + effective_uid = geteuid(); + real_uid = getuid(); + effective_gid = getegid(); + real_gid = getgid(); + PRIV_END; /* be safe */ if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, cleanup); @@ -260,16 +262,16 @@ main(int argc, char **argv) * Get the identity of the person doing the lpr using the same * algorithm as lprm. */ - userid = getuid(); - if (userid != DU || person == 0) { - if ((pw = getpwuid(userid)) == NULL) + if (real_uid != DU || person == NULL) { + if ((pw = getpwuid(real_uid)) == NULL) errx(1, "Who are you?"); - person = pw->pw_name; + if ((person = strdup(pw->pw_name)) == NULL) + err(1, NULL); } /* * Check for restricted group access. */ - if (RG != NULL && userid != DU) { + if (RG != NULL && real_uid != DU) { if ((gptr = getgrnam(RG)) == NULL) errx(1, "Restricted group specified incorrectly"); if (gptr->gr_gid != getgid()) { @@ -283,19 +285,16 @@ main(int argc, char **argv) } } /* - * Check to make sure queuing is enabled if userid is not root. + * Check to make sure queuing is enabled if real_uid is not root. */ (void)snprintf(buf, sizeof(buf), "%s/%s", SD, LO); - if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010)) + if (real_uid && stat(buf, &stb) == 0 && (stb.st_mode & 010)) errx(1, "Printer queue is disabled"); /* * Initialize the control file. */ mktemps(); tfd = nfile(tfname); - seteuid(euid); - (void)fchown(tfd, DU, -1); /* owned by daemon for protection */ - seteuid(uid); card('H', host); card('P', person); if (hdr) { @@ -354,7 +353,7 @@ main(int argc, char **argv) } if (sflag) warnx("%s: not linked, copying instead", arg); - if ((i = open(arg, O_RDONLY)) < 0) + if ((i = safe_open(arg, O_RDONLY, 0)) < 0) warn("%s", arg); else { copy(i, arg); @@ -370,8 +369,8 @@ main(int argc, char **argv) /* * Touch the control file to fix position in the queue. */ - seteuid(euid); - if ((tfd = open(tfname, O_RDWR)) >= 0) { + PRIV_START; + if ((tfd = safe_open(tfname, O_RDWR|O_NOFOLLOW, 0)) >= 0) { char c; if (read(tfd, &c, 1) == 1 && @@ -389,7 +388,7 @@ main(int argc, char **argv) cleanup(0); } unlink(tfname); - seteuid(uid); + PRIV_END; if (qflag) /* just q things up */ exit(0); if (!startdaemon(printer)) @@ -478,9 +477,9 @@ linked(file) return(NULL); file = buf; } - seteuid(euid); + PRIV_START; ret = symlink(file, dfname); - seteuid(uid); + PRIV_END; return(ret ? NULL : file); } @@ -519,18 +518,14 @@ nfile(n) int f; int oldumask = umask(0); /* should block signals */ - seteuid(euid); - f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD); + PRIV_START; + f = open(n, O_WRONLY|O_EXCL|O_CREAT, FILMOD); (void)umask(oldumask); if (f < 0) { warn("%s", n); cleanup(0); } - if (fchown(f, userid, -1) < 0) { - warn("cannot chown %s", n); - cleanup(0); /* cleanup does exit */ - } - seteuid(uid); + PRIV_END; if (++n[inchar] > 'z') { if (++n[inchar-2] == 't') { warnx("too many files - break up the job"); @@ -556,7 +551,7 @@ cleanup(signo) signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); i = inchar; - seteuid(euid); + PRIV_START; if (tfname) do unlink(tfname); @@ -588,20 +583,24 @@ test(file) int fd; char *cp; - if ((fd = open(file, O_RDONLY)) < 0) { - warn("cannot open %s\n", file); + if ((fd = open(file, O_RDONLY|O_NONBLOCK)) < 0) { + warn("cannot open %s", file); goto bad; } if (fstat(fd, &statb) < 0) { - warn("cannot stat %s\n", file); + warn("cannot stat %s", file); goto bad; } if (S_ISDIR(statb.st_mode)) { - warnx("%s is a directory\n", file); + warnx("%s is a directory", file); + goto bad; + } + if (!S_ISREG(statb.st_mode)) { + warnx("%s is not a regular file", file); goto bad; } if (statb.st_size == 0) { - warnx("%s is an empty file\n", file); + warnx("%s is an empty file", file); goto bad; } if (read(fd, &execb, sizeof(execb)) == sizeof(execb) && @@ -687,14 +686,16 @@ mktemps() int len, fd, n; char *cp; char buf[BUFSIZ]; + struct stat stb; - (void)snprintf(buf, sizeof(buf), "%s/.seq", SD); - seteuid(euid); - if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) - err(1, "cannot create %s", buf); + if (snprintf(buf, sizeof(buf), "%s/.seq", SD) >= sizeof(buf)) + errx(1, "%s/.seq: %s", SD, strerror(ENAMETOOLONG)); + PRIV_START; + if ((fd = safe_open(buf, O_RDWR|O_CREAT|O_NOFOLLOW, 0661)) < 0) + err(1, "cannot open %s", buf); if (flock(fd, LOCK_EX)) err(1, "cannot lock %s", buf); - seteuid(uid); + PRIV_END; n = 0; if ((len = read(fd, buf, sizeof(buf))) > 0) { for (cp = buf; len--; ) { @@ -704,11 +705,14 @@ mktemps() } } len = strlen(SD) + strlen(host) + 8; - tfname = lmktemp("tf", n, len); - cfname = lmktemp("cf", n, len); - dfname = lmktemp("df", n, len); + do { + tfname = lmktemp("tf", n, len); + cfname = lmktemp("cf", n, len); + dfname = lmktemp("df", n, len); + n = (n + 1) % 1000; + } while (stat(tfname, &stb) == 0 || stat(cfname, &stb) == 0 || + stat(dfname, &stb) == 0); inchar = strlen(SD) + 3; - n = (n + 1) % 1000; (void)lseek(fd, (off_t)0, 0); snprintf(buf, sizeof(buf), "%03d\n", n); (void)write(fd, buf, strlen(buf)); diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile index 968e100e65d..d132b8151b5 100644 --- a/usr.sbin/lpr/lprm/Makefile +++ b/usr.sbin/lpr/lprm/Makefile @@ -1,12 +1,11 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 -# $OpenBSD: Makefile,v 1.3 2002/05/20 23:13:50 millert Exp $ +# $OpenBSD: Makefile,v 1.4 2002/06/08 01:53:43 millert Exp $ PROG= lprm CFLAGS+=-I${.CURDIR}/../common_source SRCS= lprm.c rmjob.c startdaemon.c common.c common_vars.c -BINOWN= root BINGRP= daemon -BINMODE=6555 +BINMODE=2555 BINDIR= /usr/bin .PATH: ${.CURDIR}/../common_source diff --git a/usr.sbin/lpr/lprm/lprm.c b/usr.sbin/lpr/lprm/lprm.c index 4c7c0d949a9..0189767a996 100644 --- a/usr.sbin/lpr/lprm/lprm.c +++ b/usr.sbin/lpr/lprm/lprm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lprm.c,v 1.11 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: lprm.c,v 1.12 2002/06/08 01:53:43 millert Exp $ */ /* $$NetBSD: lprm.c,v 1.9 1999/08/16 03:12:32 simonb Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93"; #else -static const char rcsid[] = "$OpenBSD: lprm.c,v 1.11 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: lprm.c,v 1.12 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -65,6 +65,7 @@ static const char rcsid[] = "$OpenBSD: lprm.c,v 1.11 2002/05/20 23:13:50 millert #include <ctype.h> #include <dirent.h> #include <err.h> +#include <errno.h> #include <pwd.h> #include <stdlib.h> #include <stdio.h> @@ -96,13 +97,15 @@ main(int argc, char **argv) long l; int ch; - uid = getuid(); - euid = geteuid(); - seteuid(uid); /* be safe */ + effective_uid = geteuid(); + real_uid = getuid(); + effective_gid = getegid(); + real_gid = getgid(); + PRIV_END; /* be safe */ gethostname(host, sizeof(host)); openlog("lprm", 0, LOG_LPR); - if ((p = getpwuid(getuid())) == NULL) + if ((p = getpwuid(real_uid)) == NULL) fatal("Who are you?"); if (strlen(p->pw_name) >= sizeof(luser)) fatal("Your name is too long"); diff --git a/usr.sbin/lpr/pac/pac.c b/usr.sbin/lpr/pac/pac.c index 3da340f36cd..bb8efb45782 100644 --- a/usr.sbin/lpr/pac/pac.c +++ b/usr.sbin/lpr/pac/pac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pac.c,v 1.13 2002/05/20 23:13:50 millert Exp $ */ +/* $OpenBSD: pac.c,v 1.14 2002/06/08 01:53:43 millert Exp $ */ /* $NetBSD: pac.c,v 1.14 2000/04/27 13:40:18 msaitoh Exp $ */ /* @@ -45,7 +45,7 @@ static const char copyright[] = #if 0 static const char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93"; #else -static const char rcsid[] = "$OpenBSD: pac.c,v 1.13 2002/05/20 23:13:50 millert Exp $"; +static const char rcsid[] = "$OpenBSD: pac.c,v 1.14 2002/06/08 01:53:43 millert Exp $"; #endif #endif /* not lint */ @@ -119,8 +119,12 @@ main(int argc, char **argv) FILE *acct; int ch; - euid = geteuid(); /* these aren't used in pac(1) */ - uid = getuid(); + /* these aren't actually used in pac(1) */ + effective_uid = geteuid(); + real_uid = getuid(); + effective_gid = getegid(); + real_gid = getgid(); + while ((ch = getopt(argc, argv, "P:p:scmr")) != -1) { switch (ch) { case 'P': |