- add timeouts to displayq(), rmremote(), sendfile() and response(),

and use these timeout in the lpq, lpd and lprm programs.

these stop hung remote printers that accept tcp connections but do
not process jobs from hanging the whole system and letting the sysadmin
have a clue about what is going on with this rogue printer.

- add a -r flag to lpd to allow `of' filters for remote jobs.

i know there are ways around this, but i just don't care.

- add a -f flag to lpf to add missing carriage returns.

useful when printing UNIX files to an, eg, LaserWriter that wants CR's
as well as LF's in raw text.  stair-stepped text is no fun.

- implement child process accounting: we just have a limit on the number
  of children we can have (settable by the sysadmin), and we sleep when
  this number is reached.  this can reduce malicious not-so-malicious
  attacks on the print server by a rogue remote client..

- use setproctitle() where appropriate so the sysadmin has a clue about
  what each of the lpd's here are doing.

this was useful to help diagnose a problem (that the above child process
accounting change reduces the lossages of) where a rogue client was
attempting "lpq" operations on one stuck queue in rapid succession,
causing the lpd server to be extremely slow, due to the large number
of lpd processes running.


i have been running these changes in production for about a year.
This commit is contained in:
mrg 1999-12-07 14:54:44 +00:00
parent 8ad73e9274
commit 5b6d0e7e39
8 changed files with 222 additions and 63 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: displayq.c,v 1.16 1999/09/26 10:32:27 mrg Exp $ */
/* $NetBSD: displayq.c,v 1.17 1999/12/07 14:54:44 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: displayq.c,v 1.16 1999/09/26 10:32:27 mrg Exp $");
__RCSID("$NetBSD: displayq.c,v 1.17 1999/12/07 14:54:44 mrg Exp $");
#endif
#endif /* not lint */
@ -87,6 +87,10 @@ static long totsize; /* total print job size in bytes */
static char *head0 = "Rank Owner Job Files";
static char *head1 = "Total Size\n";
static void alarmer __P((int));
int wait_time = 300; /* time out after 5 minutes by default */
/*
* Display the current state of the queue. Format = 1 if long format.
*/
@ -257,15 +261,34 @@ displayq(format)
(void)printf("connection to %s is down\n", RM);
}
else {
struct sigaction osa, nsa;
i = strlen(line);
if (write(fd, line, (size_t)i) != i)
fatal("Lost connection");
while ((i = read(fd, line, sizeof(line))) > 0)
nsa.sa_handler = alarmer;
sigemptyset(&nsa.sa_mask);
sigaddset(&nsa.sa_mask, SIGALRM);
nsa.sa_flags = 0;
(void)sigaction(SIGALRM, &nsa, &osa);
alarm(wait_time);
while ((i = read(fd, line, sizeof(line))) > 0) {
(void)fwrite(line, 1, (size_t)i, stdout);
alarm(wait_time);
}
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
(void)close(fd);
}
}
static void
alarmer(s)
int s;
{
/* nothing */
}
/*
* Print a warning message if there is no daemon present.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: lp.h,v 1.12 1998/07/07 03:36:53 mrg Exp $ */
/* $NetBSD: lp.h,v 1.13 1999/12/07 14:54:44 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -90,6 +90,7 @@ extern char host[MAXHOSTNAMELEN + 1];
extern char *from; /* client's machine name */
extern int remote; /* true if sending files to a remote host */
extern char *printcapdb[]; /* printcap database array */
extern int wait_time; /* time to wait for remote responses */
/*
* Structure used for building a sorted list of control files.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: rmjob.c,v 1.14 1999/09/26 10:32:27 mrg Exp $ */
/* $NetBSD: rmjob.c,v 1.15 1999/12/07 14:54:45 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: rmjob.c,v 1.14 1999/09/26 10:32:27 mrg Exp $");
__RCSID("$NetBSD: rmjob.c,v 1.15 1999/12/07 14:54:45 mrg Exp $");
#endif
#endif /* not lint */
@ -77,6 +77,7 @@ static char current[40]; /* active control file name */
extern uid_t uid, euid; /* real and effective user id's */
static void do_unlink __P((char *));
static void alarmer __P((int));
void
rmjob()
@ -369,16 +370,35 @@ rmremote()
printf("%s: ", host);
printf("connection to %s is down\n", RM);
} else {
struct sigaction osa, nsa;
if (write(rem, s, len) != len)
fatal("Lost connection");
if (len > sizeof(line))
(void)free(s);
while ((i = read(rem, line, sizeof(line))) > 0)
nsa.sa_handler = alarmer;
sigemptyset(&nsa.sa_mask);
sigaddset(&nsa.sa_mask, SIGALRM);
nsa.sa_flags = 0;
(void)sigaction(SIGALRM, &nsa, &osa);
alarm(wait_time);
while ((i = read(rem, line, sizeof(line))) > 0) {
(void)fwrite(line, 1, (size_t)i, stdout);
alarm(wait_time);
}
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
(void)close(rem);
}
}
static void
alarmer(s)
int s;
{
/* nothing */
}
/*
* Return 1 if the filename begins with 'cf'
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: lpf.c,v 1.6 1997/10/05 15:12:05 mrg Exp $ */
/* $NetBSD: lpf.c,v 1.7 1999/12/07 14:54:46 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)lpf.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: lpf.c,v 1.6 1997/10/05 15:12:05 mrg Exp $");
__RCSID("$NetBSD: lpf.c,v 1.7 1999/12/07 14:54:46 mrg Exp $");
#endif
#endif /* not lint */
@ -71,6 +71,8 @@ int literal; /* print control characters */
char *name; /* user's login name */
char *host; /* user's machine name */
char *acctfile; /* accounting information file */
int crnl; /* \n -> \r\n */
int need_cr;
int main __P((int, char *[]));
@ -82,7 +84,7 @@ main(argc, argv)
FILE *p = stdin, *o = stdout;
int i, col;
char *cp;
int done, linedone, maxrep, ch;
int done, linedone, maxrep, ch, prch;
char *limit;
while (--argc) {
@ -114,6 +116,10 @@ main(argc, argv)
case 'c': /* Print control chars */
literal++;
break;
case 'f': /* Fix missing carriage returns */
crnl++;
break;
}
} else
acctfile = cp;
@ -126,7 +132,10 @@ main(argc, argv)
col = indent;
maxrep = -1;
linedone = 0;
prch = ch = 0;
need_cr = 0;
while (!linedone) {
prch = ch;
switch (ch = getc(p)) {
case EOF:
linedone = done = 1;
@ -136,6 +145,8 @@ main(argc, argv)
case '\f':
lineno = length;
case '\n':
if (crnl && prch != '\r')
need_cr = 1;
if (maxrep < 0)
maxrep = 0;
linedone = 1;
@ -199,8 +210,11 @@ main(argc, argv)
}
if (i < maxrep)
putc('\r', o);
else
else {
if (need_cr)
putc('\r', o);
putc(ch, o);
}
if (++lineno >= length) {
fflush(o);
npages++;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lpd.c,v 1.17 1998/07/18 05:04:40 lukem Exp $ */
/* $NetBSD: lpd.c,v 1.18 1999/12/07 14:54:46 mrg Exp $ */
/*
* Copyright (c) 1983, 1993, 1994
@ -45,7 +45,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993, 1994\n\
#if 0
static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
#else
__RCSID("$NetBSD: lpd.c,v 1.17 1998/07/18 05:04:40 lukem Exp $");
__RCSID("$NetBSD: lpd.c,v 1.18 1999/12/07 14:54:46 mrg Exp $");
#endif
#endif /* not lint */
@ -87,6 +87,7 @@ __RCSID("$NetBSD: lpd.c,v 1.17 1998/07/18 05:04:40 lukem Exp $");
#include <sys/file.h>
#include <netinet/in.h>
#include <err.h>
#include <netdb.h>
#include <unistd.h>
#include <syslog.h>
@ -106,6 +107,7 @@ __RCSID("$NetBSD: lpd.c,v 1.17 1998/07/18 05:04:40 lukem Exp $");
#include "extern.h"
int lflag; /* log requests flag */
int rflag; /* allow of for remote printers */
int sflag; /* secure (no inet) flag */
int from_remote; /* from remote socket */
@ -119,6 +121,7 @@ static int ckqueue __P((char *));
static void usage __P((void));
uid_t uid, euid;
int child_count;
int
main(argc, argv)
@ -130,6 +133,7 @@ main(argc, argv)
struct sockaddr_un un, fromunix;
struct sockaddr_in sin, frominet;
int omask, lfd, errs, i;
int child_max = 32; /* more then enough to hose the system */
euid = geteuid(); /* these shouldn't be different */
uid = getuid();
@ -139,7 +143,7 @@ main(argc, argv)
name = argv[0];
errs = 0;
while ((i = getopt(argc, argv, "dls")) != -1)
while ((i = getopt(argc, argv, "dln:srw:")) != -1)
switch (i) {
case 'd':
options |= SO_DEBUG;
@ -147,9 +151,26 @@ main(argc, argv)
case 'l':
lflag++;
break;
case 'n':
child_max = atoi(optarg);
if (child_max < 0 || child_max > 1024)
errx(1, "invalid number of children: %s",
optarg);
break;
case 'r':
rflag++;
break;
case 's':
sflag++;
break;
case 'w':
wait_time = atoi(optarg);
if (wait_time < 0)
errx(1, "wait time must be postive: %s",
optarg);
if (wait_time < 30)
warnx("warning: wait time less than 30 seconds");
break;
default:
errs++;
}
@ -255,6 +276,20 @@ main(argc, argv)
for (;;) {
int domain, nfds, s;
fd_set readfds;
/* "short" so it overflows in about 2 hours */
short sleeptime = 10;
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(20, &readfds, 0, 0, 0);
@ -277,7 +312,9 @@ main(argc, argv)
syslog(LOG_WARNING, "accept: %m");
continue;
}
if (fork() == 0) {
switch (fork()) {
case 0:
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
@ -295,6 +332,12 @@ 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);
}
@ -307,7 +350,7 @@ reapchild(signo)
union wait status;
while (wait3((int *)&status, WNOHANG, 0) > 0)
;
child_count--;
}
static void
@ -360,9 +403,12 @@ doit()
*--cp = '\0';
cp = cbuf;
if (lflag) {
if (*cp >= '\1' && *cp <= '\5')
if (*cp >= '\1' && *cp <= '\5') {
syslog(LOG_INFO, "%s requests %s %s",
from, cmdnames[(int)*cp], cp+1);
setproctitle("serving %s: %s %s", from,
cmdnames[(int)*cp], cp+1);
}
else
syslog(LOG_INFO, "bad request (%d) from %s",
*cp, from);
@ -453,7 +499,6 @@ startup()
{
char *buf;
char *cp;
int pid;
/*
* Restart the daemons.
@ -470,17 +515,20 @@ startup()
}
if (lflag)
syslog(LOG_INFO, "work for %s", buf);
if ((pid = fork()) < 0) {
switch (fork()) {
case -1:
syslog(LOG_WARNING, "startup: cannot fork");
mcleanup(0);
}
if (!pid) {
case 0:
printer = buf;
setproctitle("working on printer %s", printer);
cgetclose();
printjob();
/* NOTREACHED */
default:
child_count++;
free(buf);
}
else free(buf);
}
}
@ -550,6 +598,7 @@ chkhost(f)
if (good == 0)
fatal("address for your hostname (%s) not matched",
inet_ntoa(f->sin_addr));
setproctitle("serving %s", from);
hostf = fopen(_PATH_HOSTSEQUIV, "r");
again:
if (hostf) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: printjob.c,v 1.20 1999/09/26 10:32:28 mrg Exp $ */
/* $NetBSD: printjob.c,v 1.21 1999/12/07 14:54:47 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -45,7 +45,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95";
#else
__RCSID("$NetBSD: printjob.c,v 1.20 1999/09/26 10:32:28 mrg Exp $");
__RCSID("$NetBSD: printjob.c,v 1.21 1999/12/07 14:54:47 mrg Exp $");
#endif
#endif /* not lint */
@ -94,18 +94,18 @@ __RCSID("$NetBSD: printjob.c,v 1.20 1999/09/26 10:32:28 mrg Exp $");
#define FILTERERR 3
#define ACCESS 4
static dev_t fdev; /* device of file pointed to by symlink */
static ino_t fino; /* inode of file pointed to by symlink */
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 int lfd; /* lock file descriptor */
static int ofd; /* output filter file descriptor */
static int ofilter; /* id 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 char title[80]; /* ``pr'' title */
static int tof; /* true if at top of form */
static int child; /* id 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 int pfd; /* prstatic inter file descriptor */
static int pid; /* pid of lpd process */
static int prchild; /* id of pr process */
static char title[80]; /* ``pr'' title */
static int tof; /* true if at top of form */
static char class[32]; /* classification field */
static char fromhost[32]; /* user's host machine */
@ -119,25 +119,26 @@ static char pxwidth[10] = "-x"; /* page width in pixels */
static char tempfile[] = "errsXXXXXX"; /* file name for filter output */
static char width[10] = "-w"; /* page width in static characters */
static void abortpr __P((int));
static void banner __P((char *, char *));
static int dofork __P((int));
static int dropit __P((int));
static void init __P((void));
static void openpr __P((void));
static void opennet __P((char *));
static void opentty __P((void));
static void openrem __P((void));
static int print __P((int, char *));
static int printit __P((char *));
static void pstatus __P((const char *, ...));
static char response __P((void));
static void scan_out __P((int, char *, int));
static char *scnline __P((int, char *, int));
static int sendfile __P((int, char *));
static int sendit __P((char *));
static void sendmail __P((char *, int));
static void setty __P((void));
static void abortpr __P((int));
static void banner __P((char *, char *));
static int dofork __P((int));
static int dropit __P((int));
static void init __P((void));
static void openpr __P((void));
static void opennet __P((char *));
static void opentty __P((void));
static void openrem __P((void));
static int print __P((int, char *));
static int printit __P((char *));
static void pstatus __P((const char *, ...));
static char response __P((void));
static void scan_out __P((int, char *, int));
static char *scnline __P((int, char *, int));
static int sendfile __P((int, char *));
static int sendit __P((char *));
static void sendmail __P((char *, int));
static void setty __P((void));
static void alarmer __P((int));
void
printjob()
@ -869,7 +870,7 @@ sendfile(type, file)
return(ACCESS);
amt = snprintf(buf, sizeof(buf), "%c%qd %s\n", type,
(long long)stb.st_size, file);
for (i = 0; ; i++) {
for (i = 0; ; i++) {
if (write(pfd, buf, amt) != amt ||
(resp = response()) < 0 || resp == '\1') {
(void)close(f);
@ -887,15 +888,27 @@ sendfile(type, file)
pstatus("sending to %s", RM);
sizerr = 0;
for (i = 0; i < stb.st_size; i += BUFSIZ) {
struct sigaction osa, nsa;
amt = BUFSIZ;
if (i + amt > stb.st_size)
amt = stb.st_size - i;
if (sizerr == 0 && read(f, buf, amt) != amt)
sizerr = 1;
nsa.sa_handler = alarmer;
sigemptyset(&nsa.sa_mask);
sigaddset(&nsa.sa_mask, SIGALRM);
nsa.sa_flags = 0;
(void)sigaction(SIGALRM, &nsa, &osa);
alarm(wait_time);
if (write(pfd, buf, amt) != amt) {
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
(void)close(f);
return(REPRINT);
}
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
}
(void)close(f);
@ -918,13 +931,22 @@ sendfile(type, file)
static char
response()
{
struct sigaction osa, nsa;
char resp;
nsa.sa_handler = alarmer;
sigemptyset(&nsa.sa_mask);
sigaddset(&nsa.sa_mask, SIGALRM);
nsa.sa_flags = 0;
(void)sigaction(SIGALRM, &nsa, &osa);
alarm(wait_time);
if (read(pfd, &resp, 1) != 1) {
syslog(LOG_INFO, "%s: lost connection", printer);
return(-1);
resp = -1;
}
return(resp);
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
return (resp);
}
/*
@ -1276,6 +1298,7 @@ openpr()
{
int i, nofile;
char *cp;
extern int rflag;
if (!remote && *LP) {
if ((cp = strchr(LP, '@')))
@ -1293,7 +1316,7 @@ openpr()
/*
* Start up an output filter, if needed.
*/
if (!remote && OF) {
if ((!remote || rflag) && OF) {
int p[2];
pipe(p);
@ -1427,6 +1450,13 @@ openrem()
pstatus("sending to %s", RM);
}
static void
alarmer(s)
int s;
{
/* nothing */
}
#if !defined(__NetBSD__)
struct bauds {
int baud;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lpq.c,v 1.8 1998/07/06 07:03:28 mrg Exp $ */
/* $NetBSD: lpq.c,v 1.9 1999/12/07 14:54:47 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -41,7 +41,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95";
#else
__RCSID("$NetBSD: lpq.c,v 1.8 1998/07/06 07:03:28 mrg Exp $");
__RCSID("$NetBSD: lpq.c,v 1.9 1999/12/07 14:54:47 mrg Exp $");
#endif
#endif /* not lint */
@ -99,7 +99,7 @@ main(argc, argv)
openlog("lpd", 0, LOG_LPR);
aflag = lflag = 0;
while ((ch = getopt(argc, argv, "alP:")) != -1)
while ((ch = getopt(argc, argv, "alP:w:")) != -1)
switch((char)ch) {
case 'a':
++aflag;
@ -110,6 +110,14 @@ main(argc, argv)
case 'P': /* printer name */
printer = optarg;
break;
case 'w':
wait_time = atoi(optarg);
if (wait_time < 0)
errx(1, "wait time must be postive: %s",
optarg);
if (wait_time < 30)
warnx("warning: wait time less than 30 seconds");
break;
case '?':
default:
usage();

View File

@ -1,4 +1,4 @@
/* $NetBSD: lprm.c,v 1.9 1999/08/16 03:12:32 simonb Exp $ */
/* $NetBSD: lprm.c,v 1.10 1999/12/07 14:54:48 mrg Exp $ */
/*
* Copyright (c) 1983, 1993
@ -41,7 +41,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
#if 0
static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: lprm.c,v 1.9 1999/08/16 03:12:32 simonb Exp $");
__RCSID("$NetBSD: lprm.c,v 1.10 1999/12/07 14:54:48 mrg Exp $");
#endif
#endif /* not lint */
@ -58,6 +58,7 @@ __RCSID("$NetBSD: lprm.c,v 1.9 1999/08/16 03:12:32 simonb Exp $");
#include <sys/param.h>
#include <err.h>
#include <syslog.h>
#include <dirent.h>
#include <pwd.h>
@ -118,6 +119,19 @@ main(argc, argv)
printer = *++argv;
}
break;
case 'w':
if (arg[2])
wait_time = atoi(&arg[2]);
else if (argc > 1) {
argc--;
wait_time = atoi(*++argv);
}
if (wait_time < 0)
errx(1, "wait time must be postive: %s",
optarg);
if (wait_time < 30)
warnx("warning: wait time less than 30 seconds");
break;
case '\0':
if (!users) {
users = -1;