From gad@santropez.acs.rpi.edu  Fri Jan 14 11:19:25 2000
Return-Path: <gad@santropez.acs.rpi.edu>
Received: from santropez.acs.rpi.edu (santropez.acs.rpi.edu [128.113.24.162])
	by hub.freebsd.org (Postfix) with ESMTP id 38323156F4
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 14 Jan 2000 11:15:54 -0800 (PST)
	(envelope-from gad@santropez.acs.rpi.edu)
Received: (from gad@localhost)
	by santropez.acs.rpi.edu (8.9.3/8.9.3) id OAA18217;
	Fri, 14 Jan 2000 14:15:24 -0500 (EST)
	(envelope-from gad)
Message-Id: <200001141915.OAA18217@santropez.acs.rpi.edu>
Date: Fri, 14 Jan 2000 14:15:24 -0500 (EST)
From: Garance A Drosehn <gad@santropez.acs.rpi.edu>
Reply-To: gad@eclipse.acs.rpi.edu
To: FreeBSD-gnats-submit@freebsd.org
Cc: gad@eclipse.acs.rpi.edu
Subject: [PATCH] Enhancement for 'lpr -r'
X-Send-Pr-Version: 3.2

>Number:         16124
>Category:       bin
>Synopsis:       [MFC] [PATCH] Enhancement for 'lpr -r'
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    gad
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jan 14 11:20:00 PST 2000
>Closed-Date:    Wed Dec 27 09:24:27 PST 2000
>Last-Modified:  Wed Dec 27 09:25:02 PST 2000
>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:

From: Andre Albsmeier <andre.albsmeier@mchp.siemens.de>
To: gad@eclipse.acs.rpi.edu
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/16124: [PATCH] Enhancement for 'lpr -r'
Date: Tue, 18 Jan 2000 22:53:20 +0100

 On Fri, 14-Jan-2000 at 14:15:24 -0500, Garance A Drosehn wrote:
 > 
 > >Number:         16124
 > >Category:       bin
 > >Synopsis:       [PATCH] Enhancement for 'lpr -r'
 > >Confidential:   no
 
 Thanks a lot for your work. Hopefully, someone commits it soon...
 
 	-Andre
 
Responsible-Changed-From-To: freebsd-bugs->alfred 
Responsible-Changed-By: sheldonh 
Responsible-Changed-When: Tue Jan 18 15:17:25 PST 2000 
Responsible-Changed-Why:  
This addresses the race condition that led you to suspend 
PR 11997.  Perhaps you'd be interested in looking at this 
when we're out of feature freeze? :-) 
. 
Responsible-Changed-From-To: alfred->freebsd-bugs 
Responsible-Changed-By: wollman 
Responsible-Changed-When: Thu May 4 18:09:03 PDT 2000 
Responsible-Changed-Why:  
Submitter says alfred didn't do anything about it. 

From: Garance A Drosehn <gad@freefour.acs.rpi.edu>
To: freebsd-gnats-submit@FreeBSD.org
Cc: gad@eclipse.acs.rpi.edu
Subject: Re: bin/16124: [PATCH] Enhancement for 'lpr -r'
Date: Tue, 9 May 2000 23:29:54 -0400 (EDT)

 I wanted to improve some of the comments in this update, and thought
 I could justify that by also getting it bit closer to 'man style'
 conventions.  Here is the spruced-up version.
 
 I am not sure the patch will come thru the email correctly, so I'll
 also mention that it's available at:
 
 ftp://freefour.acs.rpi.edu/pub/bsdlpr/lpr-mv.diff
 
 [start] = = = = = = = = = = = = = = = = = [start]
 --- lpr.c.orig	Wed Jan 19 09:25:08 2000
 +++ lpr.c	Tue May  9 22:34:33 2000
 @@ -384,6 +384,81 @@
  		}
  		if (sflag)
  			printf("%s: %s: not linked, copying instead\n", name, arg);
 +
 +		if (f) {
 +			/*
 +			 * The user wants the file removed after it is copied
 +			 * to the spool area, so see if the file can be moved
 +			 * instead of copy/unlink'ed.  This is much faster and
 +			 * uses less spool space than copying the file.  This
 +			 * can be very significant when running services like
 +			 * samba, pcnfs, CAP, et al.
 +			 */
 +			int ret, didlink;
 +			struct stat statb1, statb2;
 +			seteuid(euid);
 +			didlink = 0;
 +			/*
 +			 * There are several things to check to avoid any
 +			 * security issues.  Some of these are redundant
 +			 * under BSD's, but are necessary when lpr is built
 +			 * under some other OS's (which I do do...)
 +			 */
 +			if (lstat(arg, &statb1) < 0)
 +				goto nohardlink;
 +			if (S_ISLNK(statb1.st_mode))
 +				goto nohardlink;
 +			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 (statb1.st_dev != statb2.st_dev)
 +				goto nohardlink;
 +			if (statb1.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 original file
 +			 * without special setuid-ness then this method is
 +			 * safe.  Otherwise, abandon the move and fall back
 +			 * to the (usual) copy method.
 +			 */
 +			seteuid(uid);
 +			ret = access(dfname, R_OK);
 +			if (ret == 0)
 +				ret = unlink(arg);
 +			seteuid(euid);
 +			if (ret != 0)
 +				goto nohardlink;
 +			/*
 +			 * unlink of user file was successful.  Change the
 +			 * owner and permissions, add entries to the control
 +			 * file, and skip the file copying 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 {
 [end] = = = = = = = = = = = = = = = = = = = = = [end]
 
Responsible-Changed-From-To: freebsd-bugs->imp 
Responsible-Changed-By: imp 
Responsible-Changed-When: Mon May 15 23:42:39 MDT 2000 
Responsible-Changed-Why:  
I suppose I'll do it. 

From: Garance A Drosihn <drosih@rpi.edu>
To: freebsd-gnats-submit@FreeBSD.org
Cc: imp@FreeBSD.org
Subject: Re: bin/16124: [PATCH] Enhancement for 'lpr -r'
Date: Wed, 13 Sep 2000 00:35:04 -0400

 Back on May 15th, Warner gave this patch/pr a ringing
 endorsement by changing the status to:
 
      I suppose I'll do it.
 
 I thought I'd follow up at this fourth-month mark, and
 see if life is any less busy now then it was back then...
                 :-)
 
 
 ---
 Garance Alistair Drosehn           =   gad@eclipse.acs.rpi.edu
 Senior Systems Programmer          or  drosih@rpi.edu
 Rensselaer Polytechnic Institute
 

From: Warner Losh <imp@village.org>
To: Garance A Drosihn <drosih@rpi.edu>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/16124: [PATCH] Enhancement for 'lpr -r' 
Date: Tue, 12 Sep 2000 22:43:44 -0600

 In message <v04210103b5e4b34118ea@[128.113.24.47]> Garance A Drosihn writes:
 : Back on May 15th, Warner gave this patch/pr a ringing
 : endorsement by changing the status to:
 : 
 :      I suppose I'll do it.
 : 
 : I thought I'd follow up at this fourth-month mark, and
 : see if life is any less busy now then it was back then...
 :                 :-)
 
 Hey, I have 3 days before the 4 month anniversary  :-)
 
 Warner
 
Responsible-Changed-From-To: imp->gad 
Responsible-Changed-By: gad 
Responsible-Changed-When: Tue Oct 31 20:44:55 PST 2000 
Responsible-Changed-Why:  
Now that I have commit-ability, it seemed I should take over this PR. 
I already checked with Warner, and he gave the OK for it.  I will 
try committing my most-recent patch to do this soon, probably later 
this week.  (first I want to see if my edit-pr worked... :-) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=16124 
State-Changed-From-To: open->suspended 
State-Changed-By: gad 
State-Changed-When: Thu Nov 2 20:37:57 PST 2000 
State-Changed-Why:  
Patch applied (with minor style changes).  Awaiting MFC, after it has 
sat in current for awhile. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=16124 
State-Changed-From-To: suspended->closed 
State-Changed-By: gad 
State-Changed-When: Wed Dec 27 09:24:27 PST 2000 
State-Changed-Why:  
New feature has been added to both -current (5.x) and -stable (post 4.2) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=16124 
>Unformatted:
