rmjob.c revision 78146
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 78146 2001-06-12 16:38:20Z 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 7678146Sgadstatic void alarmhandler(int _signo); 7778146Sgadstatic void do_unlink(char *_file); 7827618Simp 791553Srgrimesvoid 8078146Sgadrmjob(const char *printer) 811553Srgrimes{ 821553Srgrimes register int i, nitems; 831553Srgrimes int assasinated = 0; 841553Srgrimes struct dirent **files; 851553Srgrimes char *cp; 8631492Swollman struct printer myprinter, *pp = &myprinter; 871553Srgrimes 8831492Swollman init_printer(pp); 8931492Swollman if ((i = getprintcap(printer, pp)) < 0) 9031492Swollman fatal(pp, "getprintcap: %s", pcaperr(i)); 9131492Swollman if ((cp = checkremote(pp))) { 921553Srgrimes printf("Warning: %s\n", cp); 9331492Swollman free(cp); 9431492Swollman } 951553Srgrimes 961553Srgrimes /* 971553Srgrimes * If the format was `lprm -' and the user isn't the super-user, 981553Srgrimes * then fake things to look like he said `lprm user'. 991553Srgrimes */ 1001553Srgrimes if (users < 0) { 1011553Srgrimes if (getuid() == 0) 1021553Srgrimes all = 1; /* all files in local queue */ 1031553Srgrimes else { 1041553Srgrimes user[0] = person; 1051553Srgrimes users = 1; 1061553Srgrimes } 1071553Srgrimes } 1081553Srgrimes if (!strcmp(person, "-all")) { 1091553Srgrimes if (from == host) 11031492Swollman fatal(pp, "The login name \"-all\" is reserved"); 1111553Srgrimes all = 1; /* all those from 'from' */ 1121553Srgrimes person = root; 1131553Srgrimes } 1141553Srgrimes 11527618Simp seteuid(euid); 11631492Swollman if (chdir(pp->spool_dir) < 0) 11731492Swollman fatal(pp, "cannot chdir to spool directory"); 1181553Srgrimes if ((nitems = scandir(".", &files, iscf, NULL)) < 0) 11931492Swollman fatal(pp, "cannot access spool directory"); 12027618Simp seteuid(uid); 1211553Srgrimes 1221553Srgrimes if (nitems) { 1231553Srgrimes /* 1241553Srgrimes * Check for an active printer daemon (in which case we 1251553Srgrimes * kill it if it is reading our file) then remove stuff 1261553Srgrimes * (after which we have to restart the daemon). 1271553Srgrimes */ 12831492Swollman if (lockchk(pp, pp->lock_file) && chk(current)) { 12927618Simp seteuid(euid); 1301553Srgrimes assasinated = kill(cur_daemon, SIGINT) == 0; 13127618Simp seteuid(uid); 1321553Srgrimes if (!assasinated) 13331492Swollman fatal(pp, "cannot kill printer daemon"); 1341553Srgrimes } 1351553Srgrimes /* 1361553Srgrimes * process the files 1371553Srgrimes */ 1381553Srgrimes for (i = 0; i < nitems; i++) 13931492Swollman process(pp, files[i]->d_name); 1401553Srgrimes } 14131492Swollman rmremote(pp); 1421553Srgrimes /* 1431553Srgrimes * Restart the printer daemon if it was killed 1441553Srgrimes */ 14531492Swollman if (assasinated && !startdaemon(pp)) 14631492Swollman fatal(pp, "cannot restart printer daemon\n"); 1471553Srgrimes exit(0); 1481553Srgrimes} 1491553Srgrimes 1501553Srgrimes/* 1511553Srgrimes * Process a lock file: collect the pid of the active 1521553Srgrimes * daemon and the file name of the active spool entry. 1531553Srgrimes * Return boolean indicating existence of a lock file. 1541553Srgrimes */ 1551553Srgrimesint 15678146Sgadlockchk(struct printer *pp, char *slockf) 1571553Srgrimes{ 1581553Srgrimes register FILE *fp; 1591553Srgrimes register int i, n; 1601553Srgrimes 16127618Simp seteuid(euid); 16278146Sgad if ((fp = fopen(slockf, "r")) == NULL) { 1631553Srgrimes if (errno == EACCES) 16478146Sgad fatal(pp, "%s: %s", slockf, strerror(errno)); 1651553Srgrimes else 1661553Srgrimes return(0); 16727618Simp } 16827618Simp seteuid(uid); 1691553Srgrimes if (!getline(fp)) { 1701553Srgrimes (void) fclose(fp); 1711553Srgrimes return(0); /* no daemon present */ 1721553Srgrimes } 1731553Srgrimes cur_daemon = atoi(line); 17427618Simp if (kill(cur_daemon, 0) < 0 && errno != EPERM) { 1751553Srgrimes (void) fclose(fp); 1761553Srgrimes return(0); /* no daemon present */ 1771553Srgrimes } 1781553Srgrimes for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) { 1791553Srgrimes if (i > 5) { 1801553Srgrimes n = 1; 1811553Srgrimes break; 1821553Srgrimes } 1831553Srgrimes sleep(i); 1841553Srgrimes } 1851553Srgrimes current[n-1] = '\0'; 1861553Srgrimes (void) fclose(fp); 1871553Srgrimes return(1); 1881553Srgrimes} 1891553Srgrimes 1901553Srgrimes/* 1911553Srgrimes * Process a control file. 1921553Srgrimes */ 1931553Srgrimesvoid 19478146Sgadprocess(const struct printer *pp, char *file) 1951553Srgrimes{ 1961553Srgrimes FILE *cfp; 1971553Srgrimes 1981553Srgrimes if (!chk(file)) 1991553Srgrimes return; 20027618Simp seteuid(euid); 2011553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 20231492Swollman fatal(pp, "cannot open %s", file); 20327618Simp seteuid(uid); 2041553Srgrimes while (getline(cfp)) { 2051553Srgrimes switch (line[0]) { 2061553Srgrimes case 'U': /* unlink associated files */ 20727509Simp if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) 20827509Simp break; 20927618Simp do_unlink(line+1); 2101553Srgrimes } 2111553Srgrimes } 2121553Srgrimes (void) fclose(cfp); 21327618Simp do_unlink(file); 21427618Simp} 21527618Simp 21627618Simpstatic void 21778146Sgaddo_unlink(char *file) 21827618Simp{ 21927618Simp int ret; 22027618Simp 2211553Srgrimes if (from != host) 2221553Srgrimes printf("%s: ", host); 22327618Simp seteuid(euid); 22427618Simp ret = unlink(file); 22527618Simp seteuid(uid); 22627618Simp printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file); 2271553Srgrimes} 2281553Srgrimes 2291553Srgrimes/* 2301553Srgrimes * Do the dirty work in checking 2311553Srgrimes */ 2321553Srgrimesint 23378146Sgadchk(char *file) 2341553Srgrimes{ 2351553Srgrimes register int *r, n; 2361553Srgrimes register char **u, *cp; 2371553Srgrimes FILE *cfp; 2381553Srgrimes 2391553Srgrimes /* 2401553Srgrimes * Check for valid cf file name (mostly checking current). 2411553Srgrimes */ 2421553Srgrimes if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f') 2431553Srgrimes return(0); 2441553Srgrimes 2451553Srgrimes if (all && (from == host || !strcmp(from, file+6))) 2461553Srgrimes return(1); 2471553Srgrimes 2481553Srgrimes /* 2491553Srgrimes * get the owner's name from the control file. 2501553Srgrimes */ 25127618Simp seteuid(euid); 2521553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 2531553Srgrimes return(0); 25427618Simp seteuid(uid); 2551553Srgrimes while (getline(cfp)) { 2561553Srgrimes if (line[0] == 'P') 2571553Srgrimes break; 2581553Srgrimes } 2591553Srgrimes (void) fclose(cfp); 2601553Srgrimes if (line[0] != 'P') 2611553Srgrimes return(0); 2621553Srgrimes 2631553Srgrimes if (users == 0 && requests == 0) 2641553Srgrimes return(!strcmp(file, current) && isowner(line+1, file)); 2651553Srgrimes /* 2661553Srgrimes * Check the request list 2671553Srgrimes */ 2681553Srgrimes for (n = 0, cp = file+3; isdigit(*cp); ) 2691553Srgrimes n = n * 10 + (*cp++ - '0'); 2701553Srgrimes for (r = requ; r < &requ[requests]; r++) 2711553Srgrimes if (*r == n && isowner(line+1, file)) 2721553Srgrimes return(1); 2731553Srgrimes /* 2741553Srgrimes * Check to see if it's in the user list 2751553Srgrimes */ 2761553Srgrimes for (u = user; u < &user[users]; u++) 2771553Srgrimes if (!strcmp(*u, line+1) && isowner(line+1, file)) 2781553Srgrimes return(1); 2791553Srgrimes return(0); 2801553Srgrimes} 2811553Srgrimes 2821553Srgrimes/* 2831553Srgrimes * If root is removing a file on the local machine, allow it. 2841553Srgrimes * If root is removing a file from a remote machine, only allow 2851553Srgrimes * files sent from the remote machine to be removed. 2861553Srgrimes * Normal users can only remove the file from where it was sent. 2871553Srgrimes */ 2881553Srgrimesint 28978146Sgadisowner(char *owner, char *file) 2901553Srgrimes{ 2911553Srgrimes if (!strcmp(person, root) && (from == host || !strcmp(from, file+6))) 29278146Sgad return (1); 2931553Srgrimes if (!strcmp(person, owner) && !strcmp(from, file+6)) 29478146Sgad return (1); 2951553Srgrimes if (from != host) 2961553Srgrimes printf("%s: ", host); 2971553Srgrimes printf("%s: Permission denied\n", file); 2981553Srgrimes return(0); 2991553Srgrimes} 3001553Srgrimes 3011553Srgrimes/* 3021553Srgrimes * Check to see if we are sending files to a remote machine. If we are, 3031553Srgrimes * then try removing files on the remote machine. 3041553Srgrimes */ 3051553Srgrimesvoid 30678146Sgadrmremote(const struct printer *pp) 3071553Srgrimes{ 30874126Sgad int i, elem, firstreq, niov, rem, totlen; 3091553Srgrimes char buf[BUFSIZ]; 31030407Sjoerg void (*savealrm)(int); 31131492Swollman struct iovec *iov; 3121553Srgrimes 31331492Swollman if (!pp->remote) 3141553Srgrimes return; /* not sending to a remote machine */ 3151553Srgrimes 3161553Srgrimes /* 3171553Srgrimes * Flush stdout so the user can see what has been deleted 3181553Srgrimes * while we wait (possibly) for the connection. 3191553Srgrimes */ 3201553Srgrimes fflush(stdout); 3211553Srgrimes 32231492Swollman /* 32331492Swollman * Counting: 32431492Swollman * 4 == "\5" + remote_queue + " " + person 32531492Swollman * 2 * users == " " + user[i] for each user 32631492Swollman * requests == asprintf results for each request 32731492Swollman * 1 == "\n" 32831492Swollman * Although laborious, doing it this way makes it possible for 32931492Swollman * us to process requests of indeterminate length without 33031492Swollman * applying an arbitrary limit. Arbitrary Limits Are Bad (tm). 33131492Swollman */ 33274126Sgad if (users > 0) 33374126Sgad niov = 4 + 2 * users + requests + 1; 33474126Sgad else 33574126Sgad niov = 4 + requests + 1; 33631492Swollman iov = malloc(niov * sizeof *iov); 33731492Swollman if (iov == 0) 33874126Sgad fatal(pp, "out of memory in rmremote()"); 33931492Swollman iov[0].iov_base = "\5"; 34031492Swollman iov[1].iov_base = pp->remote_queue; 34131492Swollman iov[2].iov_base = " "; 34231492Swollman iov[3].iov_base = all ? "-all" : person; 34374126Sgad elem = 4; 34431492Swollman for (i = 0; i < users; i++) { 34574126Sgad iov[elem].iov_base = " "; 34674126Sgad iov[elem + 1].iov_base = user[i]; 34774126Sgad elem += 2; 3481553Srgrimes } 34974126Sgad firstreq = elem; 35031492Swollman for (i = 0; i < requests; i++) { 35174126Sgad asprintf(&iov[elem].iov_base, " %d", requ[i]); 35274126Sgad if (iov[elem].iov_base == 0) 35374126Sgad fatal(pp, "out of memory in rmremote()"); 35474126Sgad elem++; 3551553Srgrimes } 35674126Sgad iov[elem++].iov_base = "\n"; 35731492Swollman for (totlen = i = 0; i < niov; i++) 35831492Swollman totlen += (iov[i].iov_len = strlen(iov[i].iov_base)); 35931492Swollman 36030407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 36131492Swollman alarm(pp->conn_timeout); 36231492Swollman rem = getport(pp, pp->remote_host, 0); 36330407Sjoerg (void)signal(SIGALRM, savealrm); 3641553Srgrimes if (rem < 0) { 3651553Srgrimes if (from != host) 3661553Srgrimes printf("%s: ", host); 36731492Swollman printf("connection to %s is down\n", pp->remote_host); 3681553Srgrimes } else { 36931492Swollman if (writev(rem, iov, niov) != totlen) 37031492Swollman fatal(pp, "Lost connection"); 3711553Srgrimes while ((i = read(rem, buf, sizeof(buf))) > 0) 3721553Srgrimes (void) fwrite(buf, 1, i, stdout); 3731553Srgrimes (void) close(rem); 3741553Srgrimes } 37531492Swollman for (i = 0; i < requests; i++) 37674126Sgad free(iov[firstreq + i].iov_base); 37731492Swollman free(iov); 3781553Srgrimes} 3791553Srgrimes 3801553Srgrimes/* 3811553Srgrimes * Return 1 if the filename begins with 'cf' 3821553Srgrimes */ 3831553Srgrimesint 38478146Sgadiscf(struct dirent *d) 3851553Srgrimes{ 3861553Srgrimes return(d->d_name[0] == 'c' && d->d_name[1] == 'f'); 3871553Srgrimes} 38830407Sjoerg 38930407Sjoergvoid 39078146Sgadalarmhandler(int signo __unused) 39130407Sjoerg{ 39278146Sgad /* the signal is ignored */ 39378146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 39430407Sjoerg} 395