1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 40 #include <signal.h> 41 #include <errno.h> 42 #include <dirent.h> 43 #include <unistd.h> 44 #include <stdlib.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <ctype.h> 48 #include "lp.h" 49 #include "lp.local.h" 50 #include "pathnames.h" 51 52 /* 53 * rmjob - remove the specified jobs from the queue. 54 */ 55 56 /* 57 * Stuff for handling lprm specifications 58 */ 59 static char root[] = "root"; 60 static int all = 0; /* eliminate all files (root only) */ 61 static int cur_daemon; /* daemon's pid */ 62 static char current[40]; /* active control file name */ 63 64 void 65 rmjob() 66 { 67 register int i, nitems; 68 int assasinated = 0; 69 struct dirent **files; 70 char *cp; 71 72 if ((i = cgetent(&bp, printcapdb, printer)) == -2) 73 fatal("can't open printer description file"); 74 else if (i == -1) 75 fatal("unknown printer"); 76 else if (i == -3) 77 fatal("potential reference loop detected in printcap file"); 78 if (cgetstr(bp, "lp", &LP) < 0) 79 LP = _PATH_DEFDEVLP; 80 if (cgetstr(bp, "rp", &RP) < 0) 81 RP = DEFLP; 82 if (cgetstr(bp, "sd", &SD) < 0) 83 SD = _PATH_DEFSPOOL; 84 if (cgetstr(bp,"lo", &LO) < 0) 85 LO = DEFLOCK; 86 cgetstr(bp, "rm", &RM); 87 if (cp = checkremote()) 88 printf("Warning: %s\n", cp); 89 90 /* 91 * If the format was `lprm -' and the user isn't the super-user, 92 * then fake things to look like he said `lprm user'. 93 */ 94 if (users < 0) { 95 if (getuid() == 0) 96 all = 1; /* all files in local queue */ 97 else { 98 user[0] = person; 99 users = 1; 100 } 101 } 102 if (!strcmp(person, "-all")) { 103 if (from == host) 104 fatal("The login name \"-all\" is reserved"); 105 all = 1; /* all those from 'from' */ 106 person = root; 107 } 108 109 if (chdir(SD) < 0) 110 fatal("cannot chdir to spool directory"); 111 if ((nitems = scandir(".", &files, iscf, NULL)) < 0) 112 fatal("cannot access spool directory"); 113 114 if (nitems) { 115 /* 116 * Check for an active printer daemon (in which case we 117 * kill it if it is reading our file) then remove stuff 118 * (after which we have to restart the daemon). 119 */ 120 if (lockchk(LO) && chk(current)) { 121 assasinated = kill(cur_daemon, SIGINT) == 0; 122 if (!assasinated) 123 fatal("cannot kill printer daemon"); 124 } 125 /* 126 * process the files 127 */ 128 for (i = 0; i < nitems; i++) 129 process(files[i]->d_name); 130 } 131 rmremote(); 132 /* 133 * Restart the printer daemon if it was killed 134 */ 135 if (assasinated && !startdaemon(printer)) 136 fatal("cannot restart printer daemon\n"); 137 exit(0); 138 } 139 140 /* 141 * Process a lock file: collect the pid of the active 142 * daemon and the file name of the active spool entry. 143 * Return boolean indicating existence of a lock file. 144 */ 145 int 146 lockchk(s) 147 char *s; 148 { 149 register FILE *fp; 150 register int i, n; 151 152 if ((fp = fopen(s, "r")) == NULL) 153 if (errno == EACCES) 154 fatal("can't access lock file"); 155 else 156 return(0); 157 if (!getline(fp)) { 158 (void) fclose(fp); 159 return(0); /* no daemon present */ 160 } 161 cur_daemon = atoi(line); 162 if (kill(cur_daemon, 0) < 0) { 163 (void) fclose(fp); 164 return(0); /* no daemon present */ 165 } 166 for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) { 167 if (i > 5) { 168 n = 1; 169 break; 170 } 171 sleep(i); 172 } 173 current[n-1] = '\0'; 174 (void) fclose(fp); 175 return(1); 176 } 177 178 /* 179 * Process a control file. 180 */ 181 void 182 process(file) 183 char *file; 184 { 185 FILE *cfp; 186 187 if (!chk(file)) 188 return; 189 if ((cfp = fopen(file, "r")) == NULL) 190 fatal("cannot open %s", file); 191 while (getline(cfp)) { 192 switch (line[0]) { 193 case 'U': /* unlink associated files */ 194 if (from != host) 195 printf("%s: ", host); 196 printf(unlink(line+1) ? "cannot dequeue %s\n" : 197 "%s dequeued\n", line+1); 198 } 199 } 200 (void) fclose(cfp); 201 if (from != host) 202 printf("%s: ", host); 203 printf(unlink(file) ? "cannot dequeue %s\n" : "%s dequeued\n", file); 204 } 205 206 /* 207 * Do the dirty work in checking 208 */ 209 int 210 chk(file) 211 char *file; 212 { 213 register int *r, n; 214 register char **u, *cp; 215 FILE *cfp; 216 217 /* 218 * Check for valid cf file name (mostly checking current). 219 */ 220 if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f') 221 return(0); 222 223 if (all && (from == host || !strcmp(from, file+6))) 224 return(1); 225 226 /* 227 * get the owner's name from the control file. 228 */ 229 if ((cfp = fopen(file, "r")) == NULL) 230 return(0); 231 while (getline(cfp)) { 232 if (line[0] == 'P') 233 break; 234 } 235 (void) fclose(cfp); 236 if (line[0] != 'P') 237 return(0); 238 239 if (users == 0 && requests == 0) 240 return(!strcmp(file, current) && isowner(line+1, file)); 241 /* 242 * Check the request list 243 */ 244 for (n = 0, cp = file+3; isdigit(*cp); ) 245 n = n * 10 + (*cp++ - '0'); 246 for (r = requ; r < &requ[requests]; r++) 247 if (*r == n && isowner(line+1, file)) 248 return(1); 249 /* 250 * Check to see if it's in the user list 251 */ 252 for (u = user; u < &user[users]; u++) 253 if (!strcmp(*u, line+1) && isowner(line+1, file)) 254 return(1); 255 return(0); 256 } 257 258 /* 259 * If root is removing a file on the local machine, allow it. 260 * If root is removing a file from a remote machine, only allow 261 * files sent from the remote machine to be removed. 262 * Normal users can only remove the file from where it was sent. 263 */ 264 int 265 isowner(owner, file) 266 char *owner, *file; 267 { 268 if (!strcmp(person, root) && (from == host || !strcmp(from, file+6))) 269 return(1); 270 if (!strcmp(person, owner) && !strcmp(from, file+6)) 271 return(1); 272 if (from != host) 273 printf("%s: ", host); 274 printf("%s: Permission denied\n", file); 275 return(0); 276 } 277 278 /* 279 * Check to see if we are sending files to a remote machine. If we are, 280 * then try removing files on the remote machine. 281 */ 282 void 283 rmremote() 284 { 285 register char *cp; 286 register int i, rem; 287 char buf[BUFSIZ]; 288 289 if (!remote) 290 return; /* not sending to a remote machine */ 291 292 /* 293 * Flush stdout so the user can see what has been deleted 294 * while we wait (possibly) for the connection. 295 */ 296 fflush(stdout); 297 298 (void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person); 299 cp = buf; 300 for (i = 0; i < users; i++) { 301 cp += strlen(cp); 302 *cp++ = ' '; 303 strcpy(cp, user[i]); 304 } 305 for (i = 0; i < requests; i++) { 306 cp += strlen(cp); 307 (void) sprintf(cp, " %d", requ[i]); 308 } 309 strcat(cp, "\n"); 310 rem = getport(RM, 0); 311 if (rem < 0) { 312 if (from != host) 313 printf("%s: ", host); 314 printf("connection to %s is down\n", RM); 315 } else { 316 i = strlen(buf); 317 if (write(rem, buf, i) != i) 318 fatal("Lost connection"); 319 while ((i = read(rem, buf, sizeof(buf))) > 0) 320 (void) fwrite(buf, 1, i, stdout); 321 (void) close(rem); 322 } 323 } 324 325 /* 326 * Return 1 if the filename begins with 'cf' 327 */ 328 int 329 iscf(d) 330 struct dirent *d; 331 { 332 return(d->d_name[0] == 'c' && d->d_name[1] == 'f'); 333 } 334