Mega lpd/lpd upgrade, part I:

- Get rid of a lot of the static variables which were shared by
  many routines and programs in the suite.
- Create an abstract interface to the printcap database, so that
  other retrieval and iteration mechanisms could be developed
  (e.g., YP, Hesiod, or automatic retrieval from a trusted server).
- Give each capability a human-readable name in addition to the historic
  two-character one.
- Otherwise generally clean up a lot of dark corners.  Many still remain.
- When submitting jobs, use the official login name record (from getlogin())
  if there is one, rather than reverse-mapping the uid.

More to come...
This commit is contained in:
Garrett Wollman 1997-12-02 20:46:22 +00:00
parent a846453c5e
commit 4a1a0dbedb
43 changed files with 2907 additions and 1932 deletions

View file

@ -1,6 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
SUBDIR= lp lpc lpd lpq lpr lprm lptest pac filters
SUBDIR= common_source chkprintcap lp lpc lpd lpq lpr lprm lptest pac \
filters SMM.doc
.include <bsd.subdir.mk>

View file

@ -0,0 +1,3 @@
# $Id$
CWARNFLAGS= -Werror -Wall -Wnested-externs -Wmissing-prototypes

View file

@ -1,10 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/8/93
# From: @(#)Makefile 8.1 (Berkeley) 6/8/93
# $Id: Makefile,v 1.3 1997/02/22 13:05:43 peter Exp $
DIR= smm/07.lpd
VOLUME= smm/07.lpd
SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t 7.t
MACROS= -ms
paper.ps: ${SRCS}
${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
USE_TBL= yes
SRCDIR= ${.CURDIR}
.include <bsd.doc.mk>

View file

@ -0,0 +1,10 @@
# $Id$
PROG= chkprintcap
MAN8= chkprintcap.8
CFLAGS+=-I${.CURDIR}/../common_source -Wall -Werror
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -0,0 +1,96 @@
.\" Copyright 1997 Massachusetts Institute of Technology
.\"
.\" Permission to use, copy, modify, and distribute this software and
.\" its documentation for any purpose and without fee is hereby
.\" granted, provided that both the above copyright notice and this
.\" permission notice appear in all copies, that both the above
.\" copyright notice and this permission notice appear in all
.\" supporting documentation, and that the name of M.I.T. not be used
.\" in advertising or publicity pertaining to distribution of the
.\" software without specific, written prior permission. M.I.T. makes
.\" no representations about the suitability of this software for any
.\" purpose. It is provided "as is" without express or implied
.\" warranty.
.\"
.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id$
.Dd November 30, 1997
.Dt CHKPRINTCAP 8
.Os
.Sh NAME
.Nm chkprintcap
.Nd check validity of entries in the print spooler database
.Sh SYNOPSIS
.Nm chkprintcap
.Op Fl d
.Op Fl f Ar printcap
.Sh DESCRIPTION
.Nm Chkprintcap
scans a
.Xr printcap 5
database
(named by the
.Ar printcap
argument, or by default
.Pa /etc/printcap ) ,
looking for entries which are invalid in one way or another.
The following checks are currently implemented:
.Bl -enum -offset indent
.It
.Sq Li tc=
references were properly expanded
.It
.Sq Li tc=
references did not form a loop
.It
No two printers share the same spool directory
.Po
.Sq Li sd=
capability
.Pc .
.El
.Pp
.Nm Chkprintcap
exits with a status equal to the number of errors encountered before
processing stopped. (In some cases, processing can stop before the
entire file is scanned.)
.Pp
If the
.Fl d
flag is given,
.Nm chkprintcap
will attempt to create any missing spool directories, giving them
.Sq Li u=rwx,go=rx
(0755) mode, group
.Sq Li daemon ,
and the owner specified by the
.Sq Li du=
capability in the database (default 1, which corresponds to user
.Sq Li daemon ) .
.Sh SEE ALSO
.Xr lpr 1 ,
.Xr printcap 5 ,
.Xr lpd 8
.Sh AUTHOR
The
.Nm chkprintcap
command was written by
.An Garrett A. Wollman Aq wollman@lcs.mit.edu .
.Sh BUGS
Not enough sanity-checking is done. At a minimum, the ownership and
mode of the spool directories should also be checked. Other
parameters whose value could cause
.Xr lpd 8
to fail should be diagnosed.

View file

@ -0,0 +1,277 @@
/*
* Copyright 1997 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static const char copyright[] =
"Copyright (C) 1997, Massachusetts Institute of Technology\r\n";
static const char rcsid[] =
"$Id$";
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h> /* needed for lp.h but not used here */
#include <dirent.h> /* ditto */
#include "lp.h"
#include "lp.local.h"
static void check_spool_dirs(void);
static int interpret_error(const struct printer *pp, int error);
static void make_spool_dir(const struct printer *pp);
static void note_spool_dir(const struct printer *pp, const struct stat *st);
static void usage(void) __dead2;
static int problems; /* number of problems encountered */
/*
* chkprintcap - check the printcap file for syntactic and semantic errors
* Returns the number of problems found.
*/
int
main(int argc, char **argv)
{
int c, error, makedirs, more;
struct printer myprinter, *pp;
makedirs = 0;
pp = &myprinter;
while ((c = getopt(argc, argv, "df:")) != -1) {
switch (c) {
case 'd':
makedirs = 1;
break;
case 'f':
setprintcap(optarg);
break;
default:
usage();
}
}
if (optind != argc)
usage();
more = firstprinter(pp, &error);
if (interpret_error(pp, error) && more)
goto next;
while (more) {
struct stat stab;
errno = 0;
if (stat(pp->spool_dir, &stab) < 0) {
if (errno == ENOENT && makedirs) {
make_spool_dir(pp);
} else {
problems++;
warn("%s: %s", pp->printer, pp->spool_dir);
}
} else {
note_spool_dir(pp, &stab);
}
/* Make other validity checks here... */
next:
more = nextprinter(pp, &error);
if (interpret_error(pp, error) && more)
goto next;
}
check_spool_dirs();
return problems;
}
/*
* Interpret the error code. Returns 1 if we should skip to the next
* record (as this record is unlikely to make sense). If the problem
* is very severe, exit. Otherwise, return zero.
*/
static int
interpret_error(const struct printer *pp, int error)
{
switch(error) {
case PCAPERR_OSERR:
err(++problems, "reading printer database");
case PCAPERR_TCLOOP:
++problems;
warnx("%s: loop detected in tc= expansion", pp->printer);
return 1;
case PCAPERR_TCOPEN:
warnx("%s: unresolved tc= expansion", pp->printer);
return 1;
case PCAPERR_SUCCESS:
break;
default:
errx(++problems, "unknown printcap library error %d", error);
}
return 0;
}
/*
* Keep the list of spool directories. Note that we don't whine
* until all spool directories are noted, so that all of the more serious
* problems are noted first. We keep the list sorted by st_dev and
* st_ino, so that the problem spool directories can be noted in
* a single loop.
*/
struct dirlist {
LIST_ENTRY(dirlist) link;
struct stat stab;
char *path;
char *printer;
};
static LIST_HEAD(, dirlist) dirlist;
static int
lessp(const struct dirlist *a, const struct dirlist *b)
{
if (a->stab.st_dev == b->stab.st_dev)
return a->stab.st_ino < b->stab.st_ino;
return a->stab.st_dev < b->stab.st_dev;
}
static int
equal(const struct dirlist *a, const struct dirlist *b)
{
return ((a->stab.st_dev == b->stab.st_dev)
&& (a->stab.st_ino == b->stab.st_ino));
}
static void
note_spool_dir(const struct printer *pp, const struct stat *st)
{
struct dirlist *dp, *dp2, *last;
dp = malloc(sizeof *dp);
if (dp == 0)
err(++problems, "malloc(%lu)", (u_long)sizeof *dp);
dp->stab = *st;
dp->printer = strdup(pp->printer);
if (dp->printer == 0)
err(++problems, "malloc(%lu)", strlen(pp->printer) + 1UL);
dp->path = strdup(pp->spool_dir);
if (dp->path == 0)
err(++problems, "malloc(%lu)", strlen(pp->spool_dir) + 1UL);
last = 0;
dp2 = dirlist.lh_first;
while (dp2 && lessp(dp, dp2)) {
last = dp2;
dp2 = dp2->link.le_next;
}
if (last) {
LIST_INSERT_AFTER(last, dp, link);
} else {
LIST_INSERT_HEAD(&dirlist, dp, link);
}
}
static void
check_spool_dirs(void)
{
struct dirlist *dp, *dp2;
for (dp = dirlist.lh_first; dp; dp = dp2) {
dp2 = dp->link.le_next;
if (dp2 != 0 && equal(dp, dp2)) {
++problems;
if (strcmp(dp->path, dp2->path) == 0) {
warnx("%s and %s share the same spool, %s",
dp->printer, dp2->printer, dp->path);
} else {
warnx("%s (%s) and %s (%s) are the same "
"directory", dp->path, dp->printer,
dp2->path, dp2->printer);
}
continue;
}
/* Should probably check owners and modes here. */
}
}
#ifndef SPOOL_DIR_MODE
#define SPOOL_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR \
| S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
#endif
static void
make_spool_dir(const struct printer *pp)
{
char *sd = pp->spool_dir;
struct group *gr;
struct stat stab;
if (mkdir(sd, S_IRUSR | S_IXUSR) < 0) {
problems++;
warn("%s: mkdir %s", pp->printer, sd);
return;
}
gr = getgrnam("daemon");
if (gr == 0)
errx(++problems, "cannot locate daemon group");
if (chown(sd, pp->daemon_user, gr->gr_gid) < 0) {
++problems;
warn("%s: cannot change ownership to %ld:%ld", sd,
(long)pp->daemon_user, (long)gr->gr_gid);
return;
}
if (chmod(sd, SPOOL_DIR_MODE) < 0) {
++problems;
warn("%s: cannot change mode to %lo", (long)SPOOL_DIR_MODE);
return;
}
if (stat(sd, &stab) < 0)
err(++problems, "stat: %s", sd);
note_spool_dir(pp, &stab);
}
static void
usage(void)
{
fprintf(stderr, "usage:\n\tchkprintcap [-d] [-f printcapfile]\n");
exit(1);
}

View file

@ -0,0 +1,19 @@
# $Id$
#
# Library of internal routines for the print spooler suite.
# Originally these were compiled separately into each program,
# but the library makes it much easier to modularize them.
#
LIB= lpr
SRCS= common.c displayq.c net.c printcap.c request.c rmjob.c \
startdaemon.c
NOMAN= noman
NOPROFILE= noprofile
NOPIC= nopic
CFLAGS+= -Werror -Wall -Wnested-externs -Wmissing-prototypes \
-Wstrict-prototypes -Wredundant-decls
install:
.include <bsd.lib.mk>

View file

@ -37,150 +37,37 @@
*/
#ifndef lint
/*
static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
/*
* Routines and data common to all the line printer functions.
*/
char *AF; /* accounting file */
long BR; /* baud rate if lp is a tty */
char *CF; /* name of cifplot filter (per job) */
long CT; /* TCP connection timeout */
char *DF; /* name of tex filter (per job) */
long DU; /* daeomon user-id */
char *FF; /* form feed string */
char *GF; /* name of graph(1G) filter (per job) */
long HL; /* print header last */
char *IF; /* name of input filter (created per job) */
char *LF; /* log file for error messages */
char *LO; /* lock file name */
char *LP; /* line printer device name */
long MC; /* maximum number of copies allowed */
long MX; /* maximum number of blocks to copy */
char *NF; /* name of ditroff filter (per job) */
char *OF; /* name of output filter (created once) */
char *PF; /* name of vrast filter (per job) */
long PL; /* page length */
long PW; /* page width */
long PX; /* page width in pixels */
long PY; /* page length in pixels */
char *RF; /* name of fortran text filter (per job) */
char *RG; /* resricted group */
char *RM; /* remote machine name */
char *RP; /* remote printer name */
long RS; /* restricted to those with local accounts */
long RW; /* open LP for reading and writing */
long SB; /* short banner instead of normal header */
long SC; /* suppress multiple copies */
char *SD; /* spool directory */
long SF; /* suppress FF on each print job */
long SH; /* suppress header page */
char *ST; /* status file name */
char *TF; /* name of troff filter (per job) */
char *TR; /* trailer string to be output when Q empties */
char *MS; /* mode set, a la stty */
char *VF; /* name of vplot filter (per job) */
char line[BUFSIZ];
char *bp; /* pointer into printcap buffer. */
char *name; /* program name */
char *printer; /* printer name */
/* host machine name */
char host[MAXHOSTNAMELEN];
char *from = host; /* client's machine name */
int remote; /* true if sending files to a remote host */
char *printcapdb[2] = { _PATH_PRINTCAP, 0 };
extern uid_t uid, euid;
static int compar __P((const void *, const void *));
/*
* Create a TCP connection to host "rhost" at port "rport".
* If rport == 0, then use the printer service port.
* Most of this code comes from rcmd.c.
*/
int
getport(rhost, rport)
char *rhost;
int rport;
{
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;
int s, timo = 1, lport = IPPORT_RESERVED - 1;
int err;
/*
* Get the host address and port number to connect to.
*/
if (rhost == NULL)
fatal("no remote host to connect to");
bzero((char *)&sin, sizeof(sin));
sin.sin_addr.s_addr = inet_addr(rhost);
if (sin.sin_addr.s_addr != INADDR_NONE)
sin.sin_family = AF_INET;
else {
hp = gethostbyname(rhost);
if (hp == NULL)
fatal("unknown host %s", rhost);
bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
sin.sin_family = hp->h_addrtype;
}
if (rport == 0) {
sp = getservbyname("printer", "tcp");
if (sp == NULL)
fatal("printer/tcp: unknown service");
sin.sin_port = sp->s_port;
} else
sin.sin_port = htons(rport);
/*
* Try connecting to the server.
*/
retry:
seteuid(euid);
s = rresvport(&lport);
seteuid(uid);
if (s < 0)
return(-1);
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
err = errno;
(void) close(s);
errno = err;
if (errno == EADDRINUSE) {
lport--;
goto retry;
}
if (errno == ECONNREFUSED && timo <= 16) {
sleep(timo);
timo *= 2;
goto retry;
}
return(-1);
}
return(s);
}
/*
* Getline reads a line from the control file cfp, removes tabs, converts
* new-line to null and leaves it in line.
@ -217,7 +104,8 @@ getline(cfp)
* Return the number of entries and a pointer to the list.
*/
int
getq(namelist)
getq(pp, namelist)
const struct printer *pp;
struct queue *(*namelist[]);
{
register struct dirent *d;
@ -228,7 +116,7 @@ getq(namelist)
int arraysz;
seteuid(euid);
if ((dirp = opendir(SD)) == NULL)
if ((dirp = opendir(pp->spool_dir)) == NULL)
return(-1);
if (fstat(dirp->dd_fd, &stbuf) < 0)
goto errdone;
@ -294,65 +182,65 @@ compar(p1, p2)
return(0);
}
/*
* Figure out whether the local machine is the same
* as the remote machine (RM) entry (if it exists).
*/
char *
checkremote()
{
char name[MAXHOSTNAMELEN];
register struct hostent *hp;
static char errbuf[128];
remote = 0; /* assume printer is local */
if (RM != NULL) {
/* get the official name of the local host */
gethostname(name, sizeof(name));
name[sizeof(name) - 1] = '\0';
hp = gethostbyname(name);
if (hp == (struct hostent *) NULL) {
(void) snprintf(errbuf, sizeof(errbuf),
"unable to get official name for local machine %s",
name);
return errbuf;
} else {
(void) strncpy(name, hp->h_name, sizeof(name));
name[sizeof(name) - 1] = '\0';
}
/* get the official name of RM */
hp = gethostbyname(RM);
if (hp == (struct hostent *) NULL) {
(void) snprintf(errbuf, sizeof(errbuf),
"unable to get official name for remote machine %s",
RM);
return errbuf;
}
/*
* if the two hosts are not the same,
* then the printer must be remote.
*/
if (strcasecmp(name, hp->h_name) != 0)
remote = 1;
}
return NULL;
}
/* sleep n milliseconds */
void
delay(n)
int n;
{
struct timeval tdelay;
if (n <= 0 || n > 10000)
fatal("unreasonable delay period (%d)", n);
fatal((struct printer *)0, /* fatal() knows how to deal */
"unreasonable delay period (%d)", n);
tdelay.tv_sec = n / 1000;
tdelay.tv_usec = n * 1000 % 1000000;
(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tdelay);
}
char *
lock_file_name(pp, buf, len)
const struct printer *pp;
char *buf;
size_t len;
{
static char staticbuf[MAXPATHLEN];
if (buf == 0)
buf = staticbuf;
if (len == 0)
len = MAXPATHLEN;
if (pp->lock_file[0] == '/') {
buf[0] = '\0';
strncpy(buf, pp->lock_file, len);
} else {
snprintf(buf, len, "%s/%s", pp->spool_dir, pp->lock_file);
}
return buf;
}
char *
status_file_name(pp, buf, len)
const struct printer *pp;
char *buf;
size_t len;
{
static char staticbuf[MAXPATHLEN];
if (buf == 0)
buf = staticbuf;
if (len == 0)
len = MAXPATHLEN;
if (pp->status_file[0] == '/') {
buf[0] = '\0';
strncpy(buf, pp->status_file, len);
} else {
snprintf(buf, len, "%s/%s", pp->spool_dir, pp->status_file);
}
return buf;
}
#ifdef __STDC__
#include <stdarg.h>
#else
@ -361,9 +249,10 @@ delay(n)
void
#ifdef __STDC__
fatal(const char *msg, ...)
fatal(const struct printer *pp, const char *msg, ...)
#else
fatal(msg, va_alist)
fatal(pp, msg, va_alist)
const struct printer *pp;
char *msg;
va_dcl
#endif
@ -377,10 +266,27 @@ fatal(msg, va_alist)
if (from != host)
(void)printf("%s: ", host);
(void)printf("%s: ", name);
if (printer)
(void)printf("%s: ", printer);
if (pp && pp->printer)
(void)printf("%s: ", pp->printer);
(void)vprintf(msg, ap);
va_end(ap);
(void)putchar('\n');
exit(1);
}
/*
* Close all file descriptors from START on up.
* This is a horrific kluge, since getdtablesize() might return
* ``infinity'', in which case we will be spending a long time
* closing ``files'' which were never open. Perhaps it would
* be better to close the first N fds, for some small value of N.
*/
void
closeallfds(start)
int start;
{
int stop = getdtablesize();
for (; start < stop; start++)
close(start);
}

View file

@ -32,21 +32,30 @@
*/
#ifndef lint
/*
static char sccsid[] = "@(#)displayq.c 8.4 (Berkeley) 4/28/95";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define psignal foil_gcc_psignal
#define sys_siglist foil_gcc_siglist
#include <unistd.h>
#undef psignal
#undef sys_siglist
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
@ -76,13 +85,14 @@ static char *head0 = "Rank Owner Job Files";
static char *head1 = "Total Size\n";
static void alarmhandler __P((int));
static void warn __P((void));
static void warn __P((const struct printer *pp));
/*
* Display the current state of the queue. Format = 1 if long format.
*/
void
displayq(format)
displayq(pp, format)
struct printer *pp;
int format;
{
register struct queue *q;
@ -96,71 +106,55 @@ displayq(format)
lflag = format;
totsize = 0;
rank = -1;
if ((i = cgetent(&bp, printcapdb, printer)) == -2)
fatal("can't open printer description file");
else if (i == -1)
fatal("unknown printer");
else if (i == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "lp", &LP) < 0)
LP = _PATH_DEFDEVLP;
if (cgetstr(bp, "rp", &RP) < 0)
RP = DEFLP;
if (cgetstr(bp, "sd", &SD) < 0)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp,"lo", &LO) < 0)
LO = DEFLOCK;
if (cgetstr(bp, "st", &ST) < 0)
ST = DEFSTAT;
if (cgetnum(bp, "ct", &CT) < 0)
CT = DEFTIMEOUT;
if (cgetstr(bp, "rm", &RM) < 0)
RM = NULL;
if ((cp = checkremote()))
if ((cp = checkremote(pp))) {
printf("Warning: %s\n", cp);
free(cp);
}
/*
* Print out local queue
* Find all the control files in the spooling directory
*/
seteuid(euid);
if (chdir(SD) < 0)
fatal("cannot chdir to spooling directory");
if (chdir(pp->spool_dir) < 0)
fatal(pp, "cannot chdir to spooling directory: %s",
strerror(errno));
seteuid(uid);
if ((nitems = getq(&queue)) < 0)
fatal("cannot examine spooling area\n");
if ((nitems = getq(pp, &queue)) < 0)
fatal(pp, "cannot examine spooling area\n");
seteuid(euid);
ret = stat(LO, &statb);
ret = stat(pp->lock_file, &statb);
seteuid(uid);
if (ret >= 0) {
if (statb.st_mode & 0100) {
if (remote)
if (statb.st_mode & LFM_PRINT_DIS) {
if (pp->remote)
printf("%s: ", host);
printf("Warning: %s is down: ", printer);
printf("Warning: %s is down: ", pp->printer);
seteuid(euid);
fd = open(ST, O_RDONLY);
fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
seteuid(uid);
if (fd >= 0) {
(void) flock(fd, LOCK_SH);
while ((i = read(fd, line, sizeof(line))) > 0)
(void) fwrite(line, 1, i, stdout);
(void) close(fd); /* unlocks as well */
} else
putchar('\n');
}
if (statb.st_mode & 010) {
if (remote)
if (statb.st_mode & LFM_QUEUE_DIS) {
if (pp->remote)
printf("%s: ", host);
printf("Warning: %s queue is turned off\n", printer);
printf("Warning: %s queue is turned off\n",
pp->printer);
}
}
if (nitems) {
seteuid(euid);
fp = fopen(LO, "r");
fp = fopen(pp->lock_file, "r");
seteuid(uid);
if (fp == NULL)
warn();
warn(pp);
else {
/* get daemon pid */
cp = current;
@ -176,7 +170,7 @@ displayq(format)
seteuid(uid);
}
if (ret < 0) {
warn();
warn(pp);
} else {
/* read current file name */
cp = current;
@ -186,16 +180,16 @@ displayq(format)
/*
* Print the status file.
*/
if (remote)
if (pp->remote)
printf("%s: ", host);
seteuid(euid);
fd = open(ST, O_RDONLY);
fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
seteuid(uid);
if (fd >= 0) {
(void) flock(fd, LOCK_SH);
while ((i = read(fd, line, sizeof(line))) > 0)
(void) fwrite(line, 1, i, stdout);
(void) close(fd); /* unlocks as well */
while ((i = read(fd, line,
sizeof(line))) > 0)
fwrite(line, 1, i, stdout);
close(fd); /* unlocks as well */
} else
putchar('\n');
}
@ -209,12 +203,12 @@ displayq(format)
header();
for (i = 0; i < nitems; i++) {
q = queue[i];
inform(q->q_name);
inform(pp, q->q_name);
free(q);
}
free(queue);
}
if (!remote) {
if (!pp->remote) {
if (nitems == 0)
puts("no entries");
return;
@ -226,7 +220,8 @@ displayq(format)
*/
if (nitems)
putchar('\n');
(void) snprintf(line, sizeof(line), "%c%s", format + '\3', RP);
(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
pp->remote_queue);
cp = line;
for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
cp += strlen(cp);
@ -240,19 +235,19 @@ displayq(format)
}
strcat(line, "\n");
savealrm = signal(SIGALRM, alarmhandler);
alarm(CT);
fd = getport(RM, 0);
alarm(pp->conn_timeout);
fd = getport(pp, pp->remote_host, 0);
alarm(0);
(void)signal(SIGALRM, savealrm);
if (fd < 0) {
if (from != host)
printf("%s: ", host);
printf("connection to %s is down\n", RM);
printf("connection to %s is down\n", pp->remote_host);
}
else {
i = strlen(line);
if (write(fd, line, i) != i)
fatal("Lost connection");
fatal(pp, "Lost connection");
while ((i = read(fd, line, sizeof(line))) > 0)
(void) fwrite(line, 1, i, stdout);
(void) close(fd);
@ -263,9 +258,10 @@ displayq(format)
* Print a warning message if there is no daemon present.
*/
static void
warn()
warn(pp)
const struct printer *pp;
{
if (remote)
if (pp->remote)
printf("%s: ", host);
puts("Warning: no daemon present");
current[0] = '\0';
@ -284,7 +280,8 @@ header()
}
void
inform(cf)
inform(pp, cf)
const struct printer *pp;
char *cf;
{
register int j;
@ -301,7 +298,7 @@ inform(cf)
if (rank < 0)
rank = 0;
if (remote || garbage || strcmp(cf, current))
if (pp->remote || garbage || strcmp(cf, current))
rank++;
j = 0;
while (getline(cfp)) {

View file

@ -30,69 +30,123 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)lp.h 8.2 (Berkeley) 4/28/95
* From: @(#)lp.h 8.2 (Berkeley) 4/28/95
* $Id$
*/
#include <sys/queue.h>
/*
* All this information used to be in global static variables shared
* mysteriously by various parts of the lpr/lpd suite.
* This structure attempts to centralize all these declarations in the
* hope that they can later be made more dynamic.
*/
enum lpd_filters { LPF_CIFPLOT, LPF_DVI, LPF_GRAPH, LPF_INPUT,
LPF_DITROFF, LPF_OUTPUT, LPF_FORTRAN, LPF_TROFF,
LPF_RASTER, LPF_COUNT };
/* NB: there is a table in common.c giving the mapping from capability names */
struct printer {
char *printer; /* printer name */
int remote; /* true if RM points to a remote host */
int tof; /* true if we are at top-of-form */
/* ------------------------------------------------------ */
char *acct_file; /* AF: accounting file */
long baud_rate; /* BR: baud rate if lp is a tty */
char *filters[LPF_COUNT]; /* CF, DF, GF, IF, NF, OF, RF, TF, VF */
long conn_timeout; /* CT: TCP connection timeout */
long daemon_user; /* DU: daemon user id -- XXX belongs ???? */
char *form_feed; /* FF: form feed */
long header_last; /* HL: print header last */
char *log_file; /* LF: log file */
char *lock_file; /* LO: lock file */
char *lp; /* LP: device name or network address */
long max_copies; /* MC: maximum number of copies allowed */
long max_blocks; /* MX: maximum number of blocks to copy */
long price100; /* PC: price per 100 units of output */
long page_length; /* PL: page length */
long page_width; /* PW: page width */
long page_pwidth; /* PX: page width in pixels */
long page_plength; /* PY: page length in pixels */
char *restrict_grp; /* RG: restricted group */
char *remote_host; /* RM: remote machine name */
char *remote_queue; /* RP: remote printer name */
long restricted; /* RS: restricted to those with local accts */
long rw; /* RW: open LP for reading and writing */
long short_banner; /* SB: short banner */
long no_copies; /* SC: suppress multiple copies */
char *spool_dir; /* SD: spool directory */
long no_formfeed; /* SF: suppress FF on each print job */
long no_header; /* SH: suppress header page */
char *status_file; /* ST: status file name */
char *trailer; /* TR: trailer string send when Q empties */
char *mode_set; /* MS: mode set, a la stty */
};
/*
* Lists of user names and job numbers, for the benefit of the structs
* defined below. We use TAILQs so that requests don't get mysteriously
* reversed in process.
*/
struct req_user {
TAILQ_ENTRY(req_user) ru_link; /* macro glue */
char ru_uname[1]; /* name of user */
};
TAILQ_HEAD(req_user_head, req_user);
struct req_file {
TAILQ_ENTRY(req_file) rf_link; /* macro glue */
char rf_type; /* type (lowercase cf file letter) of file */
char *rf_prettyname; /* user-visible name of file */
char rf_fname[1]; /* name of file */
};
TAILQ_HEAD(req_file_head, req_file);
struct req_jobid {
TAILQ_ENTRY(req_jobid) rj_link; /* macro glue */
int rj_job; /* job number */
};
TAILQ_HEAD(req_jobid_head, req_jobid);
/*
* Encapsulate all the information relevant to a request in the
* lpr/lpd protocol.
*/
enum req_type { REQ_START, REQ_RECVJOB, REQ_LIST, REQ_DELETE };
struct request {
enum req_type type; /* what sort of request is this? */
struct printer prtr; /* which printer is it for? */
int remote; /* did request arrive over network? */
char *logname; /* login name of requesting user */
char *authname; /* authenticated identity of requesting user */
char *prettyname; /* ``pretty'' name of requesting user */
int privileged; /* was the request from a privileged user? */
void *authinfo; /* authentication information */
int authentic; /* was the request securely authenticated? */
/* Information for queries and deletes... */
int nusers; /* length of following list... */
struct req_user_head users; /* list of users to query/delete */
int njobids; /* length of following list... */
struct req_jobid_head jobids; /* list of jobids to query/delete */
};
/*
* Global definitions for the line printer system.
*/
extern char *AF; /* accounting file */
extern long BR; /* baud rate if lp is a tty */
extern char *CF; /* name of cifplot filter (per job) */
extern long CT; /* TCP connection timeout */
extern char *DF; /* name of tex filter (per job) */
extern long DU; /* daeomon user-id */
extern char *FF; /* form feed string */
extern char *GF; /* name of graph(1G) filter (per job) */
extern long HL; /* print header last */
extern char *IF; /* name of input filter (created per job) */
extern char *LF; /* log file for error messages */
extern char *LO; /* lock file name */
extern char *LP; /* line printer device name */
extern long MC; /* maximum number of copies allowed */
extern long MX; /* maximum number of blocks to copy */
extern char *NF; /* name of ditroff(1) filter (per job) */
extern char *OF; /* name of output filter (created once) */
extern long PL; /* page length */
extern long PW; /* page width */
extern long PX; /* page width in pixels */
extern long PY; /* page length in pixels */
extern char *RF; /* name of fortran text filter (per job) */
extern char *RG; /* restricted group */
extern char *RM; /* remote machine name */
extern char *RP; /* remote printer name */
extern long RS; /* restricted to those with local accounts */
extern long RW; /* open LP for reading and writing */
extern long SB; /* short banner instead of normal header */
extern long SC; /* suppress multiple copies */
extern char *SD; /* spool directory */
extern long SF; /* suppress FF on each print job */
extern long SH; /* suppress header page */
extern char *ST; /* status file name */
extern char *TF; /* name of troff(1) filter (per job) */
extern char *TR; /* trailer string to be output when Q empties */
extern char *MS; /* mode set, a la stty */
extern char *VF; /* name of raster filter (per job) */
extern char line[BUFSIZ];
extern char *bp; /* pointer into printcap buffer */
extern char *name; /* program name */
extern char *printer; /* printer name */
/* host machine name */
extern char host[MAXHOSTNAMELEN];
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 requ[]; /* job number of spool entries */
extern int requests; /* # of spool requests */
extern char *user[]; /* users to process */
extern int users; /* # of users in user array */
extern char *person; /* name of person doing lprm */
extern char *name;
/*
* Structure used for building a sorted list of control files.
@ -102,32 +156,78 @@ struct queue {
char q_name[MAXNAMLEN+1]; /* control file name */
};
/*
* Error codes for our mini printcap library.
*/
#define PCAPERR_TCLOOP (-3)
#define PCAPERR_OSERR (-2)
#define PCAPERR_NOTFOUND (-1)
#define PCAPERR_SUCCESS 0
#define PCAPERR_TCOPEN 1
/*
* File modes for the various status files maintained by lpd.
*/
#define LOCK_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define LFM_PRINT_DIS (S_IXUSR)
#define LFM_QUEUE_DIS (S_IXGRP)
#define LFM_RESET_QUE (S_IXOTH)
#define STAT_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define LOG_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define TEMP_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
/*
* Command codes used in the protocol.
*/
#define CMD_CHECK_QUE '\1'
#define CMD_TAKE_THIS '\2'
#define CMD_SHOWQ_SHORT '\3'
#define CMD_SHOWQ_LONG '\4'
#define CMD_RMJOB '\5'
#include <sys/cdefs.h>
__BEGIN_DECLS
struct dirent;
struct dirent;
void blankfill __P((int));
char *checkremote __P((void));
char *checkremote __P((struct printer *pp));
int chk __P((char *));
void displayq __P((int));
void closeallfds __P((int start));
void delay __P((int));
void displayq __P((struct printer *pp, int format));
void dump __P((char *, char *, int));
void fatal __P((const char *, ...));
void fatal __P((const struct printer *pp, const char *fmp, ...));
int firstprinter __P((struct printer *pp, int *status));
void free_printer __P((struct printer *pp));
void free_request __P((struct request *rp));
int getline __P((FILE *));
int getport __P((char *, int));
int getq __P((struct queue *(*[])));
int getport __P((const struct printer *pp, const char *, int));
int getprintcap __P((const char *printer, struct printer *pp));
int getq __P((const struct printer *, struct queue *(*[])));
void header __P((void));
void inform __P((char *));
void inform __P((const struct printer *pp, char *cf));
void init_printer __P((struct printer *pp));
void init_request __P((struct request *rp));
int inlist __P((char *, char *));
int iscf __P((struct dirent *));
int isowner __P((char *, char *));
void ldump __P((char *, char *, int));
int lockchk __P((char *));
void lastprinter __P((void));
int lockchk __P((struct printer *pp, char *));
char *lock_file_name __P((const struct printer *pp, char *buf, size_t len));
int nextprinter __P((struct printer *pp, int *status));
const
char *pcaperr __P((int error));
void prank __P((int));
void process __P((char *));
void rmjob __P((void));
void rmremote __P((void));
void process __P((const struct printer *pp, char *));
void rmjob __P((const char *printer));
void rmremote __P((const struct printer *pp));
void setprintcap __P((char *newprintcap));
void show __P((char *, char *, int));
int startdaemon __P((char *));
void delay __P((int));
int startdaemon __P((const struct printer *pp));
char *status_file_name __P((const struct printer *pp, char *buf,
size_t len));
ssize_t writel __P((int s, ...));
__END_DECLS

View file

@ -0,0 +1,260 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)common.c 8.5 (Berkeley) 4/28/95
*/
#ifndef lint
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h> /* required for lp.h, not used here */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
/* host machine name */
char host[MAXHOSTNAMELEN];
char *from = host; /* client's machine name */
extern uid_t uid, euid;
/*
* Create a TCP connection to host "rhost" at port "rport".
* If rport == 0, then use the printer service port.
* Most of this code comes from rcmd.c.
*/
int
getport(const struct printer *pp, const char *rhost, int rport)
{
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;
int s, timo = 1, lport = IPPORT_RESERVED - 1;
int err;
/*
* Get the host address and port number to connect to.
*/
if (rhost == NULL)
fatal(pp, "no remote host to connect to");
bzero((char *)&sin, sizeof(sin));
sin.sin_len = sizeof sin;
sin.sin_family = AF_INET;
if (inet_aton(rhost, &sin.sin_addr) == 0) {
hp = gethostbyname2(rhost, AF_INET);
if (hp == NULL)
fatal(pp, "cannot resolve %s: %s", rhost,
hstrerror(h_errno));
/* XXX - should deal with more addresses */
sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
}
if (rport == 0) {
sp = getservbyname("printer", "tcp");
if (sp == NULL)
fatal(pp, "printer/tcp: unknown service");
sin.sin_port = sp->s_port;
} else
sin.sin_port = htons(rport);
/*
* Try connecting to the server.
*/
retry:
seteuid(euid);
s = rresvport(&lport);
seteuid(uid);
if (s < 0)
return(-1);
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
err = errno;
(void) close(s);
errno = err;
/*
* This used to decrement lport, but the current semantics
* of rresvport do not provide such a function (in fact,
* rresvport should guarantee that the chosen port will
* never result in an EADDRINUSE).
*/
if (errno == EADDRINUSE)
goto retry;
if (errno == ECONNREFUSED && timo <= 16) {
sleep(timo);
timo *= 2;
goto retry;
}
return(-1);
}
return(s);
}
/*
* Figure out whether the local machine is the same
* as the remote machine (RM) entry (if it exists).
* We do this by counting the intersection of our
* address list and theirs. This is better than the
* old method (comparing the canonical names), as it
* allows load-sharing between multiple print servers.
* The return value is an error message which must be
* free()d.
*/
char *
checkremote(struct printer *pp)
{
char name[MAXHOSTNAMELEN];
register struct hostent *hp;
char *err;
struct in_addr *localaddrs;
int i, j, nlocaladdrs, ncommonaddrs;
pp->remote = 0; /* assume printer is local */
if (pp->remote_host != NULL) {
/* get the addresses of the local host */
gethostname(name, sizeof(name));
name[sizeof(name) - 1] = '\0';
hp = gethostbyname2(name, AF_INET);
if (hp == (struct hostent *) NULL) {
asprintf(&err, "unable to get official name "
"for local machine %s: %s",
name, hstrerror(h_errno));
return err;
}
for (i = 0; hp->h_addr_list[i]; i++)
;
nlocaladdrs = i;
localaddrs = malloc(i * sizeof(struct in_addr));
if (localaddrs == 0) {
asprintf(&err, "malloc %lu bytes failed",
(u_long)i * sizeof(struct in_addr));
return err;
}
for (i = 0; hp->h_addr_list[i]; i++)
localaddrs[i] = *(struct in_addr *)hp->h_addr_list[i];
/* get the official name of RM */
hp = gethostbyname2(pp->remote_host, AF_INET);
if (hp == (struct hostent *) NULL) {
asprintf(&err, "unable to get address list for "
"remote machine %s: %s",
pp->remote_host, hstrerror(h_errno));
free(localaddrs);
return err;
}
ncommonaddrs = 0;
for (i = 0; i < nlocaladdrs; i++) {
for (j = 0; hp->h_addr_list[j]; j++) {
char *them = hp->h_addr_list[j];
if (localaddrs[i].s_addr ==
(*(struct in_addr *)them).s_addr)
ncommonaddrs++;
}
}
/*
* if the two hosts do not share at least one IP address
* then the printer must be remote.
*/
if (ncommonaddrs == 0)
pp->remote = 1;
free(localaddrs);
}
return NULL;
}
/*
* This isn't really network-related, but it's used here to write
* multi-part strings onto sockets without using stdio. Return
* values are as for writev(2).
*/
ssize_t
writel(int s, ...)
{
va_list ap;
int i, n;
const char *cp;
#define NIOV 12
struct iovec iov[NIOV], *iovp = iov;
ssize_t retval;
/* first count them */
va_start(ap, s);
n = 0;
do {
cp = va_arg(ap, char *);
n++;
} while (cp);
va_end(ap);
n--; /* correct for count of trailing null */
if (n > NIOV) {
iovp = malloc(n * sizeof *iovp);
if (iovp == 0)
return -1;
}
/* now make up iovec and send */
va_start(ap, s);
for (i = 0; i < n; i++) {
iovp[i].iov_base = va_arg(ap, char *);
iovp[i].iov_len = strlen(iovp[i].iov_base);
}
va_end(ap);
retval = writev(s, iovp, n);
if (iovp != iov)
free(iovp);
return retval;
}

View file

@ -48,3 +48,4 @@
#define _PATH_VFONTI "/usr/libdata/vfont/I"
#define _PATH_VFONTR "/usr/libdata/vfont/R"
#define _PATH_VFONTS "/usr/libdata/vfont/S"
#define _PATH_CHKPRINTCAP "/usr/sbin/chkprintcap"

View file

@ -0,0 +1,428 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)common.c 8.5 (Berkeley) 4/28/95
*/
#ifndef lint
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h> /* required for lp.h, but not used here */
#include <sys/dirent.h> /* ditto */
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
/*
* Routines and data used in processing the printcap file.
*/
static char *printcapdb[2] = { _PATH_PRINTCAP, 0 }; /* list for cget* */
static char *capdb_canonical_name(const char *);
static int capdb_getaltlog(char *, const char *, const char *);
static int capdb_getaltnum(char *, const char *, const char *, long, long *);
static int capdb_getaltstr(char *, const char *, const char *, const char *,
char **);
static int getprintcap_int(char *bp, struct printer *pp);
/*
* Change the name of the printcap file. Used by chkprintcap(8),
* but could be used by other members of the suite with appropriate
* security measures.
*/
void
setprintcap(char *newfile)
{
printcapdb[0] = newfile;
}
/*
* Read the printcap database for printer `printer' into the
* struct printer pointed by `pp'. Return values are as for
* cgetent(3): -1 means we could not find what we wanted, -2
* means a system error occurred (and errno is set), -3 if a
* reference (`tc=') loop was detected, and 0 means success.
*
* Copied from lpr; should add additional capabilities as they
* are required by the other programs in the suite so that
* printcap-reading is consistent across the entire family.
*/
int
getprintcap(const char *printer, struct printer *pp)
{
int status;
char *XXX;
char *bp;
/*
* A bug in the declaration of cgetent(3) means that we have
* to hide the constness of its third argument.
*/
XXX = (char *)printer;
if ((status = cgetent(&bp, printcapdb, XXX)) < 0)
return status;
status = getprintcap_int(bp, pp);
free(bp);
return status;
}
/*
* Map the status values returned by cgetfirst/cgetnext into those
* used by cgetent, returning truth if there are more records to
* examine. This points out what is arguably a bug in the cget*
* interface (or at least a nasty wart).
*/
static int
firstnextmap(int *status)
{
switch (*status) {
case 0:
return 0;
case 1:
*status = 0;
return 1;
case 2:
*status = 1;
return 1;
case -1:
*status = -2;
return 0;
case -2:
*status = -3;
return 1;
default:
return 0;
}
}
/*
* Scan through the database of printers using cgetfirst/cgetnext.
* Return false of error or end-of-database; else true.
*/
int
firstprinter(struct printer *pp, int *error)
{
int status;
char *bp;
init_printer(pp);
status = cgetfirst(&bp, printcapdb);
if (firstnextmap(&status) == 0) {
if (error)
*error = status;
return 0;
}
if (error)
*error = status;
status = getprintcap_int(bp, pp);
free(bp);
if (error && status)
*error = status;
return 1;
}
int
nextprinter(struct printer *pp, int *error)
{
int status;
char *bp;
free_printer(pp);
status = cgetnext(&bp, printcapdb);
if (firstnextmap(&status) == 0) {
if (error)
*error = status;
return 0;
}
if (error)
*error = status;
status = getprintcap_int(bp, pp);
free(bp);
if (error && status)
*error = status;
return 1;
}
void
lastprinter(void)
{
cgetclose();
}
/*
* This must match the order of declaration of enum filter in lp.h.
*/
static const char *filters[] = {
"cf", "df", "gf", "if", "nf", "of", "rf", "tf", "vf"
};
static const char *longfilters[] = {
"filt.cifplot", "filt.dvi", "filt.plot", "filt.input", "filt.ditroff",
"filt.output", "filt.fortran", "filt.troff", "filt.raster"
};
/*
* Internal routine for both getprintcap() and nextprinter().
* Actually parse the printcap entry using cget* functions.
* Also attempt to figure out the canonical name of the printer
* and store a malloced copy of it in pp->printer.
*/
static int
getprintcap_int(bp, pp)
char *bp;
struct printer *pp;
{
enum lpd_filters filt;
if ((pp->printer = capdb_canonical_name(bp)) == 0)
return PCAPERR_OSERR;
#define CHK(x) do {if ((x) == PCAPERR_OSERR) return PCAPERR_OSERR;}while(0)
CHK(capdb_getaltstr(bp, "af", "acct.file", 0, &pp->acct_file));
CHK(capdb_getaltnum(bp, "br", "tty.rate", 0, &pp->baud_rate));
CHK(capdb_getaltnum(bp, "ct", "remote.timeout", DEFTIMEOUT,
&pp->conn_timeout));
CHK(capdb_getaltnum(bp, "du", "daemon.user", DEFUID,
&pp->daemon_user));
CHK(capdb_getaltstr(bp, "ff", "job.formfeed", DEFFF, &pp->form_feed));
CHK(capdb_getaltstr(bp, "lf", "spool.log", _PATH_CONSOLE,
&pp->log_file));
CHK(capdb_getaltstr(bp, "lo", "spool.lock", DEFLOCK, &pp->lock_file));
CHK(capdb_getaltstr(bp, "lp", "tty.device", _PATH_DEFDEVLP, &pp->lp));
CHK(capdb_getaltnum(bp, "mc", "max.copies", DEFMAXCOPIES,
&pp->max_copies));
CHK(capdb_getaltstr(bp, "ms", "tty.mode", 0, &pp->mode_set));
CHK(capdb_getaltnum(bp, "mx", "max.blocks", DEFMX, &pp->max_blocks));
CHK(capdb_getaltnum(bp, "pc", "acct.price", 0, &pp->price100));
CHK(capdb_getaltnum(bp, "pl", "page.length", DEFLENGTH,
&pp->page_length));
CHK(capdb_getaltnum(bp, "pw", "page.width", DEFWIDTH,
&pp->page_width));
CHK(capdb_getaltnum(bp, "px", "page.pwidth", 0, &pp->page_pwidth));
CHK(capdb_getaltnum(bp, "py", "page.plength", 0, &pp->page_plength));
CHK(capdb_getaltstr(bp, "rg", "daemon.restrictgrp", 0,
&pp->restrict_grp));
CHK(capdb_getaltstr(bp, "rm", "remote.host", 0, &pp->remote_host));
CHK(capdb_getaltstr(bp, "rp", "remote.queue", DEFLP,
&pp->remote_queue));
CHK(capdb_getaltstr(bp, "sd", "spool.dir", _PATH_DEFSPOOL,
&pp->spool_dir));
CHK(capdb_getaltstr(bp, "st", "spool.status", DEFSTAT,
&pp->status_file));
CHK(capdb_getaltstr(bp, "tr", "job.trailer", 0, &pp->trailer));
pp->restricted = capdb_getaltlog(bp, "rs", "daemon.restricted");
pp->short_banner = capdb_getaltlog(bp, "sb", "banner.short");
pp->no_copies = capdb_getaltlog(bp, "sc", "job.no_copies");
pp->no_formfeed = capdb_getaltlog(bp, "sf", "job.no_formfeed");
pp->no_header = capdb_getaltlog(bp, "sh", "banner.disable");
pp->header_last = capdb_getaltlog(bp, "hl", "banner.last");
pp->rw = capdb_getaltlog(bp, "rw", "tty.rw");
pp->tof = capdb_getaltlog(bp, "fo", "job.topofform");
/*
* Filters:
*/
for (filt = 0; filt < LPF_COUNT; filt++) {
CHK(capdb_getaltstr(bp, filters[filt], longfilters[filt], 0,
&pp->filters[filt]));
}
return 0;
}
/*
* Decode the error codes returned by cgetent() using the names we
* made up for them from "lp.h".
* This would have been much better done with Common Error, >sigh<.
* Perhaps this can be fixed in the next incarnation of cget*.
*/
const char *
pcaperr(int error)
{
switch(error) {
case PCAPERR_TCOPEN:
return "unresolved tc= expansion";
case PCAPERR_SUCCESS:
return "no error";
case PCAPERR_NOTFOUND:
return "printer not found";
case PCAPERR_OSERR:
return strerror(errno);
case PCAPERR_TCLOOP:
return "loop detected in tc= expansion";
default:
return "unknown printcap error";
}
}
/*
* Initialize a `struct printer' to contain values harmless to
* the other routines in liblpr.
*/
void
init_printer(struct printer *pp)
{
static struct printer zero;
*pp = zero;
}
/*
* Free the dynamically-allocated strings in a `struct printer'.
* Idempotent.
*/
void
free_printer(struct printer *pp)
{
enum lpd_filters filt;
#define cfree(x) do { if (x) free(x); } while(0)
cfree(pp->printer);
cfree(pp->acct_file);
for (filt = 0; filt < LPF_COUNT; filt++)
cfree(pp->filters[filt]);
cfree(pp->form_feed);
cfree(pp->log_file);
cfree(pp->lock_file);
cfree(pp->lp);
cfree(pp->restrict_grp);
cfree(pp->remote_host);
cfree(pp->remote_queue);
cfree(pp->spool_dir);
cfree(pp->status_file);
cfree(pp->trailer);
cfree(pp->mode_set);
init_printer(pp);
}
/*
* The following routines are part of what would be a sensible library
* interface to capability databases. Maybe someday this will become
* the default.
*/
/*
* It provides similar functionality to cgetstr(),
* except that it provides for both a long and a short
* capability name and allows for a default to be specified.
*/
static int
capdb_getaltstr(char *bp, const char *shrt, const char *lng,
const char *dflt, char **result)
{
int status;
status = cgetstr(bp, (char *)/*XXX*/lng, result);
if (status >= 0 || status == PCAPERR_OSERR)
return status;
status = cgetstr(bp, (char *)/*XXX*/shrt, result);
if (status >= 0 || status == PCAPERR_OSERR)
return status;
if (dflt) {
*result = strdup(dflt);
if (*result == 0)
return PCAPERR_OSERR;
return strlen(*result);
}
return PCAPERR_NOTFOUND;
}
/*
* The same, only for integers.
*/
static int
capdb_getaltnum(char *bp, const char *shrt, const char *lng, long dflt,
long *result)
{
int status;
status = cgetnum(bp, (char *)/*XXX*/lng, result);
if (status >= 0)
return status;
status = cgetnum(bp, (char *)/*XXX*/shrt, result);
if (status >= 0)
return status;
*result = dflt;
return 0;
}
/*
* Likewise for logical values. There's no need for a default parameter
* because the default is always false.
*/
static int
capdb_getaltlog(char *bp, const char *shrt, const char *lng)
{
if (cgetcap(bp, (char *)/*XXX*/lng, ':'))
return 1;
if (cgetcap(bp, (char *)/*XXX*/shrt, ':'))
return 1;
return 0;
}
/*
* Also should be a part of a better cget* library.
* Given a capdb entry, attempt to figure out what its canonical name
* is, and return a malloced copy of it. The canonical name is
* considered to be the first one listed.
*/
static char *
capdb_canonical_name(const char *bp)
{
char *retval;
const char *nameend;
nameend = strpbrk(bp, "|:");
if (nameend == 0)
nameend = bp + 1;
if ((retval = malloc(nameend - bp + 1)) != 0) {
retval[0] = '\0';
strncat(retval, bp, nameend - bp);
}
return retval;
}

View file

@ -43,7 +43,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95";
#endif
static const char rcsid[] =
"$Id: recvjob.c,v 1.10 1997/09/24 06:47:55 charnier Exp $";
"$Id: recvjob.c,v 1.11 1997/10/06 03:58:48 imp Exp $";
#endif /* not lint */
/*
@ -80,54 +80,56 @@ static int noresponse __P((void));
static void rcleanup __P((int));
static int read_number __P((char *));
static int readfile __P((char *, int));
static int readjob __P((void));
static int readjob __P((struct printer *pp));
void
recvjob()
recvjob(printer)
const char *printer;
{
struct stat stb;
int status;
struct printer myprinter, *pp = &myprinter;
/*
* Perform lookup for printer name or abbreviation
*/
if ((status = cgetent(&bp, printcapdb, printer)) == -2)
status = getprintcap(printer, pp);
switch (status) {
case PCAPERR_OSERR:
frecverr("cannot open printer description file");
else if (status == -1)
break;
case PCAPERR_NOTFOUND:
frecverr("unknown printer %s", printer);
else if (status == -3)
fatal("potential reference loop detected in printcap file");
break;
case PCAPERR_TCLOOP:
fatal(pp, "potential reference loop detected in printcap file");
default:
break;
}
if (cgetstr(bp, "lf", &LF) == -1)
LF = _PATH_CONSOLE;
if (cgetstr(bp, "sd", &SD) == -1)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp, "lo", &LO) == -1)
LO = DEFLOCK;
(void) close(2); /* set up log file */
if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
syslog(LOG_ERR, "%s: %m", LF);
if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) {
syslog(LOG_ERR, "%s: %m", pp->log_file);
(void) open(_PATH_DEVNULL, O_WRONLY);
}
if (chdir(SD) < 0)
frecverr("%s: %s: %m", printer, SD);
if (stat(LO, &stb) == 0) {
if (chdir(pp->spool_dir) < 0)
frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
if (stat(pp->lock_file, &stb) == 0) {
if (stb.st_mode & 010) {
/* queue is disabled */
putchar('\1'); /* return error code */
exit(1);
}
} else if (stat(SD, &stb) < 0)
frecverr("%s: %s: %m", printer, SD);
} else if (stat(pp->spool_dir, &stb) < 0)
frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
signal(SIGTERM, rcleanup);
signal(SIGPIPE, rcleanup);
if (readjob())
printjob();
if (readjob(pp))
printjob(pp);
}
/*
@ -135,7 +137,8 @@ recvjob()
* Return the number of jobs successfully transfered.
*/
static int
readjob()
readjob(pp)
struct printer *pp;
{
register int size, nfiles;
register char *cp;
@ -151,7 +154,7 @@ readjob()
if ((size = read(1, cp, 1)) != 1) {
if (size < 0)
frecverr("%s: lost connection",
printer);
pp->printer);
return(nfiles);
}
} while (*cp++ != '\n' && (cp - line + 1) < sizeof(line));

View file

@ -0,0 +1,80 @@
/*
* Copyright 1997 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static const char copyright[] =
"Copyright (C) 1997, Massachusetts Institute of Technology\r\n";
static const char rcsid[] =
"$Id$";
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h> /* needed for lp.h but not used here */
#include <dirent.h> /* ditto */
#include <stdio.h> /* ditto */
#include "lp.h"
#include "lp.local.h"
void
init_request(struct request *rp)
{
static struct request zero;
*rp = zero;
TAILQ_INIT(&rp->users);
TAILQ_INIT(&rp->jobids);
}
void
free_request(struct request *rp)
{
struct req_user *ru;
struct req_jobid *rj;
if (rp->logname)
free(rp->logname);
if (rp->authname)
free(rp->authname);
if (rp->prettyname)
free(rp->prettyname);
if (rp->authinfo)
free(rp->authinfo);
while ((ru = rp->users.tqh_first) != 0) {
TAILQ_REMOVE(&rp->users, ru, ru_link);
free(ru);
}
while ((rj = rp->jobids.tqh_first) != 0) {
TAILQ_REMOVE(&rp->jobids, rj, rj_link);
free(rj);
}
init_request(rp);
}

View file

@ -36,19 +36,25 @@
static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$Id: rmjob.c,v 1.9 1997/09/24 06:47:31 charnier Exp $";
"$Id: rmjob.c,v 1.10 1997/10/14 16:00:37 joerg Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/uio.h>
#include <signal.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define psignal foil_gcc_psignal
#define sys_siglist foil_gcc_siglist
#include <unistd.h>
#undef psignal
#undef sys_siglist
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
@ -71,32 +77,22 @@ static void alarmhandler __P((int));
static void do_unlink __P((char *));
void
rmjob()
rmjob(printer)
const char *printer;
{
register int i, nitems;
int assasinated = 0;
struct dirent **files;
char *cp;
struct printer myprinter, *pp = &myprinter;
if ((i = cgetent(&bp, printcapdb, printer)) == -2)
fatal("can't open printer description file");
else if (i == -1)
fatal("unknown printer");
else if (i == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "lp", &LP) < 0)
LP = _PATH_DEFDEVLP;
if (cgetstr(bp, "rp", &RP) < 0)
RP = DEFLP;
if (cgetstr(bp, "sd", &SD) < 0)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp,"lo", &LO) < 0)
LO = DEFLOCK;
if (cgetnum(bp, "ct", &CT) < 0)
CT = DEFTIMEOUT;
cgetstr(bp, "rm", &RM);
if ((cp = checkremote()))
init_printer(pp);
if ((i = getprintcap(printer, pp)) < 0)
fatal(pp, "getprintcap: %s", pcaperr(i));
if ((cp = checkremote(pp))) {
printf("Warning: %s\n", cp);
free(cp);
}
/*
* If the format was `lprm -' and the user isn't the super-user,
@ -112,16 +108,16 @@ rmjob()
}
if (!strcmp(person, "-all")) {
if (from == host)
fatal("The login name \"-all\" is reserved");
fatal(pp, "The login name \"-all\" is reserved");
all = 1; /* all those from 'from' */
person = root;
}
seteuid(euid);
if (chdir(SD) < 0)
fatal("cannot chdir to spool directory");
if (chdir(pp->spool_dir) < 0)
fatal(pp, "cannot chdir to spool directory");
if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
fatal("cannot access spool directory");
fatal(pp, "cannot access spool directory");
seteuid(uid);
if (nitems) {
@ -130,25 +126,25 @@ rmjob()
* kill it if it is reading our file) then remove stuff
* (after which we have to restart the daemon).
*/
if (lockchk(LO) && chk(current)) {
if (lockchk(pp, pp->lock_file) && chk(current)) {
seteuid(euid);
assasinated = kill(cur_daemon, SIGINT) == 0;
seteuid(uid);
if (!assasinated)
fatal("cannot kill printer daemon");
fatal(pp, "cannot kill printer daemon");
}
/*
* process the files
*/
for (i = 0; i < nitems; i++)
process(files[i]->d_name);
process(pp, files[i]->d_name);
}
rmremote();
rmremote(pp);
/*
* Restart the printer daemon if it was killed
*/
if (assasinated && !startdaemon(printer))
fatal("cannot restart printer daemon\n");
if (assasinated && !startdaemon(pp))
fatal(pp, "cannot restart printer daemon\n");
exit(0);
}
@ -158,7 +154,8 @@ rmjob()
* Return boolean indicating existence of a lock file.
*/
int
lockchk(s)
lockchk(pp, s)
struct printer *pp;
char *s;
{
register FILE *fp;
@ -167,7 +164,7 @@ lockchk(s)
seteuid(euid);
if ((fp = fopen(s, "r")) == NULL) {
if (errno == EACCES)
fatal("can't access lock file");
fatal(pp, "%s: %s", s, strerror(errno));
else
return(0);
}
@ -197,7 +194,8 @@ lockchk(s)
* Process a control file.
*/
void
process(file)
process(pp, file)
const struct printer *pp;
char *file;
{
FILE *cfp;
@ -206,7 +204,7 @@ process(file)
return;
seteuid(euid);
if ((cfp = fopen(file, "r")) == NULL)
fatal("cannot open %s", file);
fatal(pp, "cannot open %s", file);
seteuid(uid);
while (getline(cfp)) {
switch (line[0]) {
@ -315,14 +313,15 @@ isowner(owner, file)
* then try removing files on the remote machine.
*/
void
rmremote()
rmremote(pp)
const struct printer *pp;
{
register char *cp;
register int i, rem;
int i, rem, niov, totlen;
char buf[BUFSIZ];
void (*savealrm)(int);
struct iovec *iov;
if (!remote)
if (!pp->remote)
return; /* not sending to a remote machine */
/*
@ -331,34 +330,55 @@ rmremote()
*/
fflush(stdout);
(void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person);
cp = buf;
for (i = 0; i < users && cp-buf+1+strlen(user[i]) < sizeof(buf); i++) {
cp += strlen(cp);
*cp++ = ' ';
strcpy(cp, user[i]);
/*
* Counting:
* 4 == "\5" + remote_queue + " " + person
* 2 * users == " " + user[i] for each user
* requests == asprintf results for each request
* 1 == "\n"
* Although laborious, doing it this way makes it possible for
* us to process requests of indeterminate length without
* applying an arbitrary limit. Arbitrary Limits Are Bad (tm).
*/
niov = 4 + 2 * users + requests + 1;
iov = malloc(niov * sizeof *iov);
if (iov == 0)
fatal(pp, "out of memory");
iov[0].iov_base = "\5";
iov[1].iov_base = pp->remote_queue;
iov[2].iov_base = " ";
iov[3].iov_base = all ? "-all" : person;
for (i = 0; i < users; i++) {
iov[4 + 2 * i].iov_base = " ";
iov[4 + 2 * i + 1].iov_base = user[i];
}
for (i = 0; i < requests && cp-buf+10 < sizeof(buf) - 1; i++) {
cp += strlen(cp);
(void) sprintf(cp, " %d", requ[i]);
for (i = 0; i < requests; i++) {
asprintf(&iov[4 + 2 * users + i].iov_base, " %d", requ[i]);
if (iov[4 + 2 * users + i].iov_base == 0)
fatal(pp, "out of memory");
}
strcat(cp, "\n");
iov[4 + 2 * users + requests].iov_base = "\n";
for (totlen = i = 0; i < niov; i++)
totlen += (iov[i].iov_len = strlen(iov[i].iov_base));
savealrm = signal(SIGALRM, alarmhandler);
alarm(CT);
rem = getport(RM, 0);
alarm(pp->conn_timeout);
rem = getport(pp, pp->remote_host, 0);
(void)signal(SIGALRM, savealrm);
if (rem < 0) {
if (from != host)
printf("%s: ", host);
printf("connection to %s is down\n", RM);
printf("connection to %s is down\n", pp->remote_host);
} else {
i = strlen(buf);
if (write(rem, buf, i) != i)
fatal("Lost connection");
if (writev(rem, iov, niov) != totlen)
fatal(pp, "Lost connection");
while ((i = read(rem, buf, sizeof(buf))) > 0)
(void) fwrite(buf, 1, i, stdout);
(void) close(rem);
}
for (i = 0; i < requests; i++)
free(iov[4 + 2 * users + i].iov_base);
free(iov);
}
/*
@ -373,6 +393,7 @@ iscf(d)
void
alarmhandler(signo)
int signo;
{
/* ignored */
}

View file

@ -36,12 +36,13 @@
static char sccsid[] = "@(#)startdaemon.c 8.2 (Berkeley) 4/17/94";
#endif
static const char rcsid[] =
"$Id$";
"$Id: startdaemon.c,v 1.6 1997/09/24 06:47:32 charnier Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <dirent.h>
@ -59,20 +60,20 @@ extern uid_t uid, euid;
*/
int
startdaemon(printer)
char *printer;
startdaemon(pp)
const struct printer *pp;
{
struct sockaddr_un un;
register int s, n;
char buf[BUFSIZ];
char c;
s = socket(AF_UNIX, SOCK_STREAM, 0);
s = socket(PF_LOCAL, SOCK_STREAM, 0);
if (s < 0) {
warn("socket");
return(0);
}
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
un.sun_family = AF_LOCAL;
strcpy(un.sun_path, _PATH_SOCKETNAME);
#ifndef SUN_LEN
#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
@ -85,25 +86,25 @@ startdaemon(printer)
return(0);
}
seteuid(uid);
if (snprintf(buf, sizeof(buf), "\1%s\n", printer) > sizeof(buf) - 1) {
close(s);
return (0);
}
n = strlen(buf);
if (write(s, buf, n) != n) {
/*
* Avoid overruns without putting artificial limitations on
* the length.
*/
if (writel(s, "\1", pp->printer, "\n", (char *)0) <= 0) {
warn("write");
(void) close(s);
return(0);
}
if (read(s, buf, 1) == 1) {
if (buf[0] == '\0') { /* everything is OK */
if (read(s, &c, 1) == 1) {
if (c == '\0') { /* everything is OK */
(void) close(s);
return(1);
}
putchar(buf[0]);
putchar(c);
}
while ((n = read(s, buf, sizeof(buf))) > 0)
fwrite(buf, 1, n, stdout);
while ((n = read(s, &c, 1)) > 0)
putchar(c);
(void) close(s);
return(0);
}

View file

@ -1,4 +1,4 @@
# @(#)Makefile 5.6 (Berkeley) 6/23/90
# $Id$
BINDIR = /usr/bin
MAN1 = lp.1

View file

@ -1,12 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= lpc
CFLAGS+=-I${.CURDIR}/../common_source
CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
MAN8= lpc.8
SRCS= lpc.c cmds.c cmdtab.c startdaemon.c common.c
SRCS= lpc.c cmds.c cmdtab.c
BINGRP= daemon
BINMODE=2555
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include "../../Makefile.inc"
.include <bsd.prog.mk>

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,11 @@
*/
#ifndef lint
/*
static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <sys/cdefs.h>
@ -58,20 +62,20 @@ char topqhelp[] = "put job at top of printer queue";
char uphelp[] = "enable everything and restart spooling daemon";
struct cmd cmdtab[] = {
{ "abort", aborthelp, doabort, 1 },
{ "clean", cleanhelp, clean, 1 },
{ "enable", enablehelp, enable, 1 },
{ "abort", aborthelp, 0, 1, doabort },
{ "clean", cleanhelp, 0, 1, clean },
{ "enable", enablehelp, 0, 1, enable },
{ "exit", quithelp, quit, 0 },
{ "disable", disablehelp, disable, 1 },
{ "disable", disablehelp, 0, 1, disable },
{ "down", downhelp, down, 1 },
{ "help", helphelp, help, 0 },
{ "quit", quithelp, quit, 0 },
{ "restart", restarthelp, restart, 0 },
{ "start", starthelp, startcmd, 1 },
{ "status", statushelp, status, 0 },
{ "stop", stophelp, stop, 1 },
{ "restart", restarthelp, 0, 0, restart },
{ "start", starthelp, 0, 1, startcmd },
{ "status", statushelp, 0, 0, status },
{ "stop", stophelp, 0, 1, stop },
{ "topq", topqhelp, topq, 1 },
{ "up", uphelp, up, 1 },
{ "up", uphelp, 0, 1, up },
{ "?", helphelp, help, 0 },
{ 0 },
};

View file

@ -39,19 +39,20 @@
__BEGIN_DECLS
void clean __P((int, char **));
void disable __P((int, char **));
void doabort __P((int, char **));
void clean __P((struct printer *));
void disable __P((struct printer *));
void doabort __P((struct printer *));
void down __P((int, char **));
void enable __P((int, char **));
void enable __P((struct printer *));
void generic __P((void (*) __P((struct printer *)), int, char **));
void help __P((int, char **));
void quit __P((int, char **));
void restart __P((int, char **));
void startcmd __P((int, char **));
void status __P((int, char **));
void stop __P((int, char **));
void restart __P((struct printer *));
void startcmd __P((struct printer *));
void status __P((struct printer *));
void stop __P((struct printer *));
void topq __P((int, char **));
void up __P((int, char **));
void up __P((struct printer *));
__END_DECLS
extern int NCMDS;

View file

@ -43,13 +43,14 @@ static const char copyright[] =
static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$Id$";
"$Id: lpc.c,v 1.5 1997/09/24 06:47:46 charnier Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <grp.h>
#include <setjmp.h>
#include <signal.h>
@ -58,7 +59,7 @@ static const char rcsid[] =
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include "lp.h"
#include "lpc.h"
#include "extern.h"
@ -116,7 +117,10 @@ main(argc, argv)
printf("?Privileged command\n");
exit(1);
}
(*c->c_handler)(argc, argv);
if (c->c_generic != 0)
generic(c->c_generic, argc, argv);
else
(*c->c_handler)(argc, argv);
exit(0);
}
fromatty = isatty(fileno(stdin));
@ -172,7 +176,10 @@ cmdscanner(top)
printf("?Privileged command\n");
continue;
}
(*c->c_handler)(margc, margv);
if (c->c_generic != 0)
generic(c->c_generic, margc, margv);
else
(*c->c_handler)(margc, margv);
}
longjmp(toplevel, 0);
}

View file

@ -36,10 +36,13 @@
/*
* Line printer control program.
*/
struct printer;
struct cmd {
char *c_name; /* command name */
char *c_help; /* help message */
/* routine to do the work */
void (*c_handler) __P((int, char *[]));
int c_priv; /* privileged command */
void (*c_generic) __P((struct printer *)); /* generic command */
};

View file

@ -1,11 +1,11 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= lpd
CFLAGS+=-I${.CURDIR}/../common_source
CFLAGS+=-I${.CURDIR}/../common_source -Wall -Werror
MAN8= lpd.8
SRCS= lpd.c printjob.c recvjob.c displayq.c rmjob.c startdaemon.c \
lpdchar.c common.c modes.c
.PATH: ${.CURDIR}/../common_source
SRCS= lpd.c printjob.c recvjob.c lpdchar.c modes.c
LDADD= -L${.OBJDIR}/../common_source -llpr
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -30,7 +30,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
* From: @(#)extern.h 8.1 (Berkeley) 6/6/93
* $Id$
*/
#include <sys/cdefs.h>
@ -38,5 +39,10 @@
extern char scnkey[][HEIGHT]; /* in lpdchar.c */
extern char fromb[];
void printjob __P((void));
void recvjob __P((void));
struct printer;
__BEGIN_DECLS
void printjob __P((struct printer *pp));
void startprinting __P((const char *printer));
void recvjob __P((const char *printer));
__END_DECLS

View file

@ -43,7 +43,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95";
#endif
static const char rcsid[] =
"$Id$";
"$Id: lpd.c,v 1.8 1997/09/24 06:47:54 charnier Exp $";
#endif /* not lint */
/*
@ -111,8 +111,11 @@ 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 int ckqueue __P((struct printer *));
static void usage __P((void));
/* From rcmd.c: */
int __ivaliduser __P((FILE *, u_long, const char *,
const char *));
uid_t uid, euid;
@ -125,7 +128,8 @@ main(argc, argv)
fd_set defreadfds;
struct sockaddr_un un, fromunix;
struct sockaddr_in sin, frominet;
int omask, lfd;
int lfd;
sigset_t omask, nmask;
struct servent *sp, serv;
euid = geteuid(); /* these shouldn't be different */
@ -173,6 +177,31 @@ main(argc, argv)
if (argc != 0)
usage();
/*
* We run chkprintcap right away to catch any errors and blat them
* to stderr while we still have it open, rather than sending them
* to syslog and leaving the user wondering why lpd started and
* then stopped. There should probably be a command-line flag to
* ignore errors from chkprintcap.
*/
{
pid_t pid;
int status;
pid = fork();
if (pid < 0) {
err(EX_OSERR, "cannot fork");
} else if (pid == 0) { /* child */
execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0);
err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP);
}
if (waitpid(pid, &status, 0) < 0) {
err(EX_OSERR, "cannot wait");
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
errx(EX_OSFILE, "%d errors in printcap file, exiting",
WEXITSTATUS(status));
}
#ifndef DEBUG
/*
* Set up standard environment by detaching from the parent.
@ -183,17 +212,22 @@ main(argc, argv)
openlog("lpd", LOG_PID, LOG_LPR);
syslog(LOG_INFO, "restarted");
(void) umask(0);
lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644);
/*
* NB: This depends on O_NONBLOCK semantics doing the right thing;
* i.e., applying only to the O_EXLOCK and not to the rest of the
* open/creation. As of 1997-12-02, this is the case for commonly-
* used filesystems. There are other places in this code which
* make the same assumption.
*/
lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK,
LOCK_FILE_MODE);
if (lfd < 0) {
syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
exit(1);
}
if (flock(lfd, LOCK_EX|LOCK_NB) < 0) {
if (errno == EWOULDBLOCK) /* active deamon present */
exit(0);
syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK);
exit(1);
}
fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */
ftruncate(lfd, 0);
/*
* write process id for others to know
@ -215,8 +249,14 @@ main(argc, argv)
syslog(LOG_ERR, "socket: %m");
exit(1);
}
#define mask(s) (1 << ((s) - 1))
omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
sigemptyset(&nmask);
sigaddset(&nmask, SIGHUP);
sigaddset(&nmask, SIGINT);
sigaddset(&nmask, SIGQUIT);
sigaddset(&nmask, SIGTERM);
sigprocmask(SIG_BLOCK, &nmask, &omask);
(void) umask(07);
signal(SIGHUP, mcleanup);
signal(SIGINT, mcleanup);
@ -233,7 +273,7 @@ main(argc, argv)
exit(1);
}
(void) umask(0);
sigsetmask(omask);
sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
FD_ZERO(&defreadfds);
FD_SET(funix, &defreadfds);
listen(funix, 5);
@ -259,6 +299,9 @@ main(argc, argv)
*/
memset(&frominet, 0, sizeof(frominet));
memset(&fromunix, 0, sizeof(fromunix));
/*
* XXX - should be redone for multi-protocol
*/
for (;;) {
int domain, nfds, s;
fd_set readfds;
@ -353,17 +396,21 @@ char *cmdnames[] = {
static void
doit()
{
register char *cp;
register int n;
char *cp, *printer;
int n;
int status;
struct printer myprinter, *pp = &myprinter;
init_printer(&myprinter);
for (;;) {
cp = cbuf;
do {
if (cp >= &cbuf[sizeof(cbuf) - 1])
fatal("Command line too long");
fatal(0, "Command line too long");
if ((n = read(1, cp, 1)) != 1) {
if (n < 0)
fatal("Lost connection");
fatal(0, "Lost connection");
return;
}
} while (*cp++ != '\n');
@ -372,26 +419,25 @@ doit()
if (lflag) {
if (*cp >= '\1' && *cp <= '\5')
syslog(LOG_INFO, "%s requests %s %s",
from, cmdnames[*cp], cp+1);
from, cmdnames[(u_char)*cp], cp+1);
else
syslog(LOG_INFO, "bad request (%d) from %s",
*cp, from);
}
switch (*cp++) {
case '\1': /* check the queue and print any jobs there */
printer = cp;
printjob();
case CMD_CHECK_QUE: /* check the queue, print any jobs there */
startprinting(cp);
break;
case '\2': /* receive files to be queued */
case CMD_TAKE_THIS: /* receive files to be queued */
if (!from_remote) {
syslog(LOG_INFO, "illegal request (%d)", *cp);
exit(1);
}
printer = cp;
recvjob();
recvjob(cp);
break;
case '\3': /* display the queue (short form) */
case '\4': /* display the queue (long form) */
case CMD_SHOWQ_SHORT: /* display the queue (short form) */
case CMD_SHOWQ_LONG: /* display the queue (long form) */
/* XXX - this all needs to be redone. */
printer = cp;
while (*cp) {
if (*cp != ' ') {
@ -405,17 +451,20 @@ doit()
break;
if (isdigit(*cp)) {
if (requests >= MAXREQUESTS)
fatal("Too many requests");
fatal(0, "Too many requests");
requ[requests++] = atoi(cp);
} else {
if (users >= MAXUSERS)
fatal("Too many users");
fatal(0, "Too many users");
user[users++] = cp;
}
}
displayq(cbuf[0] - '\3');
status = getprintcap(printer, pp);
if (status < 0)
fatal(pp, pcaperr(status));
displayq(pp, cbuf[0] == CMD_SHOWQ_LONG);
exit(0);
case '\5': /* remove a job from the queue */
case CMD_RMJOB: /* remove a job from the queue */
if (!from_remote) {
syslog(LOG_INFO, "illegal request (%d)", *cp);
exit(1);
@ -439,18 +488,18 @@ doit()
break;
if (isdigit(*cp)) {
if (requests >= MAXREQUESTS)
fatal("Too many requests");
fatal(0, "Too many requests");
requ[requests++] = atoi(cp);
} else {
if (users >= MAXUSERS)
fatal("Too many users");
fatal(0, "Too many users");
user[users++] = cp;
}
}
rmjob();
rmjob(printer);
break;
}
fatal("Illegal service request");
fatal(0, "Illegal service request");
}
}
@ -461,66 +510,36 @@ doit()
static void
startup()
{
char *buf;
register char *cp;
int pid;
char *spooldirs[16]; /* Which spooldirs are active? */
int i; /* Printer index presently processed */
int j; /* Printer index of potential conflict */
char *spooldir; /* Spooldir of present printer */
int canfreespool; /* Is the spooldir malloc()ed? */
int pid, status, more;
struct printer myprinter, *pp = &myprinter;
/*
* Restart the daemons and test for spooldir conflict.
*/
i = 0;
while (cgetnext(&buf, printcapdb) > 0) {
/* Check for duplicate spooldirs */
canfreespool = 1;
if (cgetstr(buf, "sd", &spooldir) <= 0) {
spooldir = _PATH_DEFSPOOL;
canfreespool = 0;
more = firstprinter(pp, &status);
if (status)
goto errloop;
while (more) {
if (ckqueue(pp) <= 0) {
goto next;
}
if (i < sizeof(spooldirs)/sizeof(spooldirs[0]))
spooldirs[i] = spooldir;
for (j = 0;
j < MIN(i,sizeof(spooldirs)/sizeof(spooldirs[0]));
j++) {
if (strcmp(spooldir, spooldirs[j]) == 0) {
syslog(LOG_ERR,
"startup: duplicate spool directories: %s",
spooldir);
mcleanup(0);
}
}
if (canfreespool && i >= sizeof(spooldirs)/sizeof(spooldirs[0]))
free(spooldir);
i++;
/* Spooldir test done */
if (ckqueue(buf) <= 0) {
free(buf);
continue; /* no work to do for this printer */
}
for (cp = buf; *cp; cp++)
if (*cp == '|' || *cp == ':') {
*cp = '\0';
break;
}
if (lflag)
syslog(LOG_INFO, "work for %s", buf);
syslog(LOG_INFO, "work for %s", pp->printer);
if ((pid = fork()) < 0) {
syslog(LOG_WARNING, "startup: cannot fork");
mcleanup(0);
}
if (!pid) {
printer = buf;
cgetclose();
printjob();
if (pid == 0) {
lastprinter();
printjob(pp);
/* NOTREACHED */
}
else free(buf);
do {
next:
more = nextprinter(pp, &status);
errloop:
if (status)
syslog(LOG_WARNING,
"printcap for %s has errors, skipping",
pp->printer ? pp->printer : "<???>");
} while (more && status);
}
}
@ -528,15 +547,14 @@ startup()
* Make sure there's some work to do before forking off a child
*/
static int
ckqueue(cap)
char *cap;
ckqueue(pp)
struct printer *pp;
{
register struct dirent *d;
DIR *dirp;
char *spooldir;
if (cgetstr(cap, "sd", &spooldir) == -1)
spooldir = _PATH_DEFSPOOL;
spooldir = pp->spool_dir;
if ((dirp = opendir(spooldir)) == NULL)
return (-1);
while ((d = readdir(dirp)) != NULL) {
@ -567,7 +585,7 @@ chkhost(f)
hp = gethostbyaddr((char *)&f->sin_addr,
sizeof(struct in_addr), f->sin_family);
if (hp == NULL)
fatal("Host name for your address (%s) unknown",
fatal(0, "Host name for your address (%s) unknown",
inet_ntoa(f->sin_addr));
(void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1);
@ -577,7 +595,7 @@ chkhost(f)
/* Check for spoof, ala rlogind */
hp = gethostbyname(fromb);
if (!hp)
fatal("hostname for your address (%s) unknown",
fatal(0, "hostname for your address (%s) unknown",
inet_ntoa(f->sin_addr));
for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
@ -585,7 +603,7 @@ chkhost(f)
good = 1;
}
if (good == 0)
fatal("address for your hostname (%s) not matched",
fatal(0, "address for your hostname (%s) not matched",
inet_ntoa(f->sin_addr));
hostf = fopen(_PATH_HOSTSEQUIV, "r");
@ -603,7 +621,7 @@ again:
hostf = fopen(_PATH_HOSTSLPD, "r");
goto again;
}
fatal("Your host does not have line printer access");
fatal(0, "Your host does not have line printer access");
/*NOTREACHED*/
}

View file

@ -32,7 +32,11 @@
*/
#ifndef lint
/*
static char sccsid[] = "@(#)lpdchar.c 8.1 (Berkeley) 6/6/93";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
/*

View file

@ -29,12 +29,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#ifndef lint
/*
static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <stddef.h>

File diff suppressed because it is too large Load diff

View file

@ -43,7 +43,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)recvjob.c 8.2 (Berkeley) 4/27/95";
#endif
static const char rcsid[] =
"$Id: recvjob.c,v 1.10 1997/09/24 06:47:55 charnier Exp $";
"$Id: recvjob.c,v 1.11 1997/10/06 03:58:48 imp Exp $";
#endif /* not lint */
/*
@ -80,54 +80,56 @@ static int noresponse __P((void));
static void rcleanup __P((int));
static int read_number __P((char *));
static int readfile __P((char *, int));
static int readjob __P((void));
static int readjob __P((struct printer *pp));
void
recvjob()
recvjob(printer)
const char *printer;
{
struct stat stb;
int status;
struct printer myprinter, *pp = &myprinter;
/*
* Perform lookup for printer name or abbreviation
*/
if ((status = cgetent(&bp, printcapdb, printer)) == -2)
status = getprintcap(printer, pp);
switch (status) {
case PCAPERR_OSERR:
frecverr("cannot open printer description file");
else if (status == -1)
break;
case PCAPERR_NOTFOUND:
frecverr("unknown printer %s", printer);
else if (status == -3)
fatal("potential reference loop detected in printcap file");
break;
case PCAPERR_TCLOOP:
fatal(pp, "potential reference loop detected in printcap file");
default:
break;
}
if (cgetstr(bp, "lf", &LF) == -1)
LF = _PATH_CONSOLE;
if (cgetstr(bp, "sd", &SD) == -1)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp, "lo", &LO) == -1)
LO = DEFLOCK;
(void) close(2); /* set up log file */
if (open(LF, O_WRONLY|O_APPEND, 0664) < 0) {
syslog(LOG_ERR, "%s: %m", LF);
if (open(pp->log_file, O_WRONLY|O_APPEND, 0664) < 0) {
syslog(LOG_ERR, "%s: %m", pp->log_file);
(void) open(_PATH_DEVNULL, O_WRONLY);
}
if (chdir(SD) < 0)
frecverr("%s: %s: %m", printer, SD);
if (stat(LO, &stb) == 0) {
if (chdir(pp->spool_dir) < 0)
frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
if (stat(pp->lock_file, &stb) == 0) {
if (stb.st_mode & 010) {
/* queue is disabled */
putchar('\1'); /* return error code */
exit(1);
}
} else if (stat(SD, &stb) < 0)
frecverr("%s: %s: %m", printer, SD);
} else if (stat(pp->spool_dir, &stb) < 0)
frecverr("%s: %s: %m", pp->printer, pp->spool_dir);
minfree = 2 * read_number("minfree"); /* scale KB to 512 blocks */
signal(SIGTERM, rcleanup);
signal(SIGPIPE, rcleanup);
if (readjob())
printjob();
if (readjob(pp))
printjob(pp);
}
/*
@ -135,7 +137,8 @@ recvjob()
* Return the number of jobs successfully transfered.
*/
static int
readjob()
readjob(pp)
struct printer *pp;
{
register int size, nfiles;
register char *cp;
@ -151,7 +154,7 @@ readjob()
if ((size = read(1, cp, 1)) != 1) {
if (size < 0)
frecverr("%s: lost connection",
printer);
pp->printer);
return(nfiles);
}
} while (*cp++ != '\n' && (cp - line + 1) < sizeof(line));

View file

@ -1,13 +1,14 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= lpq
CFLAGS+=-I${.CURDIR}/../common_source
SRCS= lpq.c displayq.c common.c
CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
SRCS= lpq.c
BINOWN= root
BINGRP= daemon
BINMODE=6555
BINDIR= /usr/bin
MAN1= lpq.1
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include <bsd.prog.mk>

View file

@ -33,13 +33,17 @@
*/
#ifndef lint
static char copyright[] =
static const char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
/*
static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
/*
@ -54,12 +58,14 @@ static char sccsid[] = "@(#)lpq.c 8.3 (Berkeley) 5/10/95";
#include <sys/param.h>
#include <syslog.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
@ -71,19 +77,19 @@ int users; /* # of users in user array */
uid_t uid, euid;
static int ckqueue __P((char *));
static int ckqueue __P((const struct printer *));
static void usage __P((void));
int
main(argc, argv)
register int argc;
register char **argv;
int argc;
char **argv;
{
extern char *optarg;
extern int optind;
int ch, aflag, lflag;
char *buf, *cp;
int ch, aflag, lflag;
char *printer;
struct printer myprinter, *pp = &myprinter;
printer = NULL;
euid = geteuid();
uid = getuid();
seteuid(uid);
@ -115,47 +121,64 @@ main(argc, argv)
for (argc -= optind, argv += optind; argc; --argc, ++argv)
if (isdigit(argv[0][0])) {
if (requests >= MAXREQUESTS)
fatal("too many requests");
fatal(0, "too many requests");
requ[requests++] = atoi(*argv);
}
else {
if (users >= MAXUSERS)
fatal("too many users");
fatal(0, "too many users");
user[users++] = *argv;
}
if (aflag) {
while (cgetnext(&buf, printcapdb) > 0) {
if (ckqueue(buf) <= 0) {
free(buf);
continue; /* no jobs */
int more, status;
more = firstprinter(pp, &status);
if (status)
goto looperr;
while (more) {
if (ckqueue(pp) > 0) {
printf("%s:\n", pp->printer);
displayq(pp, lflag);
printf("\n");
}
for (cp = buf; *cp; cp++)
if (*cp == '|' || *cp == ':') {
*cp = '\0';
do {
more = nextprinter(pp, &status);
looperr:
switch (status) {
case PCAPERR_TCOPEN:
printf("warning: %s: unresolved "
"tc= reference(s) ",
pp->printer);
case PCAPERR_SUCCESS:
break;
default:
fatal(pp, pcaperr(status));
}
printer = buf;
printf("%s:\n", printer);
displayq(lflag);
free(buf);
printf("\n");
} while (more && status);
}
} else
displayq(lflag);
} else {
int status;
init_printer(pp);
status = getprintcap(printer, pp);
if (status < 0)
fatal(pp, pcaperr(status));
displayq(pp, lflag);
}
exit(0);
}
static int
ckqueue(cap)
char *cap;
ckqueue(pp)
const struct printer *pp;
{
register struct dirent *d;
DIR *dirp;
char *spooldir;
if (cgetstr(cap, "sd", &spooldir) == -1)
spooldir = _PATH_DEFSPOOL;
spooldir = pp->spool_dir;
if ((dirp = opendir(spooldir)) == NULL)
return (-1);
while ((d = readdir(dirp)) != NULL) {

View file

@ -1,13 +1,15 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= lpr
CFLAGS+=-I${.CURDIR}/../common_source
SRCS= lpr.c startdaemon.c common.c
CFLAGS+=-I${.CURDIR}/../common_source ${CWARNFLAGS}
SRCS= lpr.c
BINOWN= root
BINGRP= daemon
BINMODE=6555
BINDIR= /usr/bin
MAN1= lpr.1
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include <bsd.prog.mk>

View file

@ -48,7 +48,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)from: lpr.c 8.4 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$Id$";
"$Id: lpr.c,v 1.21 1997/09/24 06:48:07 charnier Exp $";
#endif /* not lint */
/*
@ -64,6 +64,7 @@ static const char rcsid[] =
#include <dirent.h>
#include <fcntl.h>
#include <a.out.h>
#include <err.h>
#include <signal.h>
#include <syslog.h>
#include <pwd.h>
@ -104,14 +105,14 @@ static struct stat statb;
static void card __P((int, char *));
static int checkwriteperm __P((char*, char *));
static void chkprinter __P((char *));
static void chkprinter __P((char *printer, struct printer *pp));
static void cleanup __P((int));
static void copy __P((int, char []));
static void fatal2 __P((const char *, ...));
static void copy __P((const struct printer *, int, char []));
static char *itoa __P((int));
static char *linked __P((char *));
static char *lmktemp __P((char *, int, int));
static void mktemps __P((void));
int main __P((int, char **));
static char *lmktemp __P((const struct printer *pp, char *, int, int));
static void mktemps __P((const struct printer *pp));
static int nfile __P((char *));
static int test __P((char *));
static void usage __P((void));
@ -125,11 +126,13 @@ main(argc, argv)
{
struct passwd *pw;
struct group *gptr;
register char *arg, *cp;
char *arg, *cp, *printer;
char buf[BUFSIZ];
int c, i, f, errs;
struct stat stb;
struct printer myprinter, *pp = &myprinter;
printer = NULL;
euid = geteuid();
uid = getuid();
seteuid(uid);
@ -247,27 +250,32 @@ main(argc, argv)
usage();
if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
printer = DEFLP;
chkprinter(printer);
if (SC && ncopies > 1)
fatal2("multiple copies are not allowed");
if (MC > 0 && ncopies > MC)
fatal2("only %d copies are allowed", MC);
chkprinter(printer, pp);
if (pp->no_copies && ncopies > 1)
errx(1, "multiple copies are not allowed");
if (pp->max_copies > 0 && ncopies > pp->max_copies)
errx(1, "only %d copies are allowed", pp->max_copies);
/*
* Get the identity of the person doing the lpr using the same
* algorithm as lprm.
* algorithm as lprm. Actually, not quite -- lprm will override
* the login name with "root" if the user is running as root;
* the daemon actually checks for the string "root" in its
* permission checking. Sigh.
*/
userid = getuid();
if (userid != DU || person == 0) {
if ((pw = getpwuid(userid)) == NULL)
fatal2("Who are you?");
person = pw->pw_name;
if ((person = getlogin()) == NULL) {
userid = getuid();
if (userid != pp->daemon_user || person == 0) {
if ((pw = getpwuid(userid)) == NULL)
errx(1, "Who are you?");
person = pw->pw_name;
}
}
/*
* Check for restricted group access.
*/
if (RG != NULL && userid != DU) {
if ((gptr = getgrnam(RG)) == NULL)
fatal2("Restricted group specified incorrectly");
if (pp->restrict_grp != NULL && userid != pp->daemon_user) {
if ((gptr = getgrnam(pp->restrict_grp)) == NULL)
errx(1, "Restricted group specified incorrectly");
if (gptr->gr_gid != getgid()) {
while (*gptr->gr_mem != NULL) {
if ((strcmp(person, *gptr->gr_mem)) == 0)
@ -275,22 +283,23 @@ main(argc, argv)
gptr->gr_mem++;
}
if (*gptr->gr_mem == NULL)
fatal2("Not a member of the restricted group");
errx(1, "Not a member of the restricted group");
}
}
/*
* Check to make sure queuing is enabled if userid is not root.
*/
(void) snprintf(buf, sizeof(buf), "%s/%s", SD, LO);
if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
fatal2("Printer queue is disabled");
lock_file_name(pp, buf, sizeof buf);
if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS))
errx(1, "Printer queue is disabled");
/*
* Initialize the control file.
*/
mktemps();
mktemps(pp);
tfd = nfile(tfname);
seteuid(euid);
(void) fchown(tfd, DU, -1); /* owned by daemon for protection */
(void) fchown(tfd, pp->daemon_user, -1);
/* owned by daemon for protection */
seteuid(uid);
card('H', host);
card('P', person);
@ -299,7 +308,8 @@ main(argc, argv)
if (argc == 0)
jobname = "stdin";
else
jobname = (arg = strrchr(argv[0], '/')) ? arg+1 : argv[0];
jobname = ((arg = strrchr(argv[0], '/'))
? arg + 1 : argv[0]);
}
card('J', jobname);
card('C', class);
@ -320,11 +330,11 @@ main(argc, argv)
* Read the files and spool them.
*/
if (argc == 0)
copy(0, " ");
copy(pp, 0, " ");
else while (argc--) {
if (argv[0][0] == '-' && argv[0][1] == '\0') {
/* use stdin */
copy(0, " ");
copy(pp, 0, " ");
argv++;
continue;
}
@ -352,7 +362,7 @@ main(argc, argv)
if ((i = open(arg, O_RDONLY)) < 0) {
printf("%s: cannot open %s\n", name, arg);
} else {
copy(i, arg);
copy(pp, i, arg);
(void) close(i);
if (f && unlink(arg) < 0)
printf("%s: %s: not removed\n", name, arg);
@ -387,7 +397,7 @@ main(argc, argv)
seteuid(uid);
if (qflag) /* just q things up */
exit(0);
if (!startdaemon(printer))
if (!startdaemon(pp))
printf("jobs queued, but cannot start daemon.\n");
exit(0);
}
@ -400,7 +410,8 @@ main(argc, argv)
* Create the file n and copy from file descriptor f.
*/
static void
copy(f, n)
copy(pp, f, n)
const struct printer *pp;
int f;
char n[];
{
@ -424,8 +435,9 @@ copy(f, n)
if (nc >= BUFSIZ) {
nc -= BUFSIZ;
nr++;
if (MX > 0 && nr > MX) {
printf("%s: %s: copy file is too large\n", name, n);
if (pp->max_blocks > 0 && nr > pp->max_blocks) {
printf("%s: %s: copy file is too large\n",
name, n);
break;
}
}
@ -669,27 +681,23 @@ itoa(i)
* Perform lookup for printer name or abbreviation --
*/
static void
chkprinter(s)
chkprinter(s, pp)
char *s;
struct printer *pp;
{
int status;
if ((status = cgetent(&bp, printcapdb, s)) == -2)
fatal2("cannot open printer description file");
else if (status == -1)
fatal2("%s: unknown printer", s);
if (cgetstr(bp, "sd", &SD) == -1)
SD = _PATH_DEFSPOOL;
if (cgetstr(bp, "lo", &LO) == -1)
LO = DEFLOCK;
cgetstr(bp, "rg", &RG);
if (cgetnum(bp, "mx", &MX) < 0)
MX = DEFMX;
if (cgetnum(bp,"mc", &MC) < 0)
MC = DEFMAXCOPIES;
if (cgetnum(bp, "du", &DU) < 0)
DU = DEFUID;
SC = (cgetcap(bp, "sc", ':') != NULL);
init_printer(pp);
status = getprintcap(s, pp);
switch(status) {
case PCAPERR_OSERR:
case PCAPERR_TCLOOP:
errx(1, "%s: %s", s, pcaperr(status));
case PCAPERR_NOTFOUND:
errx(1, "%s: unknown printer", s);
case PCAPERR_TCOPEN:
warnx("%s: unresolved tc= reference(s)", s);
}
}
/*
@ -709,14 +717,14 @@ usage()
* Make the temp files.
*/
static void
mktemps()
mktemps(pp)
const struct printer *pp;
{
register int len, fd, n;
register char *cp;
char buf[BUFSIZ];
char *lmktemp();
(void) snprintf(buf, sizeof(buf), "%s/.seq", SD);
(void) snprintf(buf, sizeof(buf), "%s/.seq", pp->spool_dir);
seteuid(euid);
if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
printf("%s: cannot create %s\n", name, buf);
@ -735,11 +743,11 @@ mktemps()
n = n * 10 + (*cp++ - '0');
}
}
len = strlen(SD) + strlen(host) + 8;
tfname = lmktemp("tf", n, len);
cfname = lmktemp("cf", n, len);
dfname = lmktemp("df", n, len);
inchar = strlen(SD) + 3;
len = strlen(pp->spool_dir) + strlen(host) + 8;
tfname = lmktemp(pp, "tf", n, len);
cfname = lmktemp(pp, "cf", n, len);
dfname = lmktemp(pp, "df", n, len);
inchar = strlen(pp->spool_dir) + 3;
n = (n + 1) % 1000;
(void) lseek(fd, (off_t)0, 0);
snprintf(buf, sizeof(buf), "%03d\n", n);
@ -751,42 +759,15 @@ mktemps()
* Make a temp file name.
*/
static char *
lmktemp(id, num, len)
lmktemp(pp, id, num, len)
const struct printer *pp;
char *id;
int num, len;
{
register char *s;
if ((s = malloc(len)) == NULL)
fatal2("out of memory");
(void) snprintf(s, len, "%s/%sA%03d%s", SD, id, num, host);
errx(1, "out of memory");
(void) snprintf(s, len, "%s/%sA%03d%s", pp->spool_dir, id, num, host);
return(s);
}
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
static void
#ifdef __STDC__
fatal2(const char *msg, ...)
#else
fatal2(msg, va_alist)
char *msg;
va_dcl
#endif
{
va_list ap;
#ifdef __STDC__
va_start(ap, msg);
#else
va_start(ap);
#endif
printf("%s: ", name);
vprintf(msg, ap);
putchar('\n');
va_end(ap);
exit(1);
}

View file

@ -1,13 +1,15 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= lprm
CFLAGS+=-I${.CURDIR}/../common_source
SRCS= lprm.c rmjob.c startdaemon.c common.c
CFLAGS+=-I${.CURDIR}/../common_source -Wall -Werror
SRCS= lprm.c
BINOWN= root
BINGRP= daemon
BINMODE=6555
BINDIR= /usr/bin
MAN1= lprm.1
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include <bsd.prog.mk>

View file

@ -43,7 +43,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)lprm.c 8.1 (Berkeley) 6/6/93";
#endif
static const char rcsid[] =
"$Id$";
"$Id: lprm.c,v 1.3 1997/09/24 06:48:17 charnier Exp $";
#endif /* not lint */
/*
@ -89,21 +89,33 @@ main(argc, argv)
int argc;
char *argv[];
{
register char *arg;
char *arg, *printer;
struct passwd *p;
static char root[] = "root";
printer = NULL;
uid = getuid();
euid = geteuid();
seteuid(uid); /* be safe */
name = argv[0];
gethostname(host, sizeof(host));
openlog("lpd", 0, LOG_LPR);
if ((p = getpwuid(getuid())) == NULL)
fatal("Who are you?");
if (strlen(p->pw_name) >= sizeof(luser))
fatal("Your name is too long");
strcpy(luser, p->pw_name);
person = luser;
/*
* Bogus code later checks for string equality between
* `person' and "root", so if we are root, better make sure
* that code will succeed.
*/
if (getuid() == 0) {
person = root;
} else if ((person = getlogin()) == NULL) {
if ((p = getpwuid(getuid())) == NULL)
fatal(0, "Who are you?");
if (strlen(p->pw_name) >= sizeof(luser))
fatal(0, "Your name is too long");
strcpy(luser, p->pw_name);
person = luser;
}
while (--argc) {
if ((arg = *++argv)[0] == '-')
switch (arg[1]) {
@ -128,11 +140,11 @@ main(argc, argv)
usage();
if (isdigit(arg[0])) {
if (requests >= MAXREQUESTS)
fatal("Too many requests");
fatal(0, "Too many requests");
requ[requests++] = atoi(arg);
} else {
if (users >= MAXUSERS)
fatal("Too many users");
fatal(0, "Too many users");
user[users++] = arg;
}
}
@ -140,7 +152,7 @@ main(argc, argv)
if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
printer = DEFLP;
rmjob();
rmjob(printer);
exit(0);
}

View file

@ -1,10 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $Id$
PROG= pac
CFLAGS+=-I${.CURDIR}/../common_source
MAN8= pac.8
SRCS= pac.c common.c
SRCS= pac.c
.PATH: ${.CURDIR}/../common_source
LDADD= -L${.OBJDIR}/../common_source -llpr
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -43,7 +43,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93";
#endif
static const char rcsid[] =
"$Id$";
"$Id: pac.c,v 1.7 1997/09/24 06:48:24 charnier Exp $";
#endif /* not lint */
/*
@ -110,9 +110,10 @@ main(argc, argv)
int argc;
char **argv;
{
register FILE *acct;
register char *cp;
FILE *acct;
char *cp, *printer;
printer = NULL;
euid = geteuid(); /* these aren't used in pac(1) */
uid = getuid();
while (--argc) {
@ -433,21 +434,22 @@ chkprinter(s)
register char *s;
{
int stat;
struct printer myprinter, *pp = &myprinter;
if ((stat = cgetent(&bp, printcapdb, s)) == -2) {
printf("pac: can't open printer description file\n");
init_printer(&myprinter);
stat = getprintcap(s, pp);
switch(stat) {
case PCAPERR_OSERR:
printf("pac: getprintcap: %s\n", pcaperr(stat));
exit(3);
} else if (stat == -1)
return(0);
else if (stat == -3)
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp, "af", &acctfile) == -1) {
printf("accounting not enabled for printer %s\n", printer);
exit(2);
case PCAPERR_NOTFOUND:
return 0;
case PCAPERR_TCLOOP:
fatal(pp, "%s", pcaperr(stat));
}
if (!pflag && (cgetnum(bp, "pc", &price100) == 0))
price = price100/10000.0;
acctfile = pp->acct_file;
if (!pflag && pp->price100)
price = pp->price100/10000.0;
sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
if (sumfile == NULL)
errx(1, "calloc failed");

View file

@ -30,7 +30,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
* From: @(#)extern.h 8.1 (Berkeley) 6/6/93
* $Id$
*/
#include <sys/cdefs.h>
@ -38,5 +39,10 @@
extern char scnkey[][HEIGHT]; /* in lpdchar.c */
extern char fromb[];
void printjob __P((void));
void recvjob __P((void));
struct printer;
__BEGIN_DECLS
void printjob __P((struct printer *pp));
void startprinting __P((const char *printer));
void recvjob __P((const char *printer));
__END_DECLS

View file

@ -32,7 +32,11 @@
*/
#ifndef lint
/*
static char sccsid[] = "@(#)lpdchar.c 8.1 (Berkeley) 6/6/93";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
/*

View file

@ -29,12 +29,14 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#ifndef lint
/*
static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
*/
static const char rcsid[] =
"$Id$";
#endif /* not lint */
#include <stddef.h>

File diff suppressed because it is too large Load diff