bug-coreutils
[Top][All Lists]
Advanced

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

Port to Solaris 10's rules for whether programs can chown files


From: Paul Eggert
Subject: Port to Solaris 10's rules for whether programs can chown files
Date: Mon, 30 May 2005 23:28:54 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.4 (gnu/linux)

Inspired by the recent change to support Solaris 10's privilege
functions with respect to unlinking directories, I noticed another use
of geteuid.  In this case it was used to decide whether programs
should be able to chown files.  I installed this patch to handle the
case where a non-root process has that privilege, or a root process
lacks it.  This shouldn't change behavior of coreutils except on
Solaris-10-like systems.  (And I like to think that this change cleans
up the code a little, even on GNU systems.)

2005-05-30  Paul Eggert  <address@hidden>

        Port to Solaris 10's rules for whether programs can chown files.
        * m4/jm-macros.m4 (gl_CHECK_ALL_HEADERS): Check for priv.h.
        * src/copy.c [HAVE_PRIV_H]: Include <priv.h>.
        (DO_CHOWN): Remove.  Replaced by chown_failure_ok.  All callers
        changed.
        (copy_internal): If chown failed, don't worry about what happened
        to the mode bits; they can't have changed.
        (chown_privileges, chown_failure_ok): New functions.
        * src/copy.h: Add copyright notice.
        (struct cp_options): Remove myeuid member.  Add chown_privileges
        member.
        (chown_privileges, chown_failure_ok): New function decls.
        * src/cp.c (re_protect): Remove unnecessary call to geteuid.
        Use chown_failure_ok rather than our own code.
        * src/cp.c (cp_options_init): Use chown_privileges rather than geteuid.
        * src/install.c (cp_option_init): Likewise.
        * src/mv.c (cp_option_init): Likewise.

Index: m4/jm-macros.m4
===================================================================
RCS file: /fetish/cu/m4/jm-macros.m4,v
retrieving revision 1.216
diff -p -u -r1.216 jm-macros.m4
--- m4/jm-macros.m4     18 May 2005 19:31:00 -0000      1.216
+++ m4/jm-macros.m4     31 May 2005 06:08:15 -0000
@@ -1,4 +1,4 @@
-#serial 87   -*- autoconf -*-
+#serial 88   -*- autoconf -*-
 
 dnl Misc type-related macros for coreutils.
 
@@ -189,6 +189,7 @@ AC_DEFUN([gl_CHECK_ALL_HEADERS],
     mnttab.h \
     netdb.h \
     paths.h \
+    priv.h \
     stdlib.h \
     stdint.h \
     string.h \
Index: src/copy.c
===================================================================
RCS file: /fetish/cu/src/copy.c,v
retrieving revision 1.182
diff -p -u -r1.182 copy.c
--- src/copy.c  14 May 2005 07:58:36 -0000      1.182
+++ src/copy.c  31 May 2005 06:08:16 -0000
@@ -25,6 +25,9 @@
 #if HAVE_HURD_H
 # include <hurd.h>
 #endif
+#if HAVE_PRIV_H
+# include <priv.h>
+#endif
 
 #include "system.h"
 #include "backupfile.h"
@@ -47,13 +50,6 @@
 #include "xreadlink.h"
 #include "yesno.h"
 
-#define DO_CHOWN(Chown, File, New_uid, New_gid)                                
\
-  (Chown (File, New_uid, New_gid)                                      \
-   /* If non-root uses -p, it's ok if we can't preserve ownership.     \
-      But root probably wants to know, e.g. if NFS disallows it,       \
-      or if the target system doesn't support file ownership.  */      \
-   && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0))
-
 #define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid)
 #define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid)
 #define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B))
@@ -848,7 +844,7 @@ copy_internal (const char *src_path, con
   bool backup_succeeded = false;
   bool delayed_ok;
   bool copied_as_regular = false;
-  bool ran_chown = false;
+  bool chown_succeeded = false;
   bool preserve_metadata;
 
   if (x->move_mode && rename_succeeded)
@@ -1530,7 +1526,8 @@ copy_internal (const char *src_path, con
          /* Preserve the owner and group of the just-`copied'
             symbolic link, if possible.  */
 # if HAVE_LCHOWN
-         if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid))
+         if (lchown (dst_path, src_sb.st_uid, src_sb.st_gid) != 0
+             && ! chown_failure_ok (x))
            {
              error (0, errno, _("failed to preserve ownership for %s"),
                     dst_path);
@@ -1590,8 +1587,9 @@ copy_internal (const char *src_path, con
   if (x->preserve_ownership
       && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb)))
     {
-      ran_chown = true;
-      if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid))
+      if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) == 0)
+       chown_succeeded = true;
+      else if (! chown_failure_ok (x))
        {
          error (0, errno, _("failed to preserve ownership for %s"),
                 quote (dst_path));
@@ -1619,9 +1617,9 @@ copy_internal (const char *src_path, con
 
   /* Permissions of newly-created regular files were set upon `open' in
      copy_reg.  But don't return early if there were any special bits and
-     we had to run chown, because the chown must have reset those bits.  */
+     chown succeeded, because the chown must have reset those bits.  */
   if ((new_dst && copied_as_regular)
-      && !(ran_chown && (src_mode & ~S_IRWXUGO)))
+      && !(chown_succeeded && (src_mode & ~S_IRWXUGO)))
     return delayed_ok;
 
   if ((x->preserve_mode || new_dst)
@@ -1701,3 +1699,37 @@ copy (const char *src_path, const char *
   return copy_internal (src_path, dst_path, nonexistent_dst, 0, NULL,
                        options, true, copy_into_self, rename_succeeded);
 }
+
+/* Return true if this process has appropriate privileges to chown a
+   file whose owner is not the effective user ID.  */
+
+bool
+chown_privileges (void)
+{
+#ifdef PRIV_FILE_CHOWN
+  bool result;
+  priv_set_t *pset = priv_allocset ();
+  if (!pset)
+    xalloc_die ();
+  result = (getppriv (PRIV_EFFECTIVE, pset) == 0
+           && priv_ismember (pset, PRIV_FILE_CHOWN));
+  priv_freeset (pset);
+  return result;
+#else
+  return (geteuid () == 0);
+#endif
+}
+
+/* Return true if it's OK for chown to fail, where errno is
+   the error number that chown failed with and X is the copying
+   option set.  */
+
+bool
+chown_failure_ok (struct cp_options const *x)
+{
+  /* If non-root uses -p, it's ok if we can't preserve ownership.
+     But root probably wants to know, e.g. if NFS disallows it,
+     or if the target system doesn't support file ownership.  */
+
+  return ((errno == EPERM || errno == EINVAL) && !x->chown_privileges);
+}
Index: src/copy.h
===================================================================
RCS file: /fetish/cu/src/copy.h,v
retrieving revision 1.31
diff -p -u -r1.31 copy.h
--- src/copy.h  26 Nov 2004 07:39:14 -0000      1.31
+++ src/copy.h  31 May 2005 06:08:16 -0000
@@ -1,3 +1,22 @@
+/* core functions for copying files and directories
+   Copyright (C) 89, 90, 91, 1995-2005 Free Software Foundation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Extracted from cp.c and librarified by Jim Meyering.  */
+
 #ifndef COPY_H
 # define COPY_H
 
@@ -94,8 +113,9 @@ struct cp_options
      If that fails, then resort to copying.  */
   bool move_mode;
 
-  /* This process's effective user ID.  */
-  uid_t myeuid;
+  /* Whether this process has appropriate privileges to chown a file
+     whose owner is not the effective user ID.  */
+  bool chown_privileges;
 
   /* If true, when copying recursively, skip any subdirectories that are
      on different file systems from the one we started on.  */
@@ -195,14 +215,14 @@ int rpl_rename (const char *, const char
 #  define rename rpl_rename
 # endif
 
-bool
-copy (const char *src_path, const char *dst_path,
-      bool nonexistent_dst, const struct cp_options *options,
-      bool *copy_into_self, bool *rename_succeeded);
-
-void
-dest_info_init (struct cp_options *);
-void
-src_info_init (struct cp_options *);
+bool copy (const char *src_path, const char *dst_path,
+          bool nonexistent_dst, const struct cp_options *options,
+          bool *copy_into_self, bool *rename_succeeded);
+
+void dest_info_init (struct cp_options *);
+void src_info_init (struct cp_options *);
+
+bool chown_privileges (void);
+bool chown_failure_ok (struct cp_options const *);
 
 #endif
Index: src/cp.c
===================================================================
RCS file: /fetish/cu/src/cp.c,v
retrieving revision 1.209
diff -p -u -r1.209 cp.c
--- src/cp.c    30 May 2005 07:32:16 -0000      1.209
+++ src/cp.c    31 May 2005 06:08:16 -0000
@@ -281,7 +281,6 @@ re_protect (const char *const_dst_path, 
   struct dir_attr *p;
   char *dst_path;              /* A copy of CONST_DST_PATH we can change. */
   char *src_path;              /* The source name in `dst_path'. */
-  uid_t myeuid = geteuid ();
 
   ASSIGN_STRDUPA (dst_path, const_dst_path);
   src_path = dst_path + src_offset;
@@ -322,11 +321,8 @@ re_protect (const char *const_dst_path, 
 
       if (x->preserve_ownership)
        {
-         /* If non-root uses -p, it's ok if we can't preserve ownership.
-            But root probably wants to know, e.g. if NFS disallows it,
-            or if the target system doesn't support file ownership.  */
-         if (chown (dst_path, src_sb.st_uid, src_sb.st_gid)
-             && ((errno != EPERM && errno != EINVAL) || myeuid == 0))
+         if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) != 0
+             && ! chown_failure_ok (x))
            {
              error (0, errno, _("failed to preserve ownership for %s"),
                     quote (dst_path));
@@ -683,7 +679,7 @@ cp_option_init (struct cp_options *x)
   x->unlink_dest_after_failed_open = false;
   x->hard_link = false;
   x->interactive = I_UNSPECIFIED;
-  x->myeuid = geteuid ();
+  x->chown_privileges = chown_privileges ();
   x->move_mode = false;
   x->one_file_system = false;
 
Index: src/install.c
===================================================================
RCS file: /fetish/cu/src/install.c,v
retrieving revision 1.177
diff -p -u -r1.177 install.c
--- src/install.c       30 May 2005 07:33:16 -0000      1.177
+++ src/install.c       31 May 2005 06:08:16 -0000
@@ -134,7 +134,7 @@ cp_option_init (struct cp_options *x)
   x->hard_link = false;
   x->interactive = I_UNSPECIFIED;
   x->move_mode = false;
-  x->myeuid = geteuid ();
+  x->chown_privileges = chown_privileges ();
   x->one_file_system = false;
   x->preserve_ownership = false;
   x->preserve_links = false;
Index: src/mv.c
===================================================================
RCS file: /fetish/cu/src/mv.c,v
retrieving revision 1.165
diff -p -u -r1.165 mv.c
--- src/mv.c    14 May 2005 07:58:37 -0000      1.165
+++ src/mv.c    31 May 2005 06:08:16 -0000
@@ -121,7 +121,7 @@ cp_option_init (struct cp_options *x)
   x->hard_link = false;
   x->interactive = I_UNSPECIFIED;
   x->move_mode = true;
-  x->myeuid = geteuid ();
+  x->chown_privileges = chown_privileges ();
   x->one_file_system = false;
   x->preserve_ownership = true;
   x->preserve_links = true;




reply via email to

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