From: Ralph Boehme Date: Tue, 24 Jun 2014 16:25:15 +0000 (+0200) Subject: Add advanced option "chmod request" controlling ACLs X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=c72d10d6f92fe81d040ab983768d7fdccea7fb2e Add advanced option "chmod request" controlling ACLs 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 --- diff --git a/NEWS b/NEWS index f6c36473..9587f424 100644 --- 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 ================ diff --git a/doc/manpages/man5/afp.conf.5.xml b/doc/manpages/man5/afp.conf.5.xml index cb5d597d..a8b4378c 100644 --- a/doc/manpages/man5/afp.conf.5.xml +++ b/doc/manpages/man5/afp.conf.5.xml @@ -807,6 +807,29 @@ + + chmod request = preserve (default) | ignore | simple + (G/V) + + + Advanced permission control that deals with ACLs. + + + + - UNIX chmod() requests are completely ignored + + + - preserve ZFS ACEs for + named users and groups or POSIX ACL group mask + + + - just to a chmod() as + requested without any extra steps + + + + + close vol = BOOLEAN (default: no) (G) diff --git a/etc/afpd/desktop.c b/etc/afpd/desktop.c index 9ba96bc5..5c56977a 100644 --- a/etc/afpd/desktop.c +++ b/etc/afpd/desktop.c @@ -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)); } diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index 7c904628..a42a6ab9 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -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; diff --git a/include/atalk/acl.h b/include/atalk/acl.h index e639cfa6..c7343a9e 100644 --- a/include/atalk/acl.h +++ b/include/atalk/acl.h @@ -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 diff --git a/include/atalk/volume.h b/include/atalk/volume.h index e2728908..084f5a0a 100644 --- a/include/atalk/volume.h +++ b/include/atalk/volume.h @@ -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 diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 3548164c..b20446d2 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -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 diff --git a/libatalk/util/unix.c b/libatalk/util/unix.c index dcef1c82..4572cadd 100644 --- a/libatalk/util/unix.c +++ b/libatalk/util/unix.c @@ -44,6 +44,7 @@ #include #include #include +#include /* 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; diff --git a/libatalk/vfs/unix.c b/libatalk/vfs/unix.c index 79e4fd33..846aa720 100644 --- a/libatalk/vfs/unix.c +++ b/libatalk/vfs/unix.c @@ -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; diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index 52c6ea84..0d1961cf 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -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; diff --git a/man/man5/afp.conf.5.in b/man/man5/afp.conf.5.in index c6eb8388..ad38876a 100644 --- a/man/man5/afp.conf.5.in +++ b/man/man5/afp.conf.5.in @@ -2,12 +2,12 @@ .\" Title: afp.conf .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" 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