Date: Fri, 14 Jan 2000 14:15:24 -0500 (EST) From: Garance A Drosehn <gad@santropez.acs.rpi.edu> To: FreeBSD-gnats-submit@freebsd.org Cc: gad@eclipse.acs.rpi.edu Subject: bin/16124: [PATCH] Enhancement for 'lpr -r' Message-ID: <200001141915.OAA18217@santropez.acs.rpi.edu>
next in thread | raw e-mail | index | archive | help
>Number: 16124 >Category: bin >Synopsis: [PATCH] Enhancement for 'lpr -r' >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Jan 14 11:20:00 PST 2000 >Closed-Date: >Last-Modified: >Originator: Garance A Drosehn >Release: FreeBSD 3.2-RELEASE i386 >Organization: Rensselaer Polytechnic Institute, Troy, NY >Environment: Any version of lpr. >Description: This is a follow-up to PR bin/11997. The goal of this enhancement is to save significant time and disk space processing large print jobs coming via mechanisms like samba. These are often configured to copy the (large) print file into a spool directory, and they then run 'lpr -r' to actually print the job. This change causes 'lpr -r' to simply move the spool file (if possible) instead of copying the entire file (thus giving you two copies in your spool directory for a moment) only to remove the original. The update given in bin/11997 had security issues. This version implements the enhancement without opening any security holes. Note this includes a few checks which are redundant under FreeBSD, but important if compiling this version of lpr under other OS's. >How-To-Repeat: >Fix: Here is the new, improved patch. This is based on the version of lpr.c found in freebsd-current as of Dec 23rd 1999. Index: lpr/lpr.c =================================================================== RCS file: /Users/cvsdepot/lpr-fbsd/lpr/lpr.c,v retrieving revision 1.1.1.1 diff -U5 -r1.1.1.1 lpr.c --- lpr.c 1999/11/30 16:15:22 1.1.1.1 +++ lpr.c 1999/12/27 21:58:39 @@ -382,10 +382,69 @@ nact++; continue; } if (sflag) printf("%s: %s: not linked, copying instead\n", name, arg); + + if (f) { + /* + * The user wants the file removed after it is copied, + * so see if it can be mv'ed instead of copy/unlink'ed. + * This will be much faster and better than copying the + * file, especially for larger files. Can be very + * useful for services like samba, pcnfs, CAP, et al. + */ + int ret, didlink; + struct stat statb2; + seteuid(euid); + didlink = 0; + /* don't do this if the user's file is a symlink */ + if (lstat(arg, &statb) < 0) goto nohardlink; + if (S_ISLNK(statb.st_mode)) goto nohardlink; + /* if the attempt to link fails, abandon the move */ + if (link(arg, dfname) != 0) goto nohardlink; + didlink = 1; + /* make sure the user hasn't tried to trick us via + * any race conditions */ + if (lstat(dfname, &statb2) < 0) goto nohardlink; + if (statb.st_dev != statb2.st_dev) goto nohardlink; + if (statb.st_ino != statb2.st_ino) goto nohardlink; + /* skip if the file already had multiple hard links, + * because changing the owner and access-bits would + * change ALL versions of the file */ + if (statb2.st_nlink > 2) goto nohardlink; + + /* if we can access and remove the given file without + * special setuid-ness then this method is safe. */ + seteuid(uid); + ret = access(dfname, R_OK); + if (ret == 0) + ret = unlink(arg); + seteuid(euid); + /* the user does not have access to read or remove + * this file, so abandon the move and fall back to + * the usual (copy) methods. */ + if (ret != 0) goto nohardlink; + + /* unlink of user file was successful. fixup perms, + * add entries to control file, and skip copy step */ + chown(dfname, pp->daemon_user, getegid()); + chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + seteuid(uid); + if (format == 'p') + card('T', title ? title : arg); + for (i = 0; i < ncopies; i++) + card(format, &dfname[inchar-2]); + card('U', &dfname[inchar-2]); + card('N', arg); + nact++; + continue; +nohardlink: + if (didlink) unlink(dfname); + seteuid(uid); /* restore old uid */ + } /* end: if (f) */ + if ((i = open(arg, O_RDONLY)) < 0) { printf("%s: cannot open %s\n", name, arg); } else { copy(pp, i, arg); (void) close(i); =================================================================== >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200001141915.OAA18217>