From bf21e6b4e0e85ae08cb5d1f2335da248f52e2d26 Mon Sep 17 00:00:00 2001 From: wollman Date: Tue, 2 Dec 1997 20:46:22 +0000 Subject: 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... --- usr.sbin/lpr/common_source/Makefile | 19 ++ usr.sbin/lpr/common_source/common.c | 254 ++++++------------ usr.sbin/lpr/common_source/displayq.c | 119 +++++---- usr.sbin/lpr/common_source/lp.h | 216 +++++++++++----- usr.sbin/lpr/common_source/net.c | 260 +++++++++++++++++++ usr.sbin/lpr/common_source/pathnames.h | 1 + usr.sbin/lpr/common_source/printcap.c | 428 +++++++++++++++++++++++++++++++ usr.sbin/lpr/common_source/recvjob.c | 53 ++-- usr.sbin/lpr/common_source/request.c | 80 ++++++ usr.sbin/lpr/common_source/rmjob.c | 139 +++++----- usr.sbin/lpr/common_source/startdaemon.c | 35 +-- 11 files changed, 1210 insertions(+), 394 deletions(-) create mode 100644 usr.sbin/lpr/common_source/Makefile create mode 100644 usr.sbin/lpr/common_source/net.c create mode 100644 usr.sbin/lpr/common_source/printcap.c create mode 100644 usr.sbin/lpr/common_source/request.c (limited to 'usr.sbin/lpr/common_source') diff --git a/usr.sbin/lpr/common_source/Makefile b/usr.sbin/lpr/common_source/Makefile new file mode 100644 index 0000000..96151e7 --- /dev/null +++ b/usr.sbin/lpr/common_source/Makefile @@ -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 diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c index 7301e2b..8cfacab 100644 --- a/usr.sbin/lpr/common_source/common.c +++ b/usr.sbin/lpr/common_source/common.c @@ -37,151 +37,38 @@ */ #ifndef lint +/* static char sccsid[] = "@(#)common.c 8.5 (Berkeley) 4/28/95"; +*/ +static const char rcsid[] = + "$Id$"; #endif /* not lint */ #include #include #include -#include -#include -#include - #include -#include -#include -#include #include +#include #include +#include + #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. * Returns 0 at EOF or the number of characters read. @@ -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 #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); +} + diff --git a/usr.sbin/lpr/common_source/displayq.c b/usr.sbin/lpr/common_source/displayq.c index 01d91a6..3f0ad42 100644 --- a/usr.sbin/lpr/common_source/displayq.c +++ b/usr.sbin/lpr/common_source/displayq.c @@ -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 #include -#include -#include -#include +#include #include -#include +#include +#include +#include #include #include #include -#include +#define psignal foil_gcc_psignal +#define sys_siglist foil_gcc_siglist +#include +#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)) { diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h index 816e652..8b3cd5f 100644 --- a/usr.sbin/lpr/common_source/lp.h +++ b/usr.sbin/lpr/common_source/lp.h @@ -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 /* - * Global definitions for the line printer system. + * 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 }; -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) */ +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 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 __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 diff --git a/usr.sbin/lpr/common_source/net.c b/usr.sbin/lpr/common_source/net.c new file mode 100644 index 0000000..d5886f9 --- /dev/null +++ b/usr.sbin/lpr/common_source/net.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include + +#include /* required for lp.h, not used here */ +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/usr.sbin/lpr/common_source/pathnames.h b/usr.sbin/lpr/common_source/pathnames.h index 5c07cdb..78ccc7b 100644 --- a/usr.sbin/lpr/common_source/pathnames.h +++ b/usr.sbin/lpr/common_source/pathnames.h @@ -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" diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c new file mode 100644 index 0000000..8991f0d --- /dev/null +++ b/usr.sbin/lpr/common_source/printcap.c @@ -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 +#include +#include +#include +#include + +#include /* required for lp.h, but not used here */ +#include /* 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; +} + + diff --git a/usr.sbin/lpr/common_source/recvjob.c b/usr.sbin/lpr/common_source/recvjob.c index 0a10e49..6b1c8b0 100644 --- a/usr.sbin/lpr/common_source/recvjob.c +++ b/usr.sbin/lpr/common_source/recvjob.c @@ -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)); diff --git a/usr.sbin/lpr/common_source/request.c b/usr.sbin/lpr/common_source/request.c new file mode 100644 index 0000000..d3e3cdf --- /dev/null +++ b/usr.sbin/lpr/common_source/request.c @@ -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 +#include + +#include +#include + +#include /* needed for lp.h but not used here */ +#include /* ditto */ +#include /* 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); +} diff --git a/usr.sbin/lpr/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c index 256da3f..e2406b9 100644 --- a/usr.sbin/lpr/common_source/rmjob.c +++ b/usr.sbin/lpr/common_source/rmjob.c @@ -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 +#include -#include -#include +#include #include -#include -#include +#include +#include #include +#include #include -#include +#define psignal foil_gcc_psignal +#define sys_siglist foil_gcc_siglist +#include +#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 */ } diff --git a/usr.sbin/lpr/common_source/startdaemon.c b/usr.sbin/lpr/common_source/startdaemon.c index 7f990b4..931a7ef 100644 --- a/usr.sbin/lpr/common_source/startdaemon.c +++ b/usr.sbin/lpr/common_source/startdaemon.c @@ -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 #include +#include #include #include @@ -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); } -- cgit v1.1