rmjob.c revision 30407
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
3529780Scharnier#if 0
3615648Sjoergstatic char sccsid[] = "@(#)rmjob.c	8.2 (Berkeley) 4/28/95";
3729780Scharnier#endif
3829780Scharnierstatic const char rcsid[] =
3930407Sjoerg	"$Id: rmjob.c,v 1.9 1997/09/24 06:47:31 charnier Exp $";
401553Srgrimes#endif /* not lint */
411553Srgrimes
421553Srgrimes#include <sys/param.h>
431553Srgrimes
441553Srgrimes#include <signal.h>
451553Srgrimes#include <errno.h>
461553Srgrimes#include <dirent.h>
471553Srgrimes#include <unistd.h>
481553Srgrimes#include <stdlib.h>
491553Srgrimes#include <stdio.h>
501553Srgrimes#include <string.h>
511553Srgrimes#include <ctype.h>
521553Srgrimes#include "lp.h"
531553Srgrimes#include "lp.local.h"
541553Srgrimes#include "pathnames.h"
551553Srgrimes
561553Srgrimes/*
571553Srgrimes * rmjob - remove the specified jobs from the queue.
581553Srgrimes */
591553Srgrimes
601553Srgrimes/*
611553Srgrimes * Stuff for handling lprm specifications
621553Srgrimes */
631553Srgrimesstatic char	root[] = "root";
641553Srgrimesstatic int	all = 0;		/* eliminate all files (root only) */
651553Srgrimesstatic int	cur_daemon;		/* daemon's pid */
661553Srgrimesstatic char	current[40];		/* active control file name */
671553Srgrimes
6827618Simpextern uid_t	uid, euid;		/* real and effective user id's */
6927618Simp
7030407Sjoergstatic	void	alarmhandler __P((int));
7127618Simpstatic	void	do_unlink __P((char *));
7227618Simp
731553Srgrimesvoid
741553Srgrimesrmjob()
751553Srgrimes{
761553Srgrimes	register int i, nitems;
771553Srgrimes	int assasinated = 0;
781553Srgrimes	struct dirent **files;
791553Srgrimes	char *cp;
801553Srgrimes
811553Srgrimes	if ((i = cgetent(&bp, printcapdb, printer)) == -2)
821553Srgrimes		fatal("can't open printer description file");
831553Srgrimes	else if (i == -1)
841553Srgrimes		fatal("unknown printer");
851553Srgrimes	else if (i == -3)
861553Srgrimes		fatal("potential reference loop detected in printcap file");
871553Srgrimes	if (cgetstr(bp, "lp", &LP) < 0)
881553Srgrimes		LP = _PATH_DEFDEVLP;
891553Srgrimes	if (cgetstr(bp, "rp", &RP) < 0)
901553Srgrimes		RP = DEFLP;
911553Srgrimes	if (cgetstr(bp, "sd", &SD) < 0)
921553Srgrimes		SD = _PATH_DEFSPOOL;
931553Srgrimes	if (cgetstr(bp,"lo", &LO) < 0)
941553Srgrimes		LO = DEFLOCK;
9530407Sjoerg	if (cgetnum(bp, "ct", &CT) < 0)
9630407Sjoerg		CT = DEFTIMEOUT;
971553Srgrimes	cgetstr(bp, "rm", &RM);
9827748Simp	if ((cp = checkremote()))
991553Srgrimes		printf("Warning: %s\n", cp);
1001553Srgrimes
1011553Srgrimes	/*
1021553Srgrimes	 * If the format was `lprm -' and the user isn't the super-user,
1031553Srgrimes	 *  then fake things to look like he said `lprm user'.
1041553Srgrimes	 */
1051553Srgrimes	if (users < 0) {
1061553Srgrimes		if (getuid() == 0)
1071553Srgrimes			all = 1;	/* all files in local queue */
1081553Srgrimes		else {
1091553Srgrimes			user[0] = person;
1101553Srgrimes			users = 1;
1111553Srgrimes		}
1121553Srgrimes	}
1131553Srgrimes	if (!strcmp(person, "-all")) {
1141553Srgrimes		if (from == host)
1151553Srgrimes			fatal("The login name \"-all\" is reserved");
1161553Srgrimes		all = 1;	/* all those from 'from' */
1171553Srgrimes		person = root;
1181553Srgrimes	}
1191553Srgrimes
12027618Simp	seteuid(euid);
1211553Srgrimes	if (chdir(SD) < 0)
1221553Srgrimes		fatal("cannot chdir to spool directory");
1231553Srgrimes	if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
1241553Srgrimes		fatal("cannot access spool directory");
12527618Simp	seteuid(uid);
1261553Srgrimes
1271553Srgrimes	if (nitems) {
1281553Srgrimes		/*
1291553Srgrimes		 * Check for an active printer daemon (in which case we
1301553Srgrimes		 *  kill it if it is reading our file) then remove stuff
1311553Srgrimes		 *  (after which we have to restart the daemon).
1321553Srgrimes		 */
1331553Srgrimes		if (lockchk(LO) && chk(current)) {
13427618Simp			seteuid(euid);
1351553Srgrimes			assasinated = kill(cur_daemon, SIGINT) == 0;
13627618Simp			seteuid(uid);
1371553Srgrimes			if (!assasinated)
1381553Srgrimes				fatal("cannot kill printer daemon");
1391553Srgrimes		}
1401553Srgrimes		/*
1411553Srgrimes		 * process the files
1421553Srgrimes		 */
1431553Srgrimes		for (i = 0; i < nitems; i++)
1441553Srgrimes			process(files[i]->d_name);
1451553Srgrimes	}
1461553Srgrimes	rmremote();
1471553Srgrimes	/*
1481553Srgrimes	 * Restart the printer daemon if it was killed
1491553Srgrimes	 */
1501553Srgrimes	if (assasinated && !startdaemon(printer))
1511553Srgrimes		fatal("cannot restart printer daemon\n");
1521553Srgrimes	exit(0);
1531553Srgrimes}
1541553Srgrimes
1551553Srgrimes/*
1561553Srgrimes * Process a lock file: collect the pid of the active
1571553Srgrimes *  daemon and the file name of the active spool entry.
1581553Srgrimes * Return boolean indicating existence of a lock file.
1591553Srgrimes */
1601553Srgrimesint
1611553Srgrimeslockchk(s)
1621553Srgrimes	char *s;
1631553Srgrimes{
1641553Srgrimes	register FILE *fp;
1651553Srgrimes	register int i, n;
1661553Srgrimes
16727618Simp	seteuid(euid);
16827618Simp	if ((fp = fopen(s, "r")) == NULL) {
1691553Srgrimes		if (errno == EACCES)
1701553Srgrimes			fatal("can't access lock file");
1711553Srgrimes		else
1721553Srgrimes			return(0);
17327618Simp	}
17427618Simp	seteuid(uid);
1751553Srgrimes	if (!getline(fp)) {
1761553Srgrimes		(void) fclose(fp);
1771553Srgrimes		return(0);		/* no daemon present */
1781553Srgrimes	}
1791553Srgrimes	cur_daemon = atoi(line);
18027618Simp	if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
1811553Srgrimes		(void) fclose(fp);
1821553Srgrimes		return(0);		/* no daemon present */
1831553Srgrimes	}
1841553Srgrimes	for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
1851553Srgrimes		if (i > 5) {
1861553Srgrimes			n = 1;
1871553Srgrimes			break;
1881553Srgrimes		}
1891553Srgrimes		sleep(i);
1901553Srgrimes	}
1911553Srgrimes	current[n-1] = '\0';
1921553Srgrimes	(void) fclose(fp);
1931553Srgrimes	return(1);
1941553Srgrimes}
1951553Srgrimes
1961553Srgrimes/*
1971553Srgrimes * Process a control file.
1981553Srgrimes */
1991553Srgrimesvoid
2001553Srgrimesprocess(file)
2011553Srgrimes	char *file;
2021553Srgrimes{
2031553Srgrimes	FILE *cfp;
2041553Srgrimes
2051553Srgrimes	if (!chk(file))
2061553Srgrimes		return;
20727618Simp	seteuid(euid);
2081553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
2091553Srgrimes		fatal("cannot open %s", file);
21027618Simp	seteuid(uid);
2111553Srgrimes	while (getline(cfp)) {
2121553Srgrimes		switch (line[0]) {
2131553Srgrimes		case 'U':  /* unlink associated files */
21427509Simp			if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
21527509Simp				break;
2161553Srgrimes			if (from != host)
2171553Srgrimes				printf("%s: ", host);
21827618Simp			do_unlink(line+1);
2191553Srgrimes		}
2201553Srgrimes	}
2211553Srgrimes	(void) fclose(cfp);
22227618Simp	do_unlink(file);
22327618Simp}
22427618Simp
22527618Simpstatic void
22627618Simpdo_unlink(file)
22727618Simp	char *file;
22827618Simp{
22927618Simp	int	ret;
23027618Simp
2311553Srgrimes	if (from != host)
2321553Srgrimes		printf("%s: ", host);
23327618Simp	seteuid(euid);
23427618Simp	ret = unlink(file);
23527618Simp	seteuid(uid);
23627618Simp	printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
2371553Srgrimes}
2381553Srgrimes
2391553Srgrimes/*
2401553Srgrimes * Do the dirty work in checking
2411553Srgrimes */
2421553Srgrimesint
2431553Srgrimeschk(file)
2441553Srgrimes	char *file;
2451553Srgrimes{
2461553Srgrimes	register int *r, n;
2471553Srgrimes	register char **u, *cp;
2481553Srgrimes	FILE *cfp;
2491553Srgrimes
2501553Srgrimes	/*
2511553Srgrimes	 * Check for valid cf file name (mostly checking current).
2521553Srgrimes	 */
2531553Srgrimes	if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
2541553Srgrimes		return(0);
2551553Srgrimes
2561553Srgrimes	if (all && (from == host || !strcmp(from, file+6)))
2571553Srgrimes		return(1);
2581553Srgrimes
2591553Srgrimes	/*
2601553Srgrimes	 * get the owner's name from the control file.
2611553Srgrimes	 */
26227618Simp	seteuid(euid);
2631553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
2641553Srgrimes		return(0);
26527618Simp	seteuid(uid);
2661553Srgrimes	while (getline(cfp)) {
2671553Srgrimes		if (line[0] == 'P')
2681553Srgrimes			break;
2691553Srgrimes	}
2701553Srgrimes	(void) fclose(cfp);
2711553Srgrimes	if (line[0] != 'P')
2721553Srgrimes		return(0);
2731553Srgrimes
2741553Srgrimes	if (users == 0 && requests == 0)
2751553Srgrimes		return(!strcmp(file, current) && isowner(line+1, file));
2761553Srgrimes	/*
2771553Srgrimes	 * Check the request list
2781553Srgrimes	 */
2791553Srgrimes	for (n = 0, cp = file+3; isdigit(*cp); )
2801553Srgrimes		n = n * 10 + (*cp++ - '0');
2811553Srgrimes	for (r = requ; r < &requ[requests]; r++)
2821553Srgrimes		if (*r == n && isowner(line+1, file))
2831553Srgrimes			return(1);
2841553Srgrimes	/*
2851553Srgrimes	 * Check to see if it's in the user list
2861553Srgrimes	 */
2871553Srgrimes	for (u = user; u < &user[users]; u++)
2881553Srgrimes		if (!strcmp(*u, line+1) && isowner(line+1, file))
2891553Srgrimes			return(1);
2901553Srgrimes	return(0);
2911553Srgrimes}
2921553Srgrimes
2931553Srgrimes/*
2941553Srgrimes * If root is removing a file on the local machine, allow it.
2951553Srgrimes * If root is removing a file from a remote machine, only allow
2961553Srgrimes * files sent from the remote machine to be removed.
2971553Srgrimes * Normal users can only remove the file from where it was sent.
2981553Srgrimes */
2991553Srgrimesint
3001553Srgrimesisowner(owner, file)
3011553Srgrimes	char *owner, *file;
3021553Srgrimes{
3031553Srgrimes	if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
3041553Srgrimes		return(1);
3051553Srgrimes	if (!strcmp(person, owner) && !strcmp(from, file+6))
3061553Srgrimes		return(1);
3071553Srgrimes	if (from != host)
3081553Srgrimes		printf("%s: ", host);
3091553Srgrimes	printf("%s: Permission denied\n", file);
3101553Srgrimes	return(0);
3111553Srgrimes}
3121553Srgrimes
3131553Srgrimes/*
3141553Srgrimes * Check to see if we are sending files to a remote machine. If we are,
3151553Srgrimes * then try removing files on the remote machine.
3161553Srgrimes */
3171553Srgrimesvoid
3181553Srgrimesrmremote()
3191553Srgrimes{
3201553Srgrimes	register char *cp;
3211553Srgrimes	register int i, rem;
3221553Srgrimes	char buf[BUFSIZ];
32330407Sjoerg	void (*savealrm)(int);
3241553Srgrimes
32515648Sjoerg	if (!remote)
3261553Srgrimes		return;	/* not sending to a remote machine */
3271553Srgrimes
3281553Srgrimes	/*
3291553Srgrimes	 * Flush stdout so the user can see what has been deleted
3301553Srgrimes	 * while we wait (possibly) for the connection.
3311553Srgrimes	 */
3321553Srgrimes	fflush(stdout);
3331553Srgrimes
3341553Srgrimes	(void)snprintf(buf, sizeof(buf), "\5%s %s", RP, all ? "-all" : person);
3351553Srgrimes	cp = buf;
33627748Simp	for (i = 0; i < users && cp-buf+1+strlen(user[i]) < sizeof(buf); i++) {
3371553Srgrimes		cp += strlen(cp);
3381553Srgrimes		*cp++ = ' ';
3391553Srgrimes		strcpy(cp, user[i]);
3401553Srgrimes	}
34127757Simp	for (i = 0; i < requests && cp-buf+10 < sizeof(buf) - 1; i++) {
3421553Srgrimes		cp += strlen(cp);
3431553Srgrimes		(void) sprintf(cp, " %d", requ[i]);
3441553Srgrimes	}
3451553Srgrimes	strcat(cp, "\n");
34630407Sjoerg	savealrm = signal(SIGALRM, alarmhandler);
34730407Sjoerg	alarm(CT);
34815648Sjoerg	rem = getport(RM, 0);
34930407Sjoerg	(void)signal(SIGALRM, savealrm);
3501553Srgrimes	if (rem < 0) {
3511553Srgrimes		if (from != host)
3521553Srgrimes			printf("%s: ", host);
3531553Srgrimes		printf("connection to %s is down\n", RM);
3541553Srgrimes	} else {
3551553Srgrimes		i = strlen(buf);
3561553Srgrimes		if (write(rem, buf, i) != i)
3571553Srgrimes			fatal("Lost connection");
3581553Srgrimes		while ((i = read(rem, buf, sizeof(buf))) > 0)
3591553Srgrimes			(void) fwrite(buf, 1, i, stdout);
3601553Srgrimes		(void) close(rem);
3611553Srgrimes	}
3621553Srgrimes}
3631553Srgrimes
3641553Srgrimes/*
3651553Srgrimes * Return 1 if the filename begins with 'cf'
3661553Srgrimes */
3671553Srgrimesint
3681553Srgrimesiscf(d)
3691553Srgrimes	struct dirent *d;
3701553Srgrimes{
3711553Srgrimes	return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
3721553Srgrimes}
37330407Sjoerg
37430407Sjoergvoid
37530407Sjoergalarmhandler(signo)
37630407Sjoerg{
37730407Sjoerg	/* ignored */
37830407Sjoerg}
379