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