From 16c2ffab14daba8ec85369749a7f5da0849d2d55 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sat, 8 Jun 2002 01:53:44 +0000 Subject: Remove setuid root from lp*. lpr needs to be setuid daemon so the files it creates are not owned by the user spooling them but the others (lpc, lpq, lprm) can get away with setgid daemon. lpd runs as user daemon for most things, only changing its uid to 0 for things that must be done as root. For the time being, don't require connections to come from a reserved port since lpq/lpr/lprm can't acquire that w/o setuid root. In the near future we will have a mechanism for select non-root processes to grab reserved ports. The upshot of this is that spool directories must be writable by group daemon and the files within the spool dirs must be owned by daemon. --- usr.sbin/lpr/SMM.doc/0.t | 18 ++-- usr.sbin/lpr/SMM.doc/2.t | 6 +- usr.sbin/lpr/SMM.doc/3.t | 46 +++++----- usr.sbin/lpr/SMM.doc/4.t | 17 ++-- usr.sbin/lpr/SMM.doc/5.t | 4 +- usr.sbin/lpr/SMM.doc/6.t | 12 ++- usr.sbin/lpr/SMM.doc/7.t | 8 +- usr.sbin/lpr/SMM.doc/spell.ok | 2 +- usr.sbin/lpr/common_source/common.c | 59 ++++++++++--- usr.sbin/lpr/common_source/common_vars.c | 7 +- usr.sbin/lpr/common_source/displayq.c | 80 ++++++++++-------- usr.sbin/lpr/common_source/lp.h | 24 +++++- usr.sbin/lpr/common_source/rmjob.c | 72 +++++++++------- usr.sbin/lpr/common_source/startdaemon.c | 14 ++-- usr.sbin/lpr/lpc/cmds.c | 140 +++++++++++++++++++------------ usr.sbin/lpr/lpc/lpc.8 | 4 +- usr.sbin/lpr/lpc/lpc.c | 16 ++-- usr.sbin/lpr/lpd/Makefile | 4 +- usr.sbin/lpr/lpd/lpd.c | 81 ++++++++++++------ usr.sbin/lpr/lpd/printjob.c | 140 +++++++++++++++++++------------ usr.sbin/lpr/lpd/recvjob.c | 24 ++++-- usr.sbin/lpr/lpq/Makefile | 5 +- usr.sbin/lpr/lpq/lpq.c | 14 ++-- usr.sbin/lpr/lpr/Makefile | 4 +- usr.sbin/lpr/lpr/lpr.c | 92 ++++++++++---------- usr.sbin/lpr/lprm/Makefile | 5 +- usr.sbin/lpr/lprm/lprm.c | 15 ++-- usr.sbin/lpr/pac/pac.c | 12 ++- 28 files changed, 563 insertions(+), 362 deletions(-) (limited to 'usr.sbin') 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 #include +#include #include #include #include @@ -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 @@ -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 -#include #include - -#include -#include #include +#include + +#include +#include #include -#include +#include +#include #include #include #include -#include +#include + #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 __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 #include +#include #include #include #include @@ -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 #include #include + #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 @@ -94,6 +96,7 @@ static const char rcsid[] = "$OpenBSD: lpd.c,v 1.32 2002/05/28 18:17:22 millert #include #include #include +#include #include #include #include @@ -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 #include #include + #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 #include #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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': -- cgit v1.2.3