Add advanced option "chmod request" controlling ACLs
authorRalph Boehme <rb@sernet.de>
Tue, 24 Jun 2014 16:25:15 +0000 (18:25 +0200)
committerRalph Boehme <rb@sernet.de>
Wed, 25 Jun 2014 13:00:38 +0000 (15:00 +0200)
chmod request = ignore | preserve (default) | simple

* ignore = UNIX chmod() requests are completely ignored
* preserve = preserve ZFS ACEs for named users and groups or POSIX ACL
  group mask
* simple = just to a chmod() as requested without any extra steps

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

diff --git a/NEWS b/NEWS
index f6c3647388bcb18be88fd59163f38ca7d3b57892..9587f4247c4b42ddef7c3df4c0e7eda77b7bb01e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ Changes in 3.1.3
        is wrong resulting in corrupt resource forks after the
        conversion. Bug #568.
 * FIX: ad: fix for bug #563 broke ad file utilities, bug #570.
+* NEW: afpd: new advanced option controlling permissions and ACLs,
+       from FR #93
 
 Changes in 3.1.2
 ================
index cb5d597dc22c88bfcf62d65f71cbd95bd8a2c262..a8b4378c402dd02a644dbe03e3f5fced67a1b330 100644 (file)
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>chmod request = <replaceable>preserve (default) | ignore | simple</replaceable>
+          <type>(G/V)</type></term>
+
+          <listitem>
+            <para>Advanced permission control that deals with ACLs.</para>
+
+            <itemizedlist>
+              <listitem><para>
+                <option>ignore</option> - UNIX chmod() requests are completely ignored
+                     </para></listitem>
+              <listitem><para>
+                <option>preserve</option> - preserve ZFS ACEs for
+                named users and groups or POSIX ACL group mask
+                     </para></listitem>
+              <listitem><para>
+                <option>simple</option> - just to a chmod() as
+                requested without any extra steps
+                     </para></listitem>
+                   </itemizedlist>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term>close vol = <replaceable>BOOLEAN</replaceable> (default:
           <emphasis>no</emphasis>) <type>(G)</type></term>
index 9ba96bc595fd5562be47886acae0aba4238dccf2..5c56977acd3fd30e6dea0659b40b68b19ac68898 100644 (file)
@@ -95,17 +95,29 @@ int setdeskmode(const struct vol *vol, const mode_t mode)
             }
 
             if (S_ISDIR(st.st_mode)) {
-                if ( chmod_acl( modbuf,  (DIRBITS | mode)) < 0 && errno != EPERM ) {
+                if (ochmod(modbuf,
+                           DIRBITS | mode,
+                           &st,
+                           vol_syml_opt(vol) | vol_chmod_opt(vol)
+                        ) < 0 && errno != EPERM) {
                      LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
                 }
-            } else if ( chmod_acl( modbuf,  mode & ~EXEC_MODE ) < 0 && errno != EPERM ) {
+            } else if (ochmod(modbuf,
+                           mode & ~EXEC_MODE,
+                           &st,
+                           vol_syml_opt(vol) | vol_chmod_opt(vol)
+                        ) < 0 && errno != EPERM) {
                 LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(modbuf), strerror(errno) );
             }
 
         }
         closedir( sub );
         /* XXX: need to preserve special modes */
-        if ( chmod_acl( deskp->d_name,  (DIRBITS | mode)) < 0 && errno != EPERM ) {
+        if (ochmod(deskp->d_name,
+                   DIRBITS | mode,
+                   NULL,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0 && errno != EPERM) {
             LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s",fullpathname(deskp->d_name), strerror(errno) );
         }
     }
@@ -115,7 +127,11 @@ int setdeskmode(const struct vol *vol, const mode_t mode)
         EC_FAIL;
     }
     /* XXX: need to preserve special modes */
-    if ( chmod_acl(bdata(dtpath),  (DIRBITS | mode)) < 0 && errno != EPERM ) {
+    if (ochmod(bdata(dtpath),
+               DIRBITS | mode,
+               NULL,
+               vol_syml_opt(vol) | vol_chmod_opt(vol)
+            ) < 0 && errno != EPERM) {
         LOG(log_error, logtype_afpd, "setdeskmode: chmod %s: %s", bdata(dtpath), strerror(errno));
     }
 
index 7c90462874cd0cceec47f3c9836f42319e6a1937..a42a6ab9093fde4f923e43510474d52ad58334b4 100644 (file)
@@ -229,18 +229,22 @@ int setdirunixmode(const struct vol *vol, char *name, mode_t mode)
     LOG(log_debug, logtype_afpd, "setdirunixmode('%s', mode:%04o) {v_dperm:%04o}",
         fullpathname(name), mode, vol->v_dperm);
 
-    mode |= vol->v_dperm;
+    mode |= (vol->v_dperm | DIRBITS) & ~vol->v_umask;
 
     if (dir_rx_set(mode)) {
        /* extending right? dir first then .AppleDouble in rf_setdirmode */
-       if (chmod_acl(name, (DIRBITS | mode) & ~vol->v_umask) < 0 )
+        if (ochmod(name, mode, NULL,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
                return -1;
     }
     if (vol->vfs->vfs_setdirunixmode(vol, name, mode, NULL) < 0) {
         return  -1 ;
     }
     if (!dir_rx_set(mode)) {
-       if (chmod_acl(name, (DIRBITS | mode) & ~vol->v_umask) < 0 )
+        if (ochmod(name, mode, NULL,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
             return -1;
     }
     return 0;
index e639cfa6ac12b27053ba96901bcb3429b6d86e30..c7343a9e735f37878cc0b6e89dbc43fc258b4b4b 100644 (file)
@@ -22,6 +22,7 @@
 #ifdef HAVE_ACLS
 
 #define O_NETATALK_ACL (O_NOFOLLOW << 1)
+#define O_IGNORE (O_NOFOLLOW << 2)
 
 #ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
index e2728908a5010a6ffe388a62c0cecd4ea1d64679..084f5a0ad48cefd564492b8c4ccb90e7714824be 100644 (file)
@@ -113,13 +113,11 @@ typedef enum {lv_none = 0, lv_all = 1} lv_flags_t;
 #define AFPVOL_USTATFS  (1<<3)
 #define AFPVOL_UQUOTA   (1<<4)
 
-/*
-  Flags that alter volume behaviour.
-  Keep in sync with libatalk/util/volinfo.c
-*/
 #define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */
 #define AFPVOL_SPOTLIGHT (1 << 6)   /* Index volume for Spotlight searches */
 #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_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 */
@@ -195,5 +193,7 @@ typedef enum {lv_none = 0, lv_all = 1} lv_flags_t;
 #define vol_unix_priv(vol) ((vol)->v_obj->afp_version >= 30 && ((vol)->v_flags & AFPVOL_UNIX_PRIV))
 #define vol_inv_dots(vol) (((vol)->v_flags & AFPVOL_INV_DOTS) ? 1 : 0)
 #define vol_syml_opt(vol) (((vol)->v_flags & AFPVOL_FOLLOWSYM) ? 0 : O_NOFOLLOW)
+#define vol_chmod_opt(vol) (((vol)->v_flags & AFPVOL_CHMOD_PRESERVE_ACL) ? O_NETATALK_ACL : \
+                            ((vol)->v_flags & AFPVOL_CHMOD_IGNORE) ? O_IGNORE : 0)
 
 #endif
index 3548164cfc99cad74e7deff1045f4452eaaa3fb0..b20446d2177c470d849b0e0e4578d62e56fe4f08 100644 (file)
@@ -827,6 +827,19 @@ static struct vol *creatvol(AFPObj *obj,
         }
     }
 
+    val = getoption(obj->iniconfig, section, "chmod request", preset, NULL);
+    if (val == NULL) {
+        val = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "chmod request", "preserve");
+    }
+    if (strcasecmp(val, "ignore") == 0) {
+        volume->v_flags |= AFPVOL_CHMOD_IGNORE;
+    } else if (strcasecmp(val, "preserve") == 0) {
+        volume->v_flags |= AFPVOL_CHMOD_PRESERVE_ACL;
+    } else if (strcasecmp(val, "simple") != 0) {
+        LOG(log_warning, logtype_afpd, "unknown 'chmod request' setting: '%s', using default", val);
+        volume->v_flags |= AFPVOL_CHMOD_PRESERVE_ACL;
+    }
+
     /*
      * Handle read-only behaviour. semantics:
      * 1) neither the rolist nor the rwlist exist -> rw
index dcef1c821856c1d04a1d38517119ac3412ac8f81..4572caddd454d36c1b0cd3e45b6b258b7aedadf3 100644 (file)
@@ -44,6 +44,7 @@
 #include <atalk/unix.h>
 #include <atalk/compat.h>
 #include <atalk/errchk.h>
+#include <atalk/acl.h>
 
 /* close all FDs >= a specified value */
 static void closeall(int fd)
@@ -262,11 +263,15 @@ int ochown(const char *path, uid_t owner, gid_t group, int options)
  * Options description:
  * O_NOFOLLOW: don't chmod() symlinks, do nothing, return 0
  * O_NETATALK_ACL: call chmod_acl() instead of chmod()
+ * O_IGNORE: ignore chmod() request, directly return 0
  */
 int ochmod(char *path, mode_t mode, const struct stat *st, int options)
 {
     struct stat sb;
 
+    if (options & O_IGNORE)
+        return 0;
+
     if (!st) {
         if (lstat(path, &sb) != 0)
             return -1;
index 79e4fd33c29b151a08cd4afb4b157c638ea444b4..846aa7206933defac01a2efff09db8831bed77d1 100644 (file)
@@ -46,7 +46,11 @@ int setfilmode(const struct vol *vol, const char *name, mode_t mode, struct stat
 
     mode |= st->st_mode & ~mask; /* keep other bits from previous mode */
 
-    if (ochmod((char *)name, mode & ~vol->v_umask, st, vol_syml_opt(vol) | O_NETATALK_ACL) < 0 && errno != EPERM ) {
+    if (ochmod((char *)name,
+               mode & ~vol->v_umask,
+               st,
+               vol_syml_opt(vol) | vol_chmod_opt(vol)
+            ) < 0 && errno != EPERM ) {
         return -1;
     }
     return 0;
index 52c6ea84945b3bffe491df06942d266cc138b404..0d1961cfa92c393065c8ab0128e72031fd57e0d0 100644 (file)
@@ -172,7 +172,11 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
     const char *adouble = vol->ad_path(name, ADFLAGS_DIR );
 
     if (dir_rx_set(mode)) {
-        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 
+        if (ochmod(ad_dir(adouble),
+                   (DIRBITS | mode) & ~vol->v_umask,
+                   st,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
             return -1;
     }
 
@@ -180,7 +184,11 @@ static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
         return -1;
 
     if (!dir_rx_set(mode)) {
-        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0 ) 
+        if (ochmod(ad_dir(adouble),
+                   (DIRBITS | mode) & ~vol->v_umask,
+                   st,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
             return  -1 ;
     }
     return 0;
@@ -212,7 +220,11 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
     const char  *adouble_p = ad_dir(adouble);
 
     if (dir_rx_set(mode)) {
-        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 
+        if (ochmod(ad_dir(adouble),
+                   (DIRBITS | mode) & ~vol->v_umask,
+                   st,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
             return -1;
     }
 
@@ -220,7 +232,11 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
         return -1;
 
     if (!dir_rx_set(mode)) {
-        if (chmod_acl(ad_dir(adouble), (DIRBITS | mode) & ~vol->v_umask) < 0) 
+        if (ochmod(ad_dir(adouble),
+                   (DIRBITS | mode) & ~vol->v_umask,
+                   st,
+                   vol_syml_opt(vol) | vol_chmod_opt(vol)
+                ) < 0)
             return  -1 ;
     }
     return 0;
index c6eb8388a3ba0fb85d0553b6dd6696f96e9976f5..ad38876a617a78a7bea5df792aec54fe646808bc 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: afp.conf
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.78.0 <http://docbook.sf.net/>
-.\"      Date: 09 Feb 2013
+.\"      Date: 05 Jun 2014
 .\"    Manual: @NETATALK_VERSION@
 .\"    Source: @NETATALK_VERSION@
 .\"  Language: English
 .\"
-.TH "AFP\&.CONF" "5" "09 Feb 2013" "@NETATALK_VERSION@" "@NETATALK_VERSION@"
+.TH "AFP\&.CONF" "5" "05 Jun 2014" "@NETATALK_VERSION@" "@NETATALK_VERSION@"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -538,6 +538,50 @@ contains symlink, you must set the canonicalized absolute path\&. In the simple
 \fBbasedir regex = /home\fR
 .RE
 .PP
+chmod request = \fIpreserve (default) | ignore | simple\fR \fB(V)\fR
+.RS 4
+Advanced permission control that deals with ACLs\&.
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+
+\fBignore\fR
+\- UNIX chmod() requests are completely ignored
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+
+\fBpreserve\fR
+\- preserve ZFS ACEs for named users and groups or POSIX ACL group mask
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+
+\fBsimple\fR
+\- just to a chmod() as requested without any extra steps
+.RE
+.RE
+.PP
 close vol = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
 .RS 4
 Whether to close volumes possibly opened by clients when they\*(Aqre removed from the configuration and the configuration is reloaded\&.
@@ -636,7 +680,7 @@ sparql results limit = \fINUMBER\fR (default: \fIUNLIMITED\fR) \fB(G)\fR
 Impose a limit on the number of results queried from Tracker via SPARQL queries\&.
 .RE
 .PP
-spotlight = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
+spotlight = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)/(V)\fR
 .RS 4
 Whether to enable Spotlight searches\&. Note: once the global option is enabled, any volume that is not enabled won\*(Aqt be searchable at all\&. See also
 \fIdbus daemon\fR