/* $OpenBSD: lp_rmjob.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */ /* * Copyright (c) 2017 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include "lp.h" #include "log.h" static int docheck(struct lp_printer *, const char *, struct lp_jobfilter *, const char *, int, int); static void doremove(int, struct lp_printer *, const char *); int lp_rmjob(int ofd, struct lp_printer *lp, const char *agent, struct lp_jobfilter *jf) { struct lp_queue q; char currjob[PATH_MAX]; pid_t currpid; int active, i, killed = 0; if ((lp_readqueue(lp, &q)) == -1) { log_warnx("cannot read queue"); return 0; } if (q.count == 0) { lp_clearqueue(&q); return 0; } /* * Find the current task being printed, and kill the printer process * if the file is to be removed. */ if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1) log_warnx("cannot get current task"); if (currjob[0] && docheck(lp, agent, jf, currjob, 1, 0) == 1) { if (kill(currpid, SIGINT) == -1) log_warn("lpr: cannot kill printer process %d", (int)currpid); else killed = 1; } for(i = 0; i < q.count; i++) { active = !strcmp(q.cfname[i], currjob); switch (docheck(lp, agent, jf, q.cfname[i], active, 0)) { case 0: break; case 1: doremove(ofd, lp, q.cfname[i]); break; case 2: if (lp->lp_type == PRN_LPR) dprintf(ofd, "%s: ", lpd_hostname); dprintf(ofd, "%s: Permission denied\n", q.cfname[i]); break; } } lp_clearqueue(&q); return killed; } /* * Check if a file must be removed. * * Return: * 0: no * 1: yes * 2: yes but user has no right to do so */ static int docheck(struct lp_printer *lp, const char *agent, struct lp_jobfilter *jf, const char *cfname, int current, int local) { FILE *fp; ssize_t len; size_t linesz = 0; char *line = NULL, *person = NULL; int i, own = 0; /* The "-all" agent means remove all jobs from the client host. */ if (!strcmp(agent, "-all") && !strcmp(LP_JOBHOST(cfname), jf->hostfrom)) return 1; /* * Consider the root user owns local files, and files sent from * the same machine. */ if (!strcmp(agent, "root")) own = local || !strcmp(LP_JOBHOST(cfname), jf->hostfrom); /* Check if the task person matches the agent. */ fp = lp_fopen(lp, cfname); if (fp == NULL) { log_warn("cannot open %s", cfname); return 0; } while ((len = getline(&line, &linesz, fp)) != -1) { if (line[len-1] == '\n') line[len - 1] = '\0'; if (line[0] == 'P') { person = line + 1; if (!strcmp(person, agent) && !strcmp(LP_JOBHOST(cfname), jf->hostfrom)) own = 1; break; } } fclose(fp); if (person == NULL) { free(line); return 0; } /* Remove the current task if the request list is empty. */ if (current && jf->nuser == 0 && jf->njob == 0) goto remove; /* Check for matching jobnum. */ for (i = 0; i < jf->njob; i++) if (jf->jobs[i] == LP_JOBNUM(cfname)) goto remove; /* Check if person is in user list. */ for (i = 0; i < jf->nuser; i++) if (!strcmp(jf->users[i], person)) goto remove; free(line); return 0; remove: free(line); return own ? 1 : 2; } static void doremove(int ofd, struct lp_printer *lp, const char *cfname) { FILE *fp; ssize_t len; size_t linesz = 0; char *line = NULL; fp = lp_fopen(lp, cfname); if (fp == NULL) { log_warn("cannot open %s", cfname); return; } if (lp->lp_type == PRN_LPR) dprintf(ofd, "%s: ", lpd_hostname); /* First, remove the control file. */ if (lp_unlink(lp, cfname) == -1) { log_warn("cannot unlink %s", cfname); dprintf(ofd, "cannot dequeue %s\n", cfname); } else { log_info("removed job %s", cfname); dprintf(ofd, "%s dequeued\n", cfname); } /* Then unlink all data files. */ while ((len = getline(&line, &linesz, fp)) != -1) { if (line[len-1] == '\n') line[len - 1] = '\0'; if (line[0] != 'U') continue; if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) continue; if (lp->lp_type == PRN_LPR) dprintf(ofd, "%s: ", lpd_hostname); if (lp_unlink(lp, line + 1) == -1) { log_warn("cannot unlink %s", line + 1); dprintf(ofd, "cannot dequeue %s\n", line + 1); } else dprintf(ofd, "%s dequeued\n", line + 1); } fclose(fp); }