From 6b3d90cecd5cb04f150acca617c1c33226b12276 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 7 Jan 2002 03:44:31 +0000 Subject: To disable a SIGCHLD signal handler use SIG_DFL, *not* SIG_IGN which now has a different meaning. --- usr.sbin/lpr/lpd/lpd.c | 183 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 123 insertions(+), 60 deletions(-) (limited to 'usr.sbin') diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c index 6d38a974c54..fe1824eb3fe 100644 --- a/usr.sbin/lpr/lpd/lpd.c +++ b/usr.sbin/lpr/lpd/lpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lpd.c,v 1.24 2001/12/06 03:12:30 ericj Exp $ */ +/* $OpenBSD: lpd.c,v 1.25 2002/01/07 03:44:30 millert Exp $ */ /* $NetBSD: lpd.c,v 1.7 1996/04/24 14:54:06 mrg 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.24 2001/12/06 03:12:30 ericj Exp $"; +static const char rcsid[] = "$OpenBSD: lpd.c,v 1.25 2002/01/07 03:44:30 millert Exp $"; #endif #endif /* not lint */ @@ -92,6 +92,7 @@ static const char rcsid[] = "$OpenBSD: lpd.c,v 1.24 2001/12/06 03:12:30 ericj Ex #include #include #include +#include #include #include #include @@ -99,22 +100,31 @@ static const char rcsid[] = "$OpenBSD: lpd.c,v 1.24 2001/12/06 03:12:30 ericj Ex #include #include #include + #include "lp.h" #include "lp.local.h" #include "pathnames.h" #include "extern.h" -extern int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *)); +#define LPD_NOPORTCHK 0001 /* skip reserved-port check */ int lflag; /* log requests flag */ +int rflag; /* allow 'of' for remote printers */ +int sflag; /* secure (no inet) flag */ int from_remote; /* from remote socket */ +uid_t uid; /* real uid */ +uid_t euid; /* effective uid */ +volatile sig_atomic_t child_count; /* number of kids forked */ + +static void reapchild __P((int)); +static void mcleanup __P((int)); +static void doit __P((void)); +static void startup __P((void)); +static void chkhost __P((struct sockaddr_in *)); +static int ckqueue __P((char *)); +static __dead void usage __P((void)); -static void reapchild __P((int)); -static void mcleanup __P((int)); -static void doit __P((void)); -static void startup __P((void)); -static void chkhost __P((struct sockaddr_in *)); -static int ckqueue __P((char *)); +extern int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *)); /* unused, needed for lpc */ volatile sig_atomic_t gotintr; @@ -122,39 +132,66 @@ volatile sig_atomic_t gotintr; uid_t uid, euid; int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { - int f, lfd, funix, finet, options, fromlen; + int f, funix, finet, options, check_options, fromlen, ch, lfd; fd_set defreadfds; + long child_max = 32; /* more then enough to hose the system */ int maxfd = 0; + char *cp; struct sockaddr_un un, fromunix; struct sockaddr_in sin, frominet; sigset_t mask, omask; euid = geteuid(); /* these shouldn't be different */ uid = getuid(); - options = 0; + options = check_options = 0; gethostname(host, sizeof(host)); - if (euid != 0) { - fprintf(stderr,"lpd: must run as root\n"); - exit(1); - } + if (euid != 0) + err(1, "must run as root"); - while (--argc > 0) { - argv++; - if (argv[0][0] == '-') - switch (argv[0][1]) { - case 'd': - options |= SO_DEBUG; - break; - case 'l': - lflag++; - break; - } + while ((ch = getopt(argc, argv, "dln:rsw:W")) != -1) { + switch (ch) { + case 'd': + options |= SO_DEBUG; + break; + case 'l': + lflag++; + break; + case 'n': + child_max = strtol(optarg, &cp, 10); + if (*cp != '\0' || child_max < 0 || child_max > 1024) + errx(1, "invalid number of children: %s", + optarg); + case 'r': + rflag++; + break; + case 's': + sflag++; + break; + case 'w': + wait_time = strtol(optarg, &cp, 10); + if (*cp != '\0' || wait_time < 0) + errx(1, "wait time must be postive integer: %s", + optarg); + if (wait_time < 30) + warnx("warning: wait time less than 30 seconds"); + break; + case 'W': + /* + * Allow connections coming from a non-reserved port. + * (done by some lpr-implementations for MS-Windows) + */ + check_options |= LPD_NOPORTCHK; + break; + default: + usage(); + break; + } } + argc -= optind; + argv += optind; #ifndef DEBUG /* @@ -165,7 +202,7 @@ main(argc, argv) openlog("lpd", LOG_PID, LOG_LPR); syslog(LOG_INFO, "restarted"); - (void) umask(0); + (void)umask(0); lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); if (lfd < 0) { syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); @@ -181,7 +218,7 @@ main(argc, argv) /* * write process id for others to know */ - sprintf(line, "%u\n", getpid()); + (void)snprintf(line, sizeof(line), "%u\n", getpid()); f = strlen(line); if (write(lfd, line, f) != f) { syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); @@ -192,8 +229,8 @@ main(argc, argv) * Restart all the printers. */ startup(); - (void) unlink(_PATH_SOCKETNAME); - funix = socket(AF_UNIX, SOCK_STREAM, 0); + (void)unlink(_PATH_SOCKETNAME); + funix = socket(AF_LOCAL, SOCK_STREAM, 0); if (funix < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); @@ -204,14 +241,14 @@ main(argc, argv) sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGTERM); sigprocmask(SIG_BLOCK, &mask, &omask); - (void) umask(07); + (void)umask(07); signal(SIGHUP, mcleanup); signal(SIGINT, mcleanup); signal(SIGQUIT, mcleanup); signal(SIGTERM, mcleanup); memset(&un, 0, sizeof(un)); - un.sun_family = AF_UNIX; - strcpy(un.sun_path, _PATH_SOCKETNAME); + un.sun_family = AF_LOCAL; + strlcpy(un.sun_path, _PATH_SOCKETNAME, sizeof(un.sun_path)); #ifndef SUN_LEN #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) #endif @@ -219,14 +256,14 @@ main(argc, argv) syslog(LOG_ERR, "ubind: %m"); exit(1); } - (void) umask(0); + (void)umask(0); sigprocmask(SIG_SETMASK, &omask, NULL); FD_ZERO(&defreadfds); FD_SET(funix, &defreadfds); if (funix > maxfd) maxfd = funix; listen(funix, 5); - finet = socket(AF_INET, SOCK_STREAM, 0); + finet = sflag ? -1 : socket(AF_INET, SOCK_STREAM, 0); if (finet >= 0) { struct servent *sp; @@ -237,7 +274,7 @@ main(argc, argv) } } f = 1; - (void) setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &f, + (void)setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); sp = getservbyname("printer", "tcp"); if (sp == NULL) { @@ -264,6 +301,19 @@ main(argc, argv) for (;;) { int domain, nfds, s; fd_set readfds; + short sleeptime = 10; /* overflows in about 2 hours */ + + while (child_max < child_count) { + syslog(LOG_WARNING, + "too many children, sleeping for %d seconds", + sleeptime); + sleep(sleeptime); + sleeptime <<= 1; + if (sleeptime < 0) { + syslog(LOG_CRIT, "sleeptime overflowed! help!"); + sleeptime = 10; + } + } FD_COPY(&defreadfds, &readfds); nfds = select(maxfd + 1, &readfds, 0, 0, 0); @@ -273,7 +323,7 @@ main(argc, argv) continue; } if (FD_ISSET(funix, &readfds)) { - domain = AF_UNIX, fromlen = sizeof(fromunix); + domain = AF_LOCAL, fromlen = sizeof(fromunix); s = accept(funix, (struct sockaddr *)&fromunix, &fromlen); } else /* if (FD_ISSET(finet, &readfds)) */ { @@ -290,17 +340,19 @@ main(argc, argv) syslog(LOG_WARNING, "accept: %m"); continue; } - if (fork() == 0) { - signal(SIGCHLD, SIG_IGN); + switch (fork()) { + case 0: + signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTERM, SIG_IGN); - (void) close(funix); - (void) close(finet); + (void)close(funix); + if (finet != -1) + (void)close(finet); if (s != STDOUT_FILENO) { dup2(s, STDOUT_FILENO); - (void) close(s); + (void)close(s); } if (domain == AF_INET) { from_remote = 1; @@ -309,26 +361,30 @@ main(argc, argv) from_remote = 0; doit(); exit(0); + case -1: + syslog(LOG_WARNING, "fork: %m, sleeping for 10 seconds..."); + sleep(10); + continue; + default: + child_count++; } - (void) close(s); + (void)close(s); } } static void -reapchild(signo) - int signo; +reapchild(int signo) { int save_errno = errno; int status; while (waitpid((pid_t)-1, &status, WNOHANG) > 0) - ; + child_count--; errno = save_errno; } static void -mcleanup(signo) - int signo; +mcleanup(int signo) { struct syslog_data sdata = SYSLOG_DATA_INIT; @@ -359,7 +415,7 @@ char *cmdnames[] = { }; static void -doit() +doit(void) { char *cp; int n; @@ -467,7 +523,7 @@ doit() * files left from the last time the machine went down. */ static void -startup() +startup(void) { char *buf; char *cp; @@ -506,8 +562,7 @@ startup() * Make sure there's some work to do before forking off a child */ static int -ckqueue(cap) - char *cap; +ckqueue(char *cap) { struct dirent *d; DIR *dirp; @@ -533,8 +588,7 @@ ckqueue(cap) * Check to see if the from host has access to the line printer. */ static void -chkhost(f) - struct sockaddr_in *f; +chkhost(struct sockaddr_in *f) { struct hostent *hp; FILE *hostf; @@ -548,7 +602,7 @@ chkhost(f) fatal("Host name for your address (%s) unknown", inet_ntoa(f->sin_addr)); - (void) strlcpy(fromb, hp->h_name, sizeof(fromb)); + (void)strlcpy(fromb, hp->h_name, sizeof(fromb)); from = fromb; /* Check for spoof, ala rlogind */ @@ -570,10 +624,10 @@ again: if (hostf) { if (__ivaliduser(hostf, f->sin_addr.s_addr, DUMMY, DUMMY) == 0) { - (void) fclose(hostf); + (void)fclose(hostf); return; } - (void) fclose(hostf); + (void)fclose(hostf); } if (first == 1) { first = 0; @@ -583,3 +637,12 @@ again: fatal("Your host does not have line printer access"); /*NOTREACHED*/ } + +static void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-dls]\n", __progname); + exit(1); +} -- cgit v1.2.3