Hi,

I'm attaching the patch we use at the moment. We try to keep our patches
as small as possible, so it is a bit Solaris specific. If you think that
this could be merged into gzip tree, I'm happy to work on more generic
approach - configure testing availability of new headers and functions
used.

Thank you
-- 
        Vlad
--- gzip-1.5/gzip.c     Tue Apr 24 16:25:28 2012
+++ gzip-1.5/gzip.c     Mon Oct 21 09:32:07 2013
@@ -83,6 +83,10 @@
 #include <stdlib.h>
 #include <errno.h>
 
+#ifdef __sun
+# include <priv.h>
+#endif
+
 #ifndef NO_DIR
 # define NO_DIR 0
 #endif
@@ -1694,6 +1698,10 @@
 {
     mode_t mode = ifstat->st_mode & S_IRWXUGO;
     int r;
+#ifdef __sun
+    int swap_chmod_chown;
+    priv_set_t *priv_set;
+#endif /* __sun */
 
 #ifndef NO_UTIME
     struct timespec timespec[2];
@@ -1722,6 +1730,40 @@
       }
 #endif
 
+#ifdef __sun
+    /* If the user is able to change ownership of his file to someone else,
+     * the chmod executed just after that may fail. In such case we need to
+     * swap chown and chmod operation. On Solaris there are two
+     * ways how to achieve this situation
+     *
+     * a) norstchown mount option
+     * b) file_chown_self user privilege.
+     *
+     * If one of the two options is met, we need to change the order of chmod
+     * and chown operation. Otherwise we first chown the file to second user
+     * and might not have permissions to chmod it afterwards.
+     *
+     * We detect whether the filesystem in question is mounted with norstchown
+     * option by checking that pathconf returns -1 but errno is 0.
+     *
+     * We detect whether current user has file_chown_self by priv_ismember
+     * function.
+     */
+    swap_chmod_chown = pathconf(ifname, _PC_CHOWN_RESTRICTED) == -1 && errno 
== 0;
+    if (!swap_chmod_chown) {
+        priv_set = priv_allocset();
+        if (priv_set == NULL) {
+            WARN((stderr, "priv_allocset can't allocate memory"));
+        } else {
+            getppriv(PRIV_EFFECTIVE, priv_set);
+            swap_chmod_chown = priv_ismember(priv_set, PRIV_FILE_CHOWN_SELF);
+            priv_freeset(priv_set);
+        }
+    }
+
+    if (!swap_chmod_chown) {
+#endif /* __sun */
+
 #ifndef NO_CHOWN
     /* Copy ownership */
 # if HAVE_FCHOWN
@@ -1731,6 +1773,10 @@
 # endif
 #endif
 
+#ifdef __sun
+    }
+#endif /* __sun */
+
     /* Copy the protection modes */
 #if HAVE_FCHMOD
     r = fchmod (ofd, mode);
@@ -1745,6 +1791,19 @@
             perror(ofname);
         }
     }
+
+#ifdef __sun
+    if (swap_chmod_chown) {
+#ifndef NO_CHOWN
+      /* Copy ownership */
+# if HAVE_FCHOWN
+      ignore_value (fchown (ofd, ifstat->st_uid, ifstat->st_gid));
+# elif HAVE_CHOWN
+      ignore_value (chown (ofname, ifstat->st_uid, ifstat->st_gid));
+# endif
+#endif
+    }
+#endif /* __sun */
 }
 
 #if ! NO_DIR

Reply via email to