bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Readable files: a Unix philosophy question for gurus


From: Jim Meyering
Subject: Re: Readable files: a Unix philosophy question for gurus
Date: Mon, 10 Feb 2003 14:27:27 +0100

Paul Eggert <eggert@twinsun.com> wrote:
>> From: Jim Meyering <jim@meyering.net>
>> Date: Sun, 09 Feb 2003 10:14:32 +0100
>>
>> There is indeed a problem with the `test' in the coreutils --
>> and with the nearly identical built-in provided by bash.
>> I've just changed the one in coreutils to use euidaccess
>> (either the one in libc, or the supplied replacement).
>> That solves the problem only in the (albeit common) case
>> in which effective and actual UID and GID are identical.
>
> As I understand it, the euidaccess replacement attempts to guess what
> 'access' would return if the real uid and gid were temporarily set to
> the effective uid and gid.  This guess can be wrong for many reasons

Exactly.  As you probably noticed, coreutils' replacement lib/euidaccess.c
is essentially the same as glibc's sysdeps/posix/euidaccess.c.

> (e.g., ACLs, read-only filesystems, etc.), andit would be a
> maintenance hassle to improve the guess's quality on all systems.
>
> Wouldn't it be easier to set the real uid and gid temporarily to the
> effective uid and gid, then invoke 'access', and then set the real uid
> and gid back?  This method will handle all that nonportable ACL
> etc. stuff automatically.  The method won't work on all ancient hosts,
> but it'll work on all modern ones and we can fall back on the current
> euidaccess method if we're on an ancient host.  Also, I suppose this
> method would be a pain if you need euidaccess to be reentrant, but
> test(1) shouldn't need that.

I like that.  Thanks!
How about this change?

2003-02-10  Jim Meyering  <jim@meyering.net>

        * src/test.c (eaccess): Rewrite function to set the real uid and gid
        temporarily to the effective uid and gid, then invoke 'access', and
        then set the real uid and gid back.  On systems that lack setreuid
        or setregid, fall back on the kludges in euidaccess.
        Before, it would not work for e.g., files with ACLs, files that were
        marked immutable, or on file systems mounted read-only.
        Nelson Beebe raised the issue.
        Paul Eggert suggested the new implementation.

Index: test.c
===================================================================
RCS file: /fetish/cu/src/test.c,v
retrieving revision 1.81
retrieving revision 1.83
diff -u -p -r1.81 -r1.83
--- test.c      9 Feb 2003 08:28:59 -0000       1.81
+++ test.c      10 Feb 2003 13:19:00 -0000      1.83
@@ -39,8 +39,8 @@
 # include "filecntl.h"
 #else /* TEST_STANDALONE */
 # include "system.h"
-# include "group-member.h"
 # include "error.h"
+# include "euidaccess.h"
 # if !defined (S_IXUGO)
 #  define S_IXUGO 0111
 # endif /* S_IXUGO */
@@ -135,43 +135,45 @@ test_syntax_error (char const *format, c
   test_exit (SHELL_BOOLEAN (FALSE));
 }
 
-/* Do the same thing access(2) does, but use the effective uid and gid,
-   and don't make the mistake of telling root that any file is executable.
-   But this loses when the containing filesystem is mounted e.g. read-only.  */
+#if HAVE_SETREUID && HAVE_SETREGID
+/* Do the same thing access(2) does, but use the effective uid and gid.  */
+
 static int
-eaccess (char *path, int mode)
+eaccess (char const *file, int mode)
 {
-  struct stat st;
-  static uid_t euid = -1;
-
-  if (stat (path, &st) < 0)
-    return (-1);
-
-  if (euid == (uid_t) -1)
-    euid = geteuid ();
+  static int have_ids;
+  static uid_t uid, euid;
+  static gid_t gid, egid;
+  int result;
 
-  if (euid == 0)
+  if (have_ids == 0)
     {
-      /* Root can read or write any file. */
-      if (mode != X_OK)
-       return (0);
-
-      /* Root can execute any file that has any one of the execute
-        bits set. */
-      if (st.st_mode & S_IXUGO)
-       return (0);
+      have_ids = 1;
+      uid = getuid ();
+      gid = getgid ();
+      euid = geteuid ();
+      egid = getegid ();
     }
 
-  if (st.st_uid == euid)        /* owner */
-    mode <<= 6;
-  else if (group_member (st.st_gid))
-    mode <<= 3;
+  /* Set the real user and group IDs to the effective ones.  */
+  if (uid != euid)
+    setreuid (euid, uid);
+  if (gid != egid)
+    setregid (egid, gid);
+
+  result = access (file, mode);
+
+  /* Restore them.  */
+  if (uid != euid)
+    setreuid (uid, euid);
+  if (gid != egid)
+    setregid (gid, egid);
 
-  if (st.st_mode & mode)
-    return (0);
-
-  return (-1);
+  return result;
 }
+#else
+# define eaccess(F, M) euidaccess (F, M)
+#endif
 
 /* Increment our position in the argument list.  Check that we're not
    past the end of the argument list.  This check is supressed if the




reply via email to

[Prev in Thread] Current Thread [Next in Thread]