1 /* $OpenBSD: lp_rmjob.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <limits.h> 20 #include <signal.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #include "lp.h" 26 27 #include "log.h" 28 29 static int docheck(struct lp_printer *, const char *, struct lp_jobfilter *, 30 const char *, int, int); 31 static void doremove(int, struct lp_printer *, const char *); 32 33 int 34 lp_rmjob(int ofd, struct lp_printer *lp, const char *agent, 35 struct lp_jobfilter *jf) 36 { 37 struct lp_queue q; 38 char currjob[PATH_MAX]; 39 pid_t currpid; 40 int active, i, killed = 0; 41 42 if ((lp_readqueue(lp, &q)) == -1) { 43 log_warnx("cannot read queue"); 44 return 0; 45 } 46 47 if (q.count == 0) { 48 lp_clearqueue(&q); 49 return 0; 50 } 51 52 /* 53 * Find the current task being printed, and kill the printer process 54 * if the file is to be removed. 55 */ 56 if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1) 57 log_warnx("cannot get current task"); 58 59 if (currjob[0] && docheck(lp, agent, jf, currjob, 1, 0) == 1) { 60 if (kill(currpid, SIGINT) == -1) 61 log_warn("lpr: cannot kill printer process %d", 62 (int)currpid); 63 else 64 killed = 1; 65 } 66 67 for(i = 0; i < q.count; i++) { 68 active = !strcmp(q.cfname[i], currjob); 69 switch (docheck(lp, agent, jf, q.cfname[i], active, 0)) { 70 case 0: 71 break; 72 case 1: 73 doremove(ofd, lp, q.cfname[i]); 74 break; 75 case 2: 76 if (lp->lp_type == PRN_LPR) 77 dprintf(ofd, "%s: ", lpd_hostname); 78 dprintf(ofd, "%s: Permission denied\n", q.cfname[i]); 79 break; 80 } 81 } 82 83 lp_clearqueue(&q); 84 85 return killed; 86 } 87 88 /* 89 * Check if a file must be removed. 90 * 91 * Return: 92 * 0: no 93 * 1: yes 94 * 2: yes but user has no right to do so 95 */ 96 static int 97 docheck(struct lp_printer *lp, const char *agent, struct lp_jobfilter *jf, 98 const char *cfname, int current, int local) 99 { 100 FILE *fp; 101 ssize_t len; 102 size_t linesz = 0; 103 char *line = NULL, *person = NULL; 104 int i, own = 0; 105 106 /* The "-all" agent means remove all jobs from the client host. */ 107 if (!strcmp(agent, "-all") && !strcmp(LP_JOBHOST(cfname), jf->hostfrom)) 108 return 1; 109 110 /* 111 * Consider the root user owns local files, and files sent from 112 * the same machine. 113 */ 114 if (!strcmp(agent, "root")) 115 own = local || !strcmp(LP_JOBHOST(cfname), jf->hostfrom); 116 117 /* Check if the task person matches the agent. */ 118 fp = lp_fopen(lp, cfname); 119 if (fp == NULL) { 120 log_warn("cannot open %s", cfname); 121 return 0; 122 } 123 while ((len = getline(&line, &linesz, fp)) != -1) { 124 if (line[len-1] == '\n') 125 line[len - 1] = '\0'; 126 if (line[0] == 'P') { 127 person = line + 1; 128 if (!strcmp(person, agent) && 129 !strcmp(LP_JOBHOST(cfname), jf->hostfrom)) 130 own = 1; 131 break; 132 } 133 } 134 fclose(fp); 135 136 if (person == NULL) { 137 free(line); 138 return 0; 139 } 140 141 /* Remove the current task if the request list is empty. */ 142 if (current && jf->nuser == 0 && jf->njob == 0) 143 goto remove; 144 145 /* Check for matching jobnum. */ 146 for (i = 0; i < jf->njob; i++) 147 if (jf->jobs[i] == LP_JOBNUM(cfname)) 148 goto remove; 149 150 /* Check if person is in user list. */ 151 for (i = 0; i < jf->nuser; i++) 152 if (!strcmp(jf->users[i], person)) 153 goto remove; 154 155 free(line); 156 return 0; 157 158 remove: 159 free(line); 160 return own ? 1 : 2; 161 } 162 163 static void 164 doremove(int ofd, struct lp_printer *lp, const char *cfname) 165 { 166 FILE *fp; 167 ssize_t len; 168 size_t linesz = 0; 169 char *line = NULL; 170 171 fp = lp_fopen(lp, cfname); 172 if (fp == NULL) { 173 log_warn("cannot open %s", cfname); 174 return; 175 } 176 177 if (lp->lp_type == PRN_LPR) 178 dprintf(ofd, "%s: ", lpd_hostname); 179 180 /* First, remove the control file. */ 181 if (lp_unlink(lp, cfname) == -1) { 182 log_warn("cannot unlink %s", cfname); 183 dprintf(ofd, "cannot dequeue %s\n", cfname); 184 } 185 else { 186 log_info("removed job %s", cfname); 187 dprintf(ofd, "%s dequeued\n", cfname); 188 } 189 190 /* Then unlink all data files. */ 191 while ((len = getline(&line, &linesz, fp)) != -1) { 192 if (line[len-1] == '\n') 193 line[len - 1] = '\0'; 194 if (line[0] != 'U') 195 continue; 196 if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) 197 continue; 198 if (lp->lp_type == PRN_LPR) 199 dprintf(ofd, "%s: ", lpd_hostname); 200 if (lp_unlink(lp, line + 1) == -1) { 201 log_warn("cannot unlink %s", line + 1); 202 dprintf(ofd, "cannot dequeue %s\n", line + 1); 203 } 204 else 205 dprintf(ofd, "%s dequeued\n", line + 1); 206 } 207 208 fclose(fp); 209 } 210