Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Jun 2001 18:01:31 -0400
From:      Garance A Drosihn <drosih@rpi.edu>
To:        freebsd-print@bostonradio.org
Cc:        freebsd-audit@FreeBSD.ORG
Subject:   Re: Patch: smarter 'lpc clean', new 'lpc tclean'
Message-ID:  <p05101005b75815833881@[128.113.24.47]>
In-Reply-To: <p05100e12b754415778b5@[128.113.24.47]>
References:  <p05100e12b754415778b5@[128.113.24.47]>

next in thread | previous in thread | raw e-mail | index | archive | help
At 8:53 PM -0400 6/18/01, Garance A Drosihn wrote:
>Main goals of this update to lpc (part of lpr & friends):
>
>  1) make 'lpc clean' somewhat safer
>  2) add an 'lpc tclean', which allows one to see what files would be
>     removed *if* an 'lpc clean' is done.  Note that 'lpc tclean' is
>     not a privileged command, since it won't actually remove anything.
>  3) have 'lpc clean' and 'lpc tclean' also look for core files
>     in spool directories.
>  4) make 'lpc clean' somewhat prettier and more informative.
>  5) get rid of some more compile-type warnings when BDECFLAGS is used
>     (mainly by fixing up cmdtab.c).
>  6) as part of creating 'lpc clean' from 'lpc tclean', make it possible
>     for "generic printer" routines to have an initialization routine
>     which can set initial values of global variables, or even do some
>     processing of command-line options.  It can also set a "wrap-up"
>     routine, which could be used to print summary information.
>
>This is cross-posted to freebsd-audit since the 'lpc' command is
>setgid daemon.  (and at least at RPI, it's often run via 'sudo').  It
>wouldn't hurt to be a little extra paranoid while eyeing these changes...

I have a newer version of the update available at:

http://freefour.acs.rpi.edu/pub/bsdlpr/lpc-clean.diff
and
http://people.freebsd.org/~gad/lpr/lpc-clean.diff

It includes a change for the man page.  Most of the rest of the
update is just minor cleanups from my previous version.  I hope
to commit this to current this weekend, assuming no one has any
feedback about it.

The update is a little over 600 lines, so I wasn't sure if I should
post the entire thing all over again.  The 'unlinkf' routine has seen
the most change, so here's just that part of the patch for people to
eyeball:


  static void
  unlinkf(char *name)
  {
+	struct stat stbuf;
+	double agemod, agestat;
+	int res;
+	char linkbuf[BUFSIZ];
+
+	/*
+	 * We have to use lstat() instead of stat(), in case this is a df*
+	 * "file" which is really a symlink due to 'lpr -s' processing.  In
+	 * that case, we need to check the last-mod time of the symlink, and
+	 * not the file that the symlink is pointed at.
+	 */
  	seteuid(euid);
-	if (unlink(name) < 0)
-		printf("\tcannot remove %s\n", name);
-	else
-		printf("\tremoved %s\n", name);
+	res = lstat(name, &stbuf);
  	seteuid(uid);
+	if (res < 0) {
+		printf("\terror return from stat(%s):\n", name);
+		printf("\t      %s\n", strerror(errno));
+		return;
+	}
+
+	agemod = difftime(cln_now, stbuf.st_mtime);
+	agestat = difftime(cln_now,  stbuf.st_ctime);
+	if (cln_debug) {
+		/* this debugging-aid probably is not needed any more... */
+		printf("\t\t  modify age=%g secs, stat age=%g secs\n",
+		    agemod, agestat);
+	}
+	if ((agemod <= cln_minage) && (agestat <= cln_minage))
+		return;
+
+	/*
+	 * if this file is a symlink, then find out the target of the
+	 * symlink before unlink-ing the file itself
+	 */
+	if (S_ISLNK(stbuf.st_mode)) {
+		seteuid(euid);
+		res = readlink(name, linkbuf, sizeof(linkbuf));
+		seteuid(uid);
+		if (res < 0) {
+			printf("\terror return from readlink(%s):\n", name);
+			printf("\t      %s\n", strerror(errno));
+			return;
+		}
+		if (res == sizeof(linkbuf))
+			res--;
+		linkbuf[res] = '\0';
+	}
+
+	cln_filecnt++;
+	cln_sizecnt += stbuf.st_size;
+
+	if (cln_testonly) {
+		printf("\twould remove %s\n", name);
+		if (S_ISLNK(stbuf.st_mode)) {
+			printf("\t    (which is a symlink to %s)\n", linkbuf);
+		}
+	} else {
+		seteuid(euid);
+		res = unlink(name);
+		seteuid(uid);
+		if (res < 0)
+			printf("\tcannot remove %s (!)\n", name);
+		else
+			printf("\tremoved %s\n", name);
+		/* XXX
+		 *  Note that for a df* file, this code should also 
check to see
+		 *  if it is a symlink to some other file, and if the original
+		 *  lpr command included '-r' ("remove file").  Of course, this
+		 *  code would not be removing the df* file unless there was no
+		 *  matching cf* file, and without the cf* file it is currently
+		 *  impossible to determine if '-r' had been specified...
+		 *
+		 *  As a result of this quandary, we may be leaving behind a
+		 *  user's file that was supposed to have been removed after
+		 *  being printed.  This may effect services such as CAP or
+		 *  samba, if they were configured to use 'lpr -r', and if
+		 *  datafiles are not being properly removed.
+		*/
+		if (S_ISLNK(stbuf.st_mode)) {
+			printf("\t    (which was a symlink to %s)\n", linkbuf);
+		}
+	}
  }

  /*


-- 
Garance Alistair Drosehn            =   gad@eclipse.acs.rpi.edu
Senior Systems Programmer           or  gad@freebsd.org
Rensselaer Polytechnic Institute    or  drosih@rpi.edu

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?p05101005b75815833881>