rmjob.c revision 74126
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[] =
3950479Speter  "$FreeBSD: head/usr.sbin/lpr/common_source/rmjob.c 74126 2001-03-12 01:16:09Z gad $";
401553Srgrimes#endif /* not lint */
411553Srgrimes
421553Srgrimes#include <sys/param.h>
4331492Swollman#include <sys/uio.h>
441553Srgrimes
4531492Swollman#include <ctype.h>
4631492Swollman#include <dirent.h>
4731492Swollman#include <errno.h>
481553Srgrimes#include <signal.h>
4931492Swollman#include <stdio.h>
501553Srgrimes#include <stdlib.h>
511553Srgrimes#include <string.h>
5231492Swollman#define psignal foil_gcc_psignal
5331492Swollman#define	sys_siglist foil_gcc_siglist
5431492Swollman#include <unistd.h>
5531492Swollman#undef psignal
5631492Swollman#undef sys_siglist
5731492Swollman
581553Srgrimes#include "lp.h"
591553Srgrimes#include "lp.local.h"
601553Srgrimes#include "pathnames.h"
611553Srgrimes
621553Srgrimes/*
631553Srgrimes * rmjob - remove the specified jobs from the queue.
641553Srgrimes */
651553Srgrimes
661553Srgrimes/*
671553Srgrimes * Stuff for handling lprm specifications
681553Srgrimes */
691553Srgrimesstatic char	root[] = "root";
701553Srgrimesstatic int	all = 0;		/* eliminate all files (root only) */
711553Srgrimesstatic int	cur_daemon;		/* daemon's pid */
7268342Sgadstatic char	current[7+MAXHOSTNAMELEN];  /* active control file name */
731553Srgrimes
7427618Simpextern uid_t	uid, euid;		/* real and effective user id's */
7527618Simp
7630407Sjoergstatic	void	alarmhandler __P((int));
7727618Simpstatic	void	do_unlink __P((char *));
7827618Simp
791553Srgrimesvoid
8031492Swollmanrmjob(printer)
8131492Swollman	const char *printer;
821553Srgrimes{
831553Srgrimes	register int i, nitems;
841553Srgrimes	int assasinated = 0;
851553Srgrimes	struct dirent **files;
861553Srgrimes	char *cp;
8731492Swollman	struct printer myprinter, *pp = &myprinter;
881553Srgrimes
8931492Swollman	init_printer(pp);
9031492Swollman	if ((i = getprintcap(printer, pp)) < 0)
9131492Swollman		fatal(pp, "getprintcap: %s", pcaperr(i));
9231492Swollman	if ((cp = checkremote(pp))) {
931553Srgrimes		printf("Warning: %s\n", cp);
9431492Swollman		free(cp);
9531492Swollman	}
961553Srgrimes
971553Srgrimes	/*
981553Srgrimes	 * If the format was `lprm -' and the user isn't the super-user,
991553Srgrimes	 *  then fake things to look like he said `lprm user'.
1001553Srgrimes	 */
1011553Srgrimes	if (users < 0) {
1021553Srgrimes		if (getuid() == 0)
1031553Srgrimes			all = 1;	/* all files in local queue */
1041553Srgrimes		else {
1051553Srgrimes			user[0] = person;
1061553Srgrimes			users = 1;
1071553Srgrimes		}
1081553Srgrimes	}
1091553Srgrimes	if (!strcmp(person, "-all")) {
1101553Srgrimes		if (from == host)
11131492Swollman			fatal(pp, "The login name \"-all\" is reserved");
1121553Srgrimes		all = 1;	/* all those from 'from' */
1131553Srgrimes		person = root;
1141553Srgrimes	}
1151553Srgrimes
11627618Simp	seteuid(euid);
11731492Swollman	if (chdir(pp->spool_dir) < 0)
11831492Swollman		fatal(pp, "cannot chdir to spool directory");
1191553Srgrimes	if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
12031492Swollman		fatal(pp, "cannot access spool directory");
12127618Simp	seteuid(uid);
1221553Srgrimes
1231553Srgrimes	if (nitems) {
1241553Srgrimes		/*
1251553Srgrimes		 * Check for an active printer daemon (in which case we
1261553Srgrimes		 *  kill it if it is reading our file) then remove stuff
1271553Srgrimes		 *  (after which we have to restart the daemon).
1281553Srgrimes		 */
12931492Swollman		if (lockchk(pp, pp->lock_file) && chk(current)) {
13027618Simp			seteuid(euid);
1311553Srgrimes			assasinated = kill(cur_daemon, SIGINT) == 0;
13227618Simp			seteuid(uid);
1331553Srgrimes			if (!assasinated)
13431492Swollman				fatal(pp, "cannot kill printer daemon");
1351553Srgrimes		}
1361553Srgrimes		/*
1371553Srgrimes		 * process the files
1381553Srgrimes		 */
1391553Srgrimes		for (i = 0; i < nitems; i++)
14031492Swollman			process(pp, files[i]->d_name);
1411553Srgrimes	}
14231492Swollman	rmremote(pp);
1431553Srgrimes	/*
1441553Srgrimes	 * Restart the printer daemon if it was killed
1451553Srgrimes	 */
14631492Swollman	if (assasinated && !startdaemon(pp))
14731492Swollman		fatal(pp, "cannot restart printer daemon\n");
1481553Srgrimes	exit(0);
1491553Srgrimes}
1501553Srgrimes
1511553Srgrimes/*
1521553Srgrimes * Process a lock file: collect the pid of the active
1531553Srgrimes *  daemon and the file name of the active spool entry.
1541553Srgrimes * Return boolean indicating existence of a lock file.
1551553Srgrimes */
1561553Srgrimesint
15731492Swollmanlockchk(pp, s)
15831492Swollman	struct printer *pp;
1591553Srgrimes	char *s;
1601553Srgrimes{
1611553Srgrimes	register FILE *fp;
1621553Srgrimes	register int i, n;
1631553Srgrimes
16427618Simp	seteuid(euid);
16527618Simp	if ((fp = fopen(s, "r")) == NULL) {
1661553Srgrimes		if (errno == EACCES)
16731492Swollman			fatal(pp, "%s: %s", s, strerror(errno));
1681553Srgrimes		else
1691553Srgrimes			return(0);
17027618Simp	}
17127618Simp	seteuid(uid);
1721553Srgrimes	if (!getline(fp)) {
1731553Srgrimes		(void) fclose(fp);
1741553Srgrimes		return(0);		/* no daemon present */
1751553Srgrimes	}
1761553Srgrimes	cur_daemon = atoi(line);
17727618Simp	if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
1781553Srgrimes		(void) fclose(fp);
1791553Srgrimes		return(0);		/* no daemon present */
1801553Srgrimes	}
1811553Srgrimes	for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
1821553Srgrimes		if (i > 5) {
1831553Srgrimes			n = 1;
1841553Srgrimes			break;
1851553Srgrimes		}
1861553Srgrimes		sleep(i);
1871553Srgrimes	}
1881553Srgrimes	current[n-1] = '\0';
1891553Srgrimes	(void) fclose(fp);
1901553Srgrimes	return(1);
1911553Srgrimes}
1921553Srgrimes
1931553Srgrimes/*
1941553Srgrimes * Process a control file.
1951553Srgrimes */
1961553Srgrimesvoid
19731492Swollmanprocess(pp, file)
19831492Swollman	const struct printer *pp;
1991553Srgrimes	char *file;
2001553Srgrimes{
2011553Srgrimes	FILE *cfp;
2021553Srgrimes
2031553Srgrimes	if (!chk(file))
2041553Srgrimes		return;
20527618Simp	seteuid(euid);
2061553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
20731492Swollman		fatal(pp, "cannot open %s", file);
20827618Simp	seteuid(uid);
2091553Srgrimes	while (getline(cfp)) {
2101553Srgrimes		switch (line[0]) {
2111553Srgrimes		case 'U':  /* unlink associated files */
21227509Simp			if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
21327509Simp				break;
21427618Simp			do_unlink(line+1);
2151553Srgrimes		}
2161553Srgrimes	}
2171553Srgrimes	(void) fclose(cfp);
21827618Simp	do_unlink(file);
21927618Simp}
22027618Simp
22127618Simpstatic void
22227618Simpdo_unlink(file)
22327618Simp	char *file;
22427618Simp{
22527618Simp	int	ret;
22627618Simp
2271553Srgrimes	if (from != host)
2281553Srgrimes		printf("%s: ", host);
22927618Simp	seteuid(euid);
23027618Simp	ret = unlink(file);
23127618Simp	seteuid(uid);
23227618Simp	printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
2331553Srgrimes}
2341553Srgrimes
2351553Srgrimes/*
2361553Srgrimes * Do the dirty work in checking
2371553Srgrimes */
2381553Srgrimesint
2391553Srgrimeschk(file)
2401553Srgrimes	char *file;
2411553Srgrimes{
2421553Srgrimes	register int *r, n;
2431553Srgrimes	register char **u, *cp;
2441553Srgrimes	FILE *cfp;
2451553Srgrimes
2461553Srgrimes	/*
2471553Srgrimes	 * Check for valid cf file name (mostly checking current).
2481553Srgrimes	 */
2491553Srgrimes	if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
2501553Srgrimes		return(0);
2511553Srgrimes
2521553Srgrimes	if (all && (from == host || !strcmp(from, file+6)))
2531553Srgrimes		return(1);
2541553Srgrimes
2551553Srgrimes	/*
2561553Srgrimes	 * get the owner's name from the control file.
2571553Srgrimes	 */
25827618Simp	seteuid(euid);
2591553Srgrimes	if ((cfp = fopen(file, "r")) == NULL)
2601553Srgrimes		return(0);
26127618Simp	seteuid(uid);
2621553Srgrimes	while (getline(cfp)) {
2631553Srgrimes		if (line[0] == 'P')
2641553Srgrimes			break;
2651553Srgrimes	}
2661553Srgrimes	(void) fclose(cfp);
2671553Srgrimes	if (line[0] != 'P')
2681553Srgrimes		return(0);
2691553Srgrimes
2701553Srgrimes	if (users == 0 && requests == 0)
2711553Srgrimes		return(!strcmp(file, current) && isowner(line+1, file));
2721553Srgrimes	/*
2731553Srgrimes	 * Check the request list
2741553Srgrimes	 */
2751553Srgrimes	for (n = 0, cp = file+3; isdigit(*cp); )
2761553Srgrimes		n = n * 10 + (*cp++ - '0');
2771553Srgrimes	for (r = requ; r < &requ[requests]; r++)
2781553Srgrimes		if (*r == n && isowner(line+1, file))
2791553Srgrimes			return(1);
2801553Srgrimes	/*
2811553Srgrimes	 * Check to see if it's in the user list
2821553Srgrimes	 */
2831553Srgrimes	for (u = user; u < &user[users]; u++)
2841553Srgrimes		if (!strcmp(*u, line+1) && isowner(line+1, file))
2851553Srgrimes			return(1);
2861553Srgrimes	return(0);
2871553Srgrimes}
2881553Srgrimes
2891553Srgrimes/*
2901553Srgrimes * If root is removing a file on the local machine, allow it.
2911553Srgrimes * If root is removing a file from a remote machine, only allow
2921553Srgrimes * files sent from the remote machine to be removed.
2931553Srgrimes * Normal users can only remove the file from where it was sent.
2941553Srgrimes */
2951553Srgrimesint
2961553Srgrimesisowner(owner, file)
2971553Srgrimes	char *owner, *file;
2981553Srgrimes{
2991553Srgrimes	if (!strcmp(person, root) && (from == host || !strcmp(from, file+6)))
3001553Srgrimes		return(1);
3011553Srgrimes	if (!strcmp(person, owner) && !strcmp(from, file+6))
3021553Srgrimes		return(1);
3031553Srgrimes	if (from != host)
3041553Srgrimes		printf("%s: ", host);
3051553Srgrimes	printf("%s: Permission denied\n", file);
3061553Srgrimes	return(0);
3071553Srgrimes}
3081553Srgrimes
3091553Srgrimes/*
3101553Srgrimes * Check to see if we are sending files to a remote machine. If we are,
3111553Srgrimes * then try removing files on the remote machine.
3121553Srgrimes */
3131553Srgrimesvoid
31431492Swollmanrmremote(pp)
31531492Swollman	const struct printer *pp;
3161553Srgrimes{
31774126Sgad	int i, elem, firstreq, niov, rem, totlen;
3181553Srgrimes	char buf[BUFSIZ];
31930407Sjoerg	void (*savealrm)(int);
32031492Swollman	struct iovec *iov;
3211553Srgrimes
32231492Swollman	if (!pp->remote)
3231553Srgrimes		return;	/* not sending to a remote machine */
3241553Srgrimes
3251553Srgrimes	/*
3261553Srgrimes	 * Flush stdout so the user can see what has been deleted
3271553Srgrimes	 * while we wait (possibly) for the connection.
3281553Srgrimes	 */
3291553Srgrimes	fflush(stdout);
3301553Srgrimes
33131492Swollman	/*
33231492Swollman	 * Counting:
33331492Swollman	 *	4 == "\5" + remote_queue + " " + person
33431492Swollman	 *	2 * users == " " + user[i] for each user
33531492Swollman	 *	requests == asprintf results for each request
33631492Swollman	 *	1 == "\n"
33731492Swollman	 * Although laborious, doing it this way makes it possible for
33831492Swollman	 * us to process requests of indeterminate length without
33931492Swollman	 * applying an arbitrary limit.  Arbitrary Limits Are Bad (tm).
34031492Swollman	 */
34174126Sgad	if (users > 0)
34274126Sgad		niov = 4 + 2 * users + requests + 1;
34374126Sgad	else
34474126Sgad		niov = 4 + requests + 1;
34531492Swollman	iov = malloc(niov * sizeof *iov);
34631492Swollman	if (iov == 0)
34774126Sgad		fatal(pp, "out of memory in rmremote()");
34831492Swollman	iov[0].iov_base = "\5";
34931492Swollman	iov[1].iov_base = pp->remote_queue;
35031492Swollman	iov[2].iov_base = " ";
35131492Swollman	iov[3].iov_base = all ? "-all" : person;
35274126Sgad	elem = 4;
35331492Swollman	for (i = 0; i < users; i++) {
35474126Sgad		iov[elem].iov_base = " ";
35574126Sgad		iov[elem + 1].iov_base = user[i];
35674126Sgad		elem += 2;
3571553Srgrimes	}
35874126Sgad	firstreq = elem;
35931492Swollman	for (i = 0; i < requests; i++) {
36074126Sgad		asprintf(&iov[elem].iov_base, " %d", requ[i]);
36174126Sgad		if (iov[elem].iov_base == 0)
36274126Sgad			fatal(pp, "out of memory in rmremote()");
36374126Sgad		elem++;
3641553Srgrimes	}
36574126Sgad	iov[elem++].iov_base = "\n";
36631492Swollman	for (totlen = i = 0; i < niov; i++)
36731492Swollman		totlen += (iov[i].iov_len = strlen(iov[i].iov_base));
36831492Swollman
36930407Sjoerg	savealrm = signal(SIGALRM, alarmhandler);
37031492Swollman	alarm(pp->conn_timeout);
37131492Swollman	rem = getport(pp, pp->remote_host, 0);
37230407Sjoerg	(void)signal(SIGALRM, savealrm);
3731553Srgrimes	if (rem < 0) {
3741553Srgrimes		if (from != host)
3751553Srgrimes			printf("%s: ", host);
37631492Swollman		printf("connection to %s is down\n", pp->remote_host);
3771553Srgrimes	} else {
37831492Swollman		if (writev(rem, iov, niov) != totlen)
37931492Swollman			fatal(pp, "Lost connection");
3801553Srgrimes		while ((i = read(rem, buf, sizeof(buf))) > 0)
3811553Srgrimes			(void) fwrite(buf, 1, i, stdout);
3821553Srgrimes		(void) close(rem);
3831553Srgrimes	}
38431492Swollman	for (i = 0; i < requests; i++)
38574126Sgad		free(iov[firstreq + i].iov_base);
38631492Swollman	free(iov);
3871553Srgrimes}
3881553Srgrimes
3891553Srgrimes/*
3901553Srgrimes * Return 1 if the filename begins with 'cf'
3911553Srgrimes */
3921553Srgrimesint
3931553Srgrimesiscf(d)
3941553Srgrimes	struct dirent *d;
3951553Srgrimes{
3961553Srgrimes	return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
3971553Srgrimes}
39830407Sjoerg
39930407Sjoergvoid
40030407Sjoergalarmhandler(signo)
40131492Swollman	int signo;
40230407Sjoerg{
40330407Sjoerg	/* ignored */
40430407Sjoerg}
405