From: Ralph Boehme Date: Wed, 25 Jun 2014 09:46:03 +0000 (+0200) Subject: Writing metadata xattr on directories with sticky bit set, FR#94 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=3a84db87064922ad10ac10cc1d6833380e575995 Writing metadata xattr on directories with sticky bit set, FR#94 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 --- diff --git a/NEWS b/NEWS index 9cf18b96..212272de 100644 --- 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 ================ diff --git a/doc/manpages/man5/afp.conf.5.xml b/doc/manpages/man5/afp.conf.5.xml index a8b4378c..44e083c2 100644 --- a/doc/manpages/man5/afp.conf.5.xml +++ b/doc/manpages/man5/afp.conf.5.xml @@ -928,6 +928,22 @@ + + force xattr with sticky bit = + BOOLEAN (default: + no) (G/V) + + + 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. + + By enabling this option Netatalk will write the + metadata xattr as root. + + + guest account = name (G) diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index f279d28c..40c92a11 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -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) diff --git a/include/atalk/volume.h b/include/atalk/volume.h index 084f5a0a..ad8be2b8 100644 --- a/include/atalk/volume.h +++ b/include/atalk/volume.h @@ -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 */ diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index 6a1900c7..f049876d 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -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; diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 1a4f9fa6..a1d27311 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -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)) diff --git a/man/man5/afp.conf.5.in b/man/man5/afp.conf.5.in index 588911a5..5356bdf2 100644 --- a/man/man5/afp.conf.5.in +++ b/man/man5/afp.conf.5.in @@ -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\&.