#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
extern char *user[];
extern int users;
extern int requ[];
extern int requests;
extern char *person;
static char root[] = "root";
static int all = 0;
static int cur_daemon;
static char current[NAME_MAX];
static void alarmer(int);
static int chk(char *);
static void do_unlink(char *);
static int iscf(const struct dirent *);
static int isowner(char *, char *);
static int lockchk(char *);
static void process(char *);
static void rmremote(void);
void
rmjob(void)
{
int i, nitems;
int assassinated = 0;
struct dirent **files;
char *cp;
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, DEFLP, &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;
cgetstr(bp, "rm", &RM);
if ((cp = checkremote()) != NULL)
printf("Warning: %s\n", cp);
if (users < 0) {
if (getuid() == 0)
all = 1;
else {
user[0] = person;
users = 1;
}
}
if (!strcmp(person, "-all")) {
if (from == host)
fatal("The login name \"-all\" is reserved");
all = 1;
person = root;
}
PRIV_START;
if (chdir(SD) < 0)
fatal("cannot chdir to spool directory");
if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
fatal("cannot access spool directory");
PRIV_END;
if (nitems) {
if (lockchk(LO) && chk(current)) {
PRIV_START;
assassinated = kill(cur_daemon, SIGINT) == 0;
PRIV_END;
if (!assassinated)
fatal("cannot kill printer daemon");
}
for (i = 0; i < nitems; i++)
process(files[i]->d_name);
}
rmremote();
if (assassinated && !startdaemon(printer))
fatal("cannot restart printer daemon");
exit(0);
}
static int
lockchk(char *s)
{
FILE *fp = NULL;
int fd, i, n;
PRIV_START;
fd = safe_open(s, O_RDONLY|O_NOFOLLOW, 0);
PRIV_END;
if (fd < 0 || (fp = fdopen(fd, "r")) == NULL) {
if (fd >= 0)
close(fd);
if (errno == EACCES)
fatal("can't access lock file");
else
return(0);
}
if (!get_line(fp)) {
(void)fclose(fp);
return(0);
}
cur_daemon = atoi(line);
if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
(void)fclose(fp);
return(0);
}
for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
if (i > 5) {
n = 1;
break;
}
sleep(i);
}
current[n-1] = '\0';
(void)fclose(fp);
return(1);
}
static void
process(char *file)
{
FILE *cfp = NULL;
int fd;
if (!chk(file))
return;
PRIV_START;
fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0);
PRIV_END;
if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) {
if (fd >= 0)
close(fd);
fatal("cannot open %s", file);
}
while (get_line(cfp)) {
switch (line[0]) {
case 'U':
if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
break;
do_unlink(line+1);
}
}
(void)fclose(cfp);
do_unlink(file);
}
static void
do_unlink(char *file)
{
int ret;
if (from != host)
printf("%s: ", host);
PRIV_START;
ret = unlink(file);
PRIV_END;
printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
}
static int
chk(char *file)
{
int *r, n, fd;
char **u, *cp;
FILE *cfp = NULL;
if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
return(0);
if (all && (from == host || !strcmp(from, file+6)))
return(1);
PRIV_START;
fd = safe_open(file, O_RDONLY|O_NOFOLLOW, 0);
PRIV_END;
if (fd < 0 || (cfp = fdopen(fd, "r")) == NULL) {
if (fd >= 0)
close(fd);
return(0);
}
while (get_line(cfp)) {
if (line[0] == 'P')
break;
}
(void)fclose(cfp);
if (line[0] != 'P')
return(0);
if (users == 0 && requests == 0)
return(!strcmp(file, current) && isowner(line+1, file));
for (n = 0, cp = file+3; isdigit((unsigned char)*cp); )
n = n * 10 + (*cp++ - '0');
for (r = requ; r < &requ[requests]; r++)
if (*r == n && isowner(line+1, file))
return(1);
for (u = user; u < &user[users]; u++)
if (!strcmp(*u, line+1) && isowner(line+1, file))
return(1);
return(0);
}
static int
isowner(char *owner, char *file)
{
if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
return(1);
if (!strcmp(person, owner) && !strcmp(from, file+6))
return(1);
if (from != host)
printf("%s: ", host);
printf("%s: Permission denied\n", file);
return(0);
}
static void
rmremote(void)
{
char *cp;
int i, rem;
size_t n;
char buf[BUFSIZ];
if (!remote)
return;
fflush(stdout);
n = snprintf(buf, sizeof(buf), "\5%s %s ", RP, all ? "-all" : person);
if (n < 0 || n >= sizeof(buf))
goto bad;
cp = buf + n;
for (i = 0; i < users; i++) {
n = strlcpy(cp, user[i], sizeof(buf) - (cp - buf + 1));
if (n >= sizeof(buf) - (cp - buf + 1))
goto bad;
cp += n;
*cp++ = ' ';
}
*cp = '\0';
for (i = 0; i < requests; i++) {
n = snprintf(cp, sizeof(buf) - (cp - buf), "%d ", requ[i]);
if (n < 0 || n >= sizeof(buf) - (cp - buf))
goto bad;
cp += n;
}
cp[-1] = '\n';
rem = getport(RM, 0);
if (rem < 0) {
if (from != host)
printf("%s: ", host);
printf("connection to %s is down\n", RM);
} else {
struct sigaction osa, nsa;
memset(&nsa, 0, sizeof(nsa));
nsa.sa_handler = alarmer;
sigemptyset(&nsa.sa_mask);
nsa.sa_flags = 0;
(void)sigaction(SIGALRM, &nsa, &osa);
alarm(wait_time);
i = strlen(buf);
if (write(rem, buf, i) != i)
fatal("Lost connection");
while ((i = read(rem, buf, sizeof(buf))) > 0)
(void)fwrite(buf, 1, i, stdout);
alarm(0);
(void)sigaction(SIGALRM, &osa, NULL);
(void)close(rem);
}
return;
bad:
printf("remote buffer too large\n");
return;
}
static void
alarmer(int s)
{
}
static int
iscf(const struct dirent *d)
{
return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
}