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 * 4. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 3029780Scharnier#if 0 31117592Sgad#ifndef lint 3215648Sjoergstatic char sccsid[] = "@(#)rmjob.c 8.2 (Berkeley) 4/28/95"; 33117592Sgad#endif /* not lint */ 3429780Scharnier#endif 35117592Sgad 36117541Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 37117541Sgad__FBSDID("$FreeBSD$"); 381553Srgrimes 391553Srgrimes#include <sys/param.h> 4031492Swollman#include <sys/uio.h> 411553Srgrimes 4231492Swollman#include <ctype.h> 4331492Swollman#include <dirent.h> 44241852Seadler#include <err.h> 4531492Swollman#include <errno.h> 461553Srgrimes#include <signal.h> 4731492Swollman#include <stdio.h> 481553Srgrimes#include <stdlib.h> 491553Srgrimes#include <string.h> 5031492Swollman#define psignal foil_gcc_psignal 5131492Swollman#define sys_siglist foil_gcc_siglist 5231492Swollman#include <unistd.h> 5331492Swollman#undef psignal 5431492Swollman#undef sys_siglist 5531492Swollman 561553Srgrimes#include "lp.h" 571553Srgrimes#include "lp.local.h" 581553Srgrimes#include "pathnames.h" 591553Srgrimes 601553Srgrimes/* 611553Srgrimes * rmjob - remove the specified jobs from the queue. 621553Srgrimes */ 631553Srgrimes 641553Srgrimes/* 651553Srgrimes * Stuff for handling lprm specifications 661553Srgrimes */ 671553Srgrimesstatic char root[] = "root"; 681553Srgrimesstatic int all = 0; /* eliminate all files (root only) */ 691553Srgrimesstatic int cur_daemon; /* daemon's pid */ 7068342Sgadstatic char current[7+MAXHOSTNAMELEN]; /* active control file name */ 711553Srgrimes 7278146Sgadstatic void alarmhandler(int _signo); 7378146Sgadstatic void do_unlink(char *_file); 74139464Sgadstatic int isowner(char *_owner, char *_file, const char *_cfhost); 7527618Simp 761553Srgrimesvoid 7778146Sgadrmjob(const char *printer) 781553Srgrimes{ 791553Srgrimes register int i, nitems; 80228990Suqs int assassinated = 0; 811553Srgrimes struct dirent **files; 821553Srgrimes char *cp; 8331492Swollman struct printer myprinter, *pp = &myprinter; 841553Srgrimes 8531492Swollman init_printer(pp); 8631492Swollman if ((i = getprintcap(printer, pp)) < 0) 8731492Swollman fatal(pp, "getprintcap: %s", pcaperr(i)); 8831492Swollman if ((cp = checkremote(pp))) { 891553Srgrimes printf("Warning: %s\n", cp); 9031492Swollman free(cp); 9131492Swollman } 921553Srgrimes 931553Srgrimes /* 941553Srgrimes * If the format was `lprm -' and the user isn't the super-user, 951553Srgrimes * then fake things to look like he said `lprm user'. 961553Srgrimes */ 971553Srgrimes if (users < 0) { 981553Srgrimes if (getuid() == 0) 991553Srgrimes all = 1; /* all files in local queue */ 1001553Srgrimes else { 1011553Srgrimes user[0] = person; 1021553Srgrimes users = 1; 1031553Srgrimes } 1041553Srgrimes } 1051553Srgrimes if (!strcmp(person, "-all")) { 10678300Sgad if (from_host == local_host) 10731492Swollman fatal(pp, "The login name \"-all\" is reserved"); 10878300Sgad all = 1; /* all those from 'from_host' */ 1091553Srgrimes person = root; 1101553Srgrimes } 1111553Srgrimes 112241852Seadler PRIV_START 11331492Swollman if (chdir(pp->spool_dir) < 0) 11431492Swollman fatal(pp, "cannot chdir to spool directory"); 1151553Srgrimes if ((nitems = scandir(".", &files, iscf, NULL)) < 0) 11631492Swollman fatal(pp, "cannot access spool directory"); 117241852Seadler PRIV_END 1181553Srgrimes 1191553Srgrimes if (nitems) { 1201553Srgrimes /* 1211553Srgrimes * Check for an active printer daemon (in which case we 1221553Srgrimes * kill it if it is reading our file) then remove stuff 1231553Srgrimes * (after which we have to restart the daemon). 1241553Srgrimes */ 12531492Swollman if (lockchk(pp, pp->lock_file) && chk(current)) { 126241852Seadler PRIV_START 127228990Suqs assassinated = kill(cur_daemon, SIGINT) == 0; 128241852Seadler PRIV_END 129228990Suqs if (!assassinated) 13031492Swollman fatal(pp, "cannot kill printer daemon"); 1311553Srgrimes } 1321553Srgrimes /* 1331553Srgrimes * process the files 1341553Srgrimes */ 1351553Srgrimes for (i = 0; i < nitems; i++) 13631492Swollman process(pp, files[i]->d_name); 1371553Srgrimes } 13831492Swollman rmremote(pp); 1391553Srgrimes /* 1401553Srgrimes * Restart the printer daemon if it was killed 1411553Srgrimes */ 142228990Suqs if (assassinated && !startdaemon(pp)) 14331492Swollman fatal(pp, "cannot restart printer daemon\n"); 1441553Srgrimes exit(0); 1451553Srgrimes} 1461553Srgrimes 1471553Srgrimes/* 1481553Srgrimes * Process a lock file: collect the pid of the active 1491553Srgrimes * daemon and the file name of the active spool entry. 1501553Srgrimes * Return boolean indicating existence of a lock file. 1511553Srgrimes */ 1521553Srgrimesint 15378146Sgadlockchk(struct printer *pp, char *slockf) 1541553Srgrimes{ 1551553Srgrimes register FILE *fp; 1561553Srgrimes register int i, n; 1571553Srgrimes 158241852Seadler PRIV_START 15978146Sgad if ((fp = fopen(slockf, "r")) == NULL) { 1601553Srgrimes if (errno == EACCES) 16178146Sgad fatal(pp, "%s: %s", slockf, strerror(errno)); 1621553Srgrimes else 1631553Srgrimes return(0); 16427618Simp } 165241852Seadler PRIV_END 1661553Srgrimes if (!getline(fp)) { 1671553Srgrimes (void) fclose(fp); 1681553Srgrimes return(0); /* no daemon present */ 1691553Srgrimes } 1701553Srgrimes cur_daemon = atoi(line); 17127618Simp if (kill(cur_daemon, 0) < 0 && errno != EPERM) { 1721553Srgrimes (void) fclose(fp); 1731553Srgrimes return(0); /* no daemon present */ 1741553Srgrimes } 1751553Srgrimes for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) { 1761553Srgrimes if (i > 5) { 1771553Srgrimes n = 1; 1781553Srgrimes break; 1791553Srgrimes } 1801553Srgrimes sleep(i); 1811553Srgrimes } 1821553Srgrimes current[n-1] = '\0'; 1831553Srgrimes (void) fclose(fp); 1841553Srgrimes return(1); 1851553Srgrimes} 1861553Srgrimes 1871553Srgrimes/* 1881553Srgrimes * Process a control file. 1891553Srgrimes */ 1901553Srgrimesvoid 19178146Sgadprocess(const struct printer *pp, char *file) 1921553Srgrimes{ 1931553Srgrimes FILE *cfp; 1941553Srgrimes 1951553Srgrimes if (!chk(file)) 1961553Srgrimes return; 197241852Seadler PRIV_START 1981553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 19931492Swollman fatal(pp, "cannot open %s", file); 200241852Seadler PRIV_END 2011553Srgrimes while (getline(cfp)) { 2021553Srgrimes switch (line[0]) { 2031553Srgrimes case 'U': /* unlink associated files */ 20427509Simp if (strchr(line+1, '/') || strncmp(line+1, "df", 2)) 20527509Simp break; 20627618Simp do_unlink(line+1); 2071553Srgrimes } 2081553Srgrimes } 2091553Srgrimes (void) fclose(cfp); 21027618Simp do_unlink(file); 21127618Simp} 21227618Simp 21327618Simpstatic void 21478146Sgaddo_unlink(char *file) 21527618Simp{ 21627618Simp int ret; 21727618Simp 21878300Sgad if (from_host != local_host) 21978300Sgad printf("%s: ", local_host); 220241852Seadler PRIV_START 22127618Simp ret = unlink(file); 222241852Seadler PRIV_END 22327618Simp printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file); 2241553Srgrimes} 2251553Srgrimes 2261553Srgrimes/* 2271553Srgrimes * Do the dirty work in checking 2281553Srgrimes */ 2291553Srgrimesint 23078146Sgadchk(char *file) 2311553Srgrimes{ 232139464Sgad int *r, jnum; 233139464Sgad char **u; 234139464Sgad const char *cfhost; 2351553Srgrimes FILE *cfp; 2361553Srgrimes 2371553Srgrimes /* 2381553Srgrimes * Check for valid cf file name (mostly checking current). 2391553Srgrimes */ 2401553Srgrimes if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f') 2411553Srgrimes return(0); 2421553Srgrimes 243139464Sgad jnum = calc_jobnum(file, &cfhost); 244139464Sgad if (all && (from_host == local_host || !strcmp(from_host, cfhost))) 2451553Srgrimes return(1); 2461553Srgrimes 2471553Srgrimes /* 2481553Srgrimes * get the owner's name from the control file. 2491553Srgrimes */ 250241852Seadler PRIV_START 2511553Srgrimes if ((cfp = fopen(file, "r")) == NULL) 2521553Srgrimes return(0); 253241852Seadler PRIV_END 2541553Srgrimes while (getline(cfp)) { 2551553Srgrimes if (line[0] == 'P') 2561553Srgrimes break; 2571553Srgrimes } 2581553Srgrimes (void) fclose(cfp); 2591553Srgrimes if (line[0] != 'P') 2601553Srgrimes return(0); 2611553Srgrimes 2621553Srgrimes if (users == 0 && requests == 0) 263139464Sgad return(!strcmp(file, current) && isowner(line+1, file, cfhost)); 2641553Srgrimes /* 2651553Srgrimes * Check the request list 2661553Srgrimes */ 2671553Srgrimes for (r = requ; r < &requ[requests]; r++) 268139464Sgad if (*r == jnum && isowner(line+1, file, cfhost)) 2691553Srgrimes return(1); 2701553Srgrimes /* 2711553Srgrimes * Check to see if it's in the user list 2721553Srgrimes */ 2731553Srgrimes for (u = user; u < &user[users]; u++) 274139464Sgad if (!strcmp(*u, line+1) && isowner(line+1, file, cfhost)) 2751553Srgrimes return(1); 2761553Srgrimes return(0); 2771553Srgrimes} 2781553Srgrimes 2791553Srgrimes/* 2801553Srgrimes * If root is removing a file on the local machine, allow it. 2811553Srgrimes * If root is removing a file from a remote machine, only allow 2821553Srgrimes * files sent from the remote machine to be removed. 2831553Srgrimes * Normal users can only remove the file from where it was sent. 2841553Srgrimes */ 285139464Sgadstatic int 286139464Sgadisowner(char *owner, char *file, const char *cfhost) 2871553Srgrimes{ 28878300Sgad if (!strcmp(person, root) && (from_host == local_host || 289139464Sgad !strcmp(from_host, cfhost))) 29078146Sgad return (1); 291139464Sgad if (!strcmp(person, owner) && !strcmp(from_host, cfhost)) 29278146Sgad return (1); 29378300Sgad if (from_host != local_host) 29478300Sgad printf("%s: ", local_host); 2951553Srgrimes printf("%s: Permission denied\n", file); 2961553Srgrimes return(0); 2971553Srgrimes} 2981553Srgrimes 2991553Srgrimes/* 3001553Srgrimes * Check to see if we are sending files to a remote machine. If we are, 3011553Srgrimes * then try removing files on the remote machine. 3021553Srgrimes */ 3031553Srgrimesvoid 30478146Sgadrmremote(const struct printer *pp) 3051553Srgrimes{ 30674126Sgad int i, elem, firstreq, niov, rem, totlen; 3071553Srgrimes char buf[BUFSIZ]; 30830407Sjoerg void (*savealrm)(int); 30931492Swollman struct iovec *iov; 3101553Srgrimes 31131492Swollman if (!pp->remote) 3121553Srgrimes return; /* not sending to a remote machine */ 3131553Srgrimes 3141553Srgrimes /* 3151553Srgrimes * Flush stdout so the user can see what has been deleted 3161553Srgrimes * while we wait (possibly) for the connection. 3171553Srgrimes */ 3181553Srgrimes fflush(stdout); 3191553Srgrimes 32031492Swollman /* 32131492Swollman * Counting: 32231492Swollman * 4 == "\5" + remote_queue + " " + person 32331492Swollman * 2 * users == " " + user[i] for each user 32431492Swollman * requests == asprintf results for each request 32531492Swollman * 1 == "\n" 32631492Swollman * Although laborious, doing it this way makes it possible for 32731492Swollman * us to process requests of indeterminate length without 32831492Swollman * applying an arbitrary limit. Arbitrary Limits Are Bad (tm). 32931492Swollman */ 33074126Sgad if (users > 0) 33174126Sgad niov = 4 + 2 * users + requests + 1; 33274126Sgad else 33374126Sgad niov = 4 + requests + 1; 33431492Swollman iov = malloc(niov * sizeof *iov); 33531492Swollman if (iov == 0) 33674126Sgad fatal(pp, "out of memory in rmremote()"); 33731492Swollman iov[0].iov_base = "\5"; 33831492Swollman iov[1].iov_base = pp->remote_queue; 33931492Swollman iov[2].iov_base = " "; 34031492Swollman iov[3].iov_base = all ? "-all" : person; 34174126Sgad elem = 4; 34231492Swollman for (i = 0; i < users; i++) { 34374126Sgad iov[elem].iov_base = " "; 34474126Sgad iov[elem + 1].iov_base = user[i]; 34574126Sgad elem += 2; 3461553Srgrimes } 34774126Sgad firstreq = elem; 34831492Swollman for (i = 0; i < requests; i++) { 349121525Speter asprintf((char **)&iov[elem].iov_base, " %d", requ[i]); 35074126Sgad if (iov[elem].iov_base == 0) 35174126Sgad fatal(pp, "out of memory in rmremote()"); 35274126Sgad elem++; 3531553Srgrimes } 35474126Sgad iov[elem++].iov_base = "\n"; 35531492Swollman for (totlen = i = 0; i < niov; i++) 35631492Swollman totlen += (iov[i].iov_len = strlen(iov[i].iov_base)); 35731492Swollman 35830407Sjoerg savealrm = signal(SIGALRM, alarmhandler); 35931492Swollman alarm(pp->conn_timeout); 36031492Swollman rem = getport(pp, pp->remote_host, 0); 36130407Sjoerg (void)signal(SIGALRM, savealrm); 3621553Srgrimes if (rem < 0) { 36378300Sgad if (from_host != local_host) 36478300Sgad printf("%s: ", local_host); 36531492Swollman printf("connection to %s is down\n", pp->remote_host); 3661553Srgrimes } else { 36731492Swollman if (writev(rem, iov, niov) != totlen) 36831492Swollman fatal(pp, "Lost connection"); 3691553Srgrimes while ((i = read(rem, buf, sizeof(buf))) > 0) 3701553Srgrimes (void) fwrite(buf, 1, i, stdout); 3711553Srgrimes (void) close(rem); 3721553Srgrimes } 37331492Swollman for (i = 0; i < requests; i++) 37474126Sgad free(iov[firstreq + i].iov_base); 37531492Swollman free(iov); 3761553Srgrimes} 3771553Srgrimes 3781553Srgrimes/* 3791553Srgrimes * Return 1 if the filename begins with 'cf' 3801553Srgrimes */ 3811553Srgrimesint 382201512Skibiscf(const struct dirent *d) 3831553Srgrimes{ 3841553Srgrimes return(d->d_name[0] == 'c' && d->d_name[1] == 'f'); 3851553Srgrimes} 38630407Sjoerg 38730407Sjoergvoid 38878146Sgadalarmhandler(int signo __unused) 38930407Sjoerg{ 39078146Sgad /* the signal is ignored */ 39178146Sgad /* (the '__unused' is just to avoid a compile-time warning) */ 39230407Sjoerg} 393