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