diff options
Diffstat (limited to 'usr.sbin/lpr/lpd/lpd.c')
-rw-r--r-- | usr.sbin/lpr/lpd/lpd.c | 81 |
1 files changed, 55 insertions, 26 deletions
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; |