Fix so all parts of lpd, lpc, lpq, and lprm will use the same algorithm

for calculating the job number for a job based on the control-file name.
We might receive cf-files named by other implementations of lpr, where
the job number shown by lpq would not match the job number that other
commands expected for the same name.

This also uses a newer algorithm for determining a job number, to avoid
problems caused when a control-file is named using an IP address, instead
of the hostname.

This also moved the declaration if isowner() from lp.h to rmjob.c.  When I
went to change the parameters, I noticed that rmjob.c was the only source
file which uses it.

MFC after:	2 weeks
This commit is contained in:
Garance A Drosehn 2004-12-31 00:36:28 +00:00
parent fff3e23824
commit c547dbe854
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=139464
5 changed files with 79 additions and 37 deletions

View File

@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@ -72,6 +73,13 @@ extern uid_t uid, euid;
static int compar(const void *_p1, const void *_p2);
/*
* isdigit() takes a parameter of 'int', but expect values in the range
* of unsigned char. Define a wrapper which takes a value of type 'char',
* whether signed or unsigned, and ensure it ends up in the right range.
*/
#define isdigitch(Anychar) isdigit((u_char)(Anychar))
/*
* Getline reads a line from the control file cfp, removes tabs, converts
* new-line to null and leaves it in line.
@ -207,6 +215,53 @@ compar(const void *p1, const void *p2)
return (strcmp(qe1->job_cfname, qe2->job_cfname));
}
/*
* A simple routine to determine the job number for a print job based on
* the name of its control file. The algorithm used here may look odd, but
* the main issue is that all parts of `lpd', `lpc', `lpq' & `lprm' must be
* using the same algorithm, whatever that algorithm may be. If the caller
* provides a non-null value for ''hostpp', then this returns a pointer to
* the start of the hostname (or IP address?) as found in the filename.
*
* Algorithm: The standard `cf' file has the job number start in position 4,
* but some implementations have that as an extra file-sequence letter, and
* start the job number in position 5. The job number is usually three bytes,
* but may be as many as five. Confusing matters still more, some Windows
* print servers will append an IP address to the job number, instead of
* the expected hostname. So, if the job number ends with a '.', then
* assume the correct jobnum value is the first three digits.
*/
int
calc_jobnum(const char *cfname, const char **hostpp)
{
int jnum;
const char *cp, *numstr, *hoststr;
numstr = cfname + 3;
if (!isdigitch(*numstr))
numstr++;
jnum = 0;
for (cp = numstr; (cp < numstr + 5) && isdigitch(*cp); cp++)
jnum = jnum * 10 + (*cp - '0');
hoststr = cp;
/*
* If the filename was built with an IP number instead of a hostname,
* then recalculate using only the first three digits found.
*/
while(isdigitch(*cp))
cp++;
if (*cp == '.') {
jnum = 0;
for (cp = numstr; (cp < numstr + 3) && isdigitch(*cp); cp++)
jnum = jnum * 10 + (*cp - '0');
hoststr = cp;
}
if (hostpp != NULL)
*hostpp = hoststr;
return (jnum);
}
/* sleep n milliseconds */
void
delay(int millisec)

View File

@ -286,7 +286,7 @@ header(void)
void
inform(const struct printer *pp, char *cf)
{
register int copycnt;
int copycnt, jnum;
char savedname[MAXPATHLEN+1];
FILE *cfp;
@ -318,6 +318,7 @@ inform(const struct printer *pp, char *cf)
copycnt = 0;
file[0] = '\0';
savedname[0] = '\0';
jnum = calc_jobnum(cf, NULL);
while (getline(cfp)) {
switch (line[0]) {
case 'P': /* Was this file specified in the user's list? */
@ -335,7 +336,7 @@ inform(const struct printer *pp, char *cf)
col = 0;
prank(rank);
blankfill(OWNCOL);
printf("%-10s %-3d ", line+1, atoi(cf+3));
printf("%-10s %-3d ", line+1, jnum);
col += 16;
first = 1;
}
@ -383,8 +384,9 @@ inform(const struct printer *pp, char *cf)
int
inlist(char *uname, char *cfile)
{
register int *r, n;
register char **u, *cp;
int *r, jnum;
char **u;
const char *cfhost;
if (users == 0 && requests == 0)
return(1);
@ -397,10 +399,9 @@ inlist(char *uname, char *cfile)
/*
* Check the request list
*/
for (n = 0, cp = cfile+3; isdigit(*cp); )
n = n * 10 + (*cp++ - '0');
jnum = calc_jobnum(cfile, &cfhost);
for (r = requ; r < &requ[requests]; r++)
if (*r == n && !strcmp(cp, from_host))
if (*r == jnum && !strcmp(cfhost, from_host))
return(1);
return(0);
}

View File

@ -259,6 +259,7 @@ __BEGIN_DECLS
struct dirent;
void blankfill(int _tocol);
int calc_jobnum(const char *_cfname, const char **_hostpp);
char *checkremote(struct printer *_pp);
int chk(char *_file);
void closeallfds(int _start);
@ -280,7 +281,6 @@ void init_printer(struct printer *_pp);
void init_request(struct request *_rp);
int inlist(char *_uname, char *_cfile);
int iscf(struct dirent *_d);
int isowner(char *_owner, char *_file);
void ldump(const char *_nfile, const char *_datafile, int _copies);
void lastprinter(void);
int lockchk(struct printer *_pp, char *_slockf);

View File

@ -401,7 +401,7 @@ static int
match_jobspec(struct jobqueue *jq, struct jobspec *jspec)
{
struct cjobinfo *cfinf;
char *cp, *cf_numstr, *cf_hoststr;
const char *cf_hoststr;
int jnum, match;
#if DEBUG_SCANJS
@ -418,22 +418,7 @@ match_jobspec(struct jobqueue *jq, struct jobspec *jspec)
if (jq->job_matched)
return (0);
/*
* The standard `cf' file has the job number start in position 4,
* but some implementations have that as an extra file-sequence
* letter, and start the job number in position 5. The job
* number is usually three bytes, but may be as many as five.
*
* XXX - All this nonsense should really be handled in a single
* place, like getq()...
*/
cf_numstr = jq->job_cfname + 3;
if (!isdigitch(*cf_numstr))
cf_numstr++;
jnum = 0;
for (cp = cf_numstr; (cp < cf_numstr + 5) && isdigitch(*cp); cp++)
jnum = jnum * 10 + (*cp - '0');
cf_hoststr = cp;
jnum = calc_jobnum(jq->job_cfname, &cf_hoststr);
cfinf = NULL;
match = 0; /* assume the job will not match */
jspec->matcheduser = NULL;

View File

@ -76,6 +76,7 @@ extern uid_t uid, euid; /* real and effective user id's */
static void alarmhandler(int _signo);
static void do_unlink(char *_file);
static int isowner(char *_owner, char *_file, const char *_cfhost);
void
rmjob(const char *printer)
@ -233,8 +234,9 @@ do_unlink(char *file)
int
chk(char *file)
{
register int *r, n;
register char **u, *cp;
int *r, jnum;
char **u;
const char *cfhost;
FILE *cfp;
/*
@ -243,7 +245,8 @@ chk(char *file)
if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
return(0);
if (all && (from_host == local_host || !strcmp(from_host, file+6)))
jnum = calc_jobnum(file, &cfhost);
if (all && (from_host == local_host || !strcmp(from_host, cfhost)))
return(1);
/*
@ -262,20 +265,18 @@ chk(char *file)
return(0);
if (users == 0 && requests == 0)
return(!strcmp(file, current) && isowner(line+1, file));
return(!strcmp(file, current) && isowner(line+1, file, cfhost));
/*
* Check the request list
*/
for (n = 0, cp = file+3; isdigit(*cp); )
n = n * 10 + (*cp++ - '0');
for (r = requ; r < &requ[requests]; r++)
if (*r == n && isowner(line+1, file))
if (*r == jnum && isowner(line+1, file, cfhost))
return(1);
/*
* Check to see if it's in the user list
*/
for (u = user; u < &user[users]; u++)
if (!strcmp(*u, line+1) && isowner(line+1, file))
if (!strcmp(*u, line+1) && isowner(line+1, file, cfhost))
return(1);
return(0);
}
@ -286,13 +287,13 @@ chk(char *file)
* files sent from the remote machine to be removed.
* Normal users can only remove the file from where it was sent.
*/
int
isowner(char *owner, char *file)
static int
isowner(char *owner, char *file, const char *cfhost)
{
if (!strcmp(person, root) && (from_host == local_host ||
!strcmp(from_host, file+6)))
!strcmp(from_host, cfhost)))
return (1);
if (!strcmp(person, owner) && !strcmp(from_host, file+6))
if (!strcmp(person, owner) && !strcmp(from_host, cfhost))
return (1);
if (from_host != local_host)
printf("%s: ", local_host);