Writing metadata xattr on directories with sticky bit set, FR#94
authorRalph Boehme <rb@sernet.de>
Wed, 25 Jun 2014 09:46:03 +0000 (11:46 +0200)
committerRalph Boehme <rb@sernet.de>
Thu, 10 Jul 2014 16:03:07 +0000 (18:03 +0200)
Even though we may have write access to a directory, if the sticky bit
is set only the owner is allowed to write xattrs.

Add an option that enables behaviour to set the xattr as root, using
the fact that we can distinguish between a failing xattr set request
due to insufficient permissions (EACCES) or the sticky bit (EPERM):

  force xattr with sticky bit = yes|no (default: no)

Signed-off-by: Ralph Boehme <rb@sernet.de>
NEWS
doc/manpages/man5/afp.conf.5.xml
include/atalk/adouble.h
include/atalk/volume.h
libatalk/adouble/ad_flush.c
libatalk/util/netatalk_conf.c
man/man5/afp.conf.5.in

diff --git a/NEWS b/NEWS
index 9cf18b9..212272d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Changes in 3.1.4
 ================
 * FIX: afpd: Hangs in Netatalk which causes it to stop responding to
        connections, bug #572.
+* NEW: afpd: new option "force xattr with sticky bit = yes|no"
+       (default: no), FR #94
 
 Changes in 3.1.3
 ================
index a8b4378..44e083c 100644 (file)
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>force xattr with sticky bit =
+          <replaceable>BOOLEAN</replaceable> (default:
+          <emphasis>no</emphasis>) <type>(G/V)</type></term>
+
+          <listitem>
+            <para>Writing metadata xattr on directories with the
+            sticky bit set may fail even though we may have write
+            access to a directory, because if the sticky bit is set
+            only the owner is allowed to write xattrs.</para>
+
+            <para>By enabling this option Netatalk will write the
+            metadata xattr as root.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term>guest account = <replaceable>name</replaceable>
           <type>(G)</type></term>
index f279d28..40c92a1 100644 (file)
@@ -249,6 +249,7 @@ struct adouble {
 #define ADVOL_UNIXPRIV   (1 << 2) /* adouble unix priv */
 #define ADVOL_INVDOTS    (1 << 3) /* dot files (.DS_Store) are invisible) */
 #define ADVOL_FOLLO_SYML (1 << 4)
+#define ADVOL_FORCE_STICKY_XATTR (1 << 5)
 
 /* lock flags */
 #define ADLOCK_CLR      (0)
index 084f5a0..ad8be2b 100644 (file)
@@ -118,6 +118,7 @@ typedef enum {lv_none = 0, lv_all = 1} lv_flags_t;
 #define AFPVOL_RO        (1 << 8)   /* read-only volume */
 #define AFPVOL_CHMOD_PRESERVE_ACL (1 << 9) /* try to preserve ACLs */
 #define AFPVOL_CHMOD_IGNORE (1 << 10) /* try to preserve ACLs */
+#define AFPVOL_FORCE_STICKY_XATTR (1 << 11) /* write metadata xattr as root on sticky dirs */
 #define AFPVOL_NOSTAT    (1 << 16)  /* advertise the volume even if we can't stat() it
                                      * maybe because it will be mounted later in preexec */
 #define AFPVOL_UNIX_PRIV (1 << 17)  /* support unix privileges */
index 6a1900c..f049876 100644 (file)
@@ -286,8 +286,33 @@ static int ad_flush_hf(struct adouble *ad)
                 if (ad->ad_adflags & ADFLAGS_DIR) {
                     EC_NEG1_LOG( cwd = open(".", O_RDONLY) );
                     EC_NEG1_LOG( fchdir(ad_data_fileno(ad)) );
-                    EC_ZERO_LOGSTR( sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0),
-                                    "sys_lsetxattr(\"%s\"): %s", fullpathname(".") ,strerror(errno));
+
+                    ret = sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0);
+
+                    if (ret != 0) {
+                        if (errno != EPERM)
+                            EC_FAIL;
+
+                        if (!(ad->ad_options & ADVOL_FORCE_STICKY_XATTR))
+                            EC_FAIL;
+
+                        /*
+                         * This may be a directory with a sticky bit
+                         * set, which means even though we may have
+                         * write access to the directory, only the
+                         * owner is allowed to write xattrs
+                         */
+
+                        become_root();
+                        ret = sys_lsetxattr(".", AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0);
+                        unbecome_root();
+
+                        if (ret != 0) {
+                            LOG(log_error, logtype_ad, "ad_flush_hf: %s", strerror(errno));
+                            EC_FAIL;
+                        }
+                    }
+
                     EC_NEG1_LOG( fchdir(cwd) );
                     EC_NEG1_LOG( close(cwd) );
                     cwd = -1;
index 1a4f9fa..a1d2731 100644 (file)
@@ -841,6 +841,8 @@ static struct vol *creatvol(AFPObj *obj,
         volume->v_preexec_close = 1;
     if (getoption_bool(obj->iniconfig, section, "root preexec close", preset, 0))
         volume->v_root_preexec_close = 1;
+    if (vdgoption_bool(obj->iniconfig, section, "force xattr with sticky bit", preset, 0))
+        volume->v_flags |= AFPVOL_FORCE_STICKY_XATTR;
 
     if ((val = getoption(obj->iniconfig, section, "ignored attributes", preset, obj->options.ignored_attr))) {
         if (strstr(val, "all")) {
@@ -895,6 +897,8 @@ static struct vol *creatvol(AFPObj *obj,
         volume->v_ad_options |= ADVOL_FOLLO_SYML;
     if ((volume->v_flags & AFPVOL_RO))
         volume->v_ad_options |= ADVOL_RO;
+    if ((volume->v_flags & AFPVOL_FORCE_STICKY_XATTR))
+        volume->v_ad_options |= ADVOL_FORCE_STICKY_XATTR;
 
     /* Mac to Unix conversion flags*/
     if ((volume->v_flags & AFPVOL_EILSEQ))
index 588911a..5356bdf 100644 (file)
@@ -630,6 +630,13 @@ extmap file = \fIpath\fR \fB(G)\fR
 Sets the path to the file which defines file extension type/creator mappings\&. (default is @pkgconfdir@/extmap\&.conf)\&.
 .RE
 .PP
+force xattr with sticky bit = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G/V)\fR
+.RS 4
+Writing metadata xattr on directories with the sticky bit set may fail even though we may have write access to a directory, because if the sticky bit is set only the owner is allowed to write xattrs\&.
+.sp
+By enabling this option Netatalk will write the metadata xattr as root\&.
+.RE
+.PP
 guest account = \fIname\fR \fB(G)\fR
 .RS 4
 Specifies the user that guests should use (default is "nobody")\&. The name should be quoted\&.