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

Reply via email to