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