At 2:33 AM -0800 12/10/99, Alfred Perlstein wrote:
>Can someone take a look at this?
>
>Basically, it makes the link to the file, if it can unlink the original
>it will then chown the spool file if it can't delete or read the original
>then the user didn't have permission and it backs out.
Okay, I've finally gotten back to this and come up with an alternate
version, which I think should be pretty safe. It includes some checks
which are probably redundant for freebsd, but which would be necessary
on some other platforms I use this on.
It's basically Alfred's code, with a few more checks for symlinks
and to make sure race conditions can't trick us. If no problems
are found with this, I'll submit it as a PR follow-on to #bin/11997
Pardon the difference in version-numbering, I probably don't have
CVS setup exactly right for version numbers to match freebsd's...
Index: 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/23 23:31:43
@@ -382,10 +382,65 @@
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;
+
+ /* 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, userid, 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);
===================================================================
---
Garance Alistair Drosehn = [EMAIL PROTECTED]
Senior Systems Programmer or [EMAIL PROTECTED]
Rensselaer Polytechnic Institute
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message