[BACK]Return to lp_rmjob.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / lpd

File: [local] / src / usr.sbin / lpd / lp_rmjob.c (download)

Revision 1.1, Fri Apr 27 16:14:36 2018 UTC (6 years, 1 month ago) by eric
Branch point for: MAIN

Initial revision

/*	$OpenBSD: lp_rmjob.c,v 1.1 2018/04/27 16:14:36 eric Exp $	*/

/*
 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "lp.h"

#include "log.h"

static int docheck(struct lp_printer *, const char *, struct lp_jobfilter *,
    const char *, int, int);
static void doremove(int, struct lp_printer *, const char *);

int
lp_rmjob(int ofd, struct lp_printer *lp, const char *agent,
    struct lp_jobfilter *jf)
{
	struct lp_queue q;
	char currjob[PATH_MAX];
	pid_t currpid;
	int active, i, killed = 0;

	if ((lp_readqueue(lp, &q)) == -1) {
		log_warnx("cannot read queue");
		return 0;
	}

	if (q.count == 0) {
		lp_clearqueue(&q);
		return 0;
	}

	/*
	 * Find the current task being printed, and kill the printer process
	 * if the file is to be removed.
	 */
	if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1)
		log_warnx("cannot get current task");

	if (currjob[0] && docheck(lp, agent, jf, currjob, 1, 0) == 1) {
		if (kill(currpid, SIGINT) == -1)
			log_warn("lpr: cannot kill printer process %d",
			    (int)currpid);
		else
			killed = 1;
	}

	for(i = 0; i < q.count; i++) {
		active = !strcmp(q.cfname[i], currjob);
		switch (docheck(lp, agent, jf, q.cfname[i], active, 0)) {
		case 0:
			break;
		case 1:
			doremove(ofd, lp, q.cfname[i]);
			break;
		case 2:
			if (lp->lp_type == PRN_LPR)
				dprintf(ofd, "%s: ", lpd_hostname);
			dprintf(ofd, "%s: Permission denied\n", q.cfname[i]);
			break;
		}
	}

	lp_clearqueue(&q);

	return killed;
}

/*
 * Check if a file must be removed.
 *
 * Return:
 *	0: no
 *	1: yes
 *	2: yes but user has no right to do so
 */
static int
docheck(struct lp_printer *lp, const char *agent, struct lp_jobfilter *jf,
    const char *cfname, int current, int local)
{
	FILE *fp;
	ssize_t len;
	size_t linesz = 0;
	char *line = NULL, *person = NULL;
	int i, own = 0;

	/* The "-all" agent means remove all jobs from the client host. */
	if (!strcmp(agent, "-all") && !strcmp(LP_JOBHOST(cfname), jf->hostfrom))
		return 1;

	/*
	 * Consider the root user owns local files, and files sent from
	 * the same machine.
	 */
	if (!strcmp(agent, "root"))
		own = local || !strcmp(LP_JOBHOST(cfname), jf->hostfrom);

	/* Check if the task person matches the agent. */
	fp = lp_fopen(lp, cfname);
	if (fp == NULL) {
		log_warn("cannot open %s", cfname);
		return 0;
	}
	while ((len = getline(&line, &linesz, fp)) != -1) {
		if (line[len-1] == '\n')
			line[len - 1] = '\0';
		if (line[0] == 'P') {
			person = line + 1;
			if (!strcmp(person, agent) &&
			    !strcmp(LP_JOBHOST(cfname), jf->hostfrom))
				own = 1;
			break;
		}
	}
	fclose(fp);

	if (person == NULL) {
		free(line);
		return 0;
	}

	/* Remove the current task if the request list is empty. */
	if (current && jf->nuser == 0 && jf->njob == 0)
		goto remove;

	/* Check for matching jobnum. */
	for (i = 0; i < jf->njob; i++)
		if (jf->jobs[i] == LP_JOBNUM(cfname))
			goto remove;

	/* Check if person is in user list. */
	for (i = 0; i < jf->nuser; i++)
		if (!strcmp(jf->users[i], person))
			goto remove;

	free(line);
	return 0;

    remove:
	free(line);
	return own ? 1 : 2;
}

static void
doremove(int ofd, struct lp_printer *lp, const char *cfname)
{
	FILE *fp;
	ssize_t len;
	size_t linesz = 0;
	char *line = NULL;

	fp = lp_fopen(lp, cfname);
	if (fp == NULL) {
		log_warn("cannot open %s", cfname);
		return;
	}

	if (lp->lp_type == PRN_LPR)
		dprintf(ofd, "%s: ", lpd_hostname);

	/* First, remove the control file. */
	if (lp_unlink(lp, cfname) == -1) {
		log_warn("cannot unlink %s", cfname);
		dprintf(ofd, "cannot dequeue %s\n", cfname);
	}
	else {
		log_info("removed job %s", cfname);
		dprintf(ofd, "%s dequeued\n", cfname);
	}

	/* Then unlink all data files. */
	while ((len = getline(&line, &linesz, fp)) != -1) {
		if (line[len-1] == '\n')
			line[len - 1] = '\0';
		if (line[0] != 'U')
			continue;
		if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
			continue;
		if (lp->lp_type == PRN_LPR)
			dprintf(ofd, "%s: ", lpd_hostname);
		if (lp_unlink(lp, line + 1) == -1) {
			log_warn("cannot unlink %s", line + 1);
			dprintf(ofd, "cannot dequeue %s\n", line + 1);
		}
		else
			dprintf(ofd, "%s dequeued\n", line + 1);
	}

	fclose(fp);
}