vfs: Store ACL control flags in gpfs vfs module.
authorAlexander Werth <alexander.werth@de.ibm.com>
Tue, 4 Feb 2014 16:50:54 +0000 (17:50 +0100)
committerJeremy Allison <jra@samba.org>
Fri, 4 Apr 2014 22:50:14 +0000 (00:50 +0200)
Use literals to allow a compile and execution on gpfs 3.4.

Signed-off-by: Alexander Werth <alexander.werth@de.ibm.com>
Reviewed-by: Christof Schmitt <cs@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_gpfs.c

index 73ab4a463d9655dab4812148c0b8d48797a2f15d..edbc88573ba40bccb75237dd426cd59df1606aca 100644 (file)
@@ -52,6 +52,24 @@ struct gpfs_config_data {
        bool recalls;
 };
 
+static inline unsigned int gpfs_acl_flags(gpfs_acl_t *gacl)
+{
+       if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
+               /* gacl->v4Level1.acl_flags requires gpfs 3.5 */
+               return *(unsigned int *)&gacl->ace_v4;
+       }
+       return 0;
+}
+
+static inline gpfs_ace_v4_t *gpfs_ace_ptr(gpfs_acl_t *gacl, unsigned int i)
+{
+       if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
+               /* &gacl->v4Level1.ace_v4[i] requires gpfs 3.5 */
+               char *ptr = (char *)&gacl->ace_v4[i] + sizeof(unsigned int);
+               return (gpfs_ace_v4_t *)ptr;
+       }
+       return &gacl->ace_v4[i];
+}
 
 static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
                                 uint32 share_mode, uint32 access_mask)
@@ -208,6 +226,34 @@ static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle,
        return 0;
 }
 
+static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl)
+{
+       unsigned int gpfs_aclflags = 0;
+       control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
+               SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
+               SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
+               SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
+       gpfs_aclflags = control << 8;
+       if (!(control & SEC_DESC_DACL_PRESENT))
+               gpfs_aclflags |= 0x00800000; /* ACL4_FLAG_NULL_DACL; */
+       if (!(control & SEC_DESC_SACL_PRESENT))
+               gpfs_aclflags |= 0x01000000; /* ACL4_FLAG_NULL_SACL; */
+       gacl->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS*/
+       /* gacl->v4Level1.acl_flags requires gpfs 3.5 */
+       *(unsigned int *)&gacl->ace_v4 = gpfs_aclflags;
+}
+
+static uint16_t gpfs2sd_control(unsigned int gpfs_aclflags)
+{
+       uint16_t control = gpfs_aclflags >> 8;
+       control &= SEC_DESC_DACL_PROTECTED | SEC_DESC_SACL_PROTECTED |
+               SEC_DESC_DACL_AUTO_INHERITED | SEC_DESC_SACL_AUTO_INHERITED |
+               SEC_DESC_DACL_DEFAULTED | SEC_DESC_SACL_DEFAULTED |
+               SEC_DESC_DACL_PRESENT | SEC_DESC_SACL_PRESENT;
+       control |= SEC_DESC_SELF_RELATIVE;
+       return control;
+}
+
 static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
 {
        gpfs_aclCount_t i;
@@ -217,14 +263,18 @@ static void gpfs_dumpacl(int level, struct gpfs_acl *gacl)
                return;
        }
 
-       DEBUG(level, ("gpfs acl: nace: %d, type:%d, version:%d, level:%d, len:%d\n",
-               gacl->acl_nace, gacl->acl_type, gacl->acl_version, gacl->acl_level, gacl->acl_len));
+       DEBUG(level, ("len: %d, level: %d, version: %d, nace: %d, "
+                     "control: %x\n",
+                     gacl->acl_len, gacl->acl_level, gacl->acl_version,
+                     gacl->acl_nace, gpfs_acl_flags(gacl)));
+
        for(i=0; i<gacl->acl_nace; i++)
        {
-               struct gpfs_ace_v4 *gace = gacl->ace_v4 + i;
-               DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, iflags:0x%x, who:%u\n",
-                       i, gace->aceType, gace->aceFlags, gace->aceMask,
-                       gace->aceIFlags, gace->aceWho));
+               struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
+               DEBUG(level, ("\tace[%d]: type:%d, flags:0x%x, mask:0x%x, "
+                             "iflags:0x%x, who:%u\n",
+                             i, gace->aceType, gace->aceFlags, gace->aceMask,
+                             gace->aceIFlags, gace->aceWho));
        }
 }
 
@@ -266,9 +316,11 @@ again:
        } else {
                struct gpfs_acl *buf = (struct gpfs_acl *) aclbuf;
                buf->acl_type = type;
+               buf->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS */
                flags = GPFS_GETACL_STRUCT;
                len = &(buf->acl_len);
-               struct_size = sizeof(struct gpfs_acl);
+               /* reserve space for control flags in gpfs 3.5 and beyond */
+               struct_size = sizeof(struct gpfs_acl) + sizeof(unsigned int);
        }
 
        /* set the length of the buffer as input value */
@@ -331,12 +383,17 @@ static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname, SMB4ACL_T *
 
        *ppacl = smb_create_smb4acl(mem_ctx);
 
-       DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n",
+       if (gacl->acl_level == 1) { /* GPFS_ACL_LEVEL_V4FLAGS */
+               uint16_t control = gpfs2sd_control(gpfs_acl_flags(gacl));
+               smbacl4_set_controlflags(*ppacl, control);
+       }
+
+       DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d, control: %x\n",
                   gacl->acl_len, gacl->acl_level, gacl->acl_version,
-                  gacl->acl_nace));
+                  gacl->acl_nace, gpfs_acl_flags(gacl)));
 
        for (i=0; i<gacl->acl_nace; i++) {
-               struct gpfs_ace_v4 *gace = &gacl->ace_v4[i];
+               struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, i);
                SMB_ACE4PROP_T smbace;
                DEBUG(10, ("type: %d, iflags: %x, flags: %x, mask: %x, "
                           "who: %d\n", gace->aceType, gace->aceIFlags,
@@ -369,7 +426,7 @@ static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname, SMB4ACL_T *
 
                /* remove redundant deny entries */
                if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
-                       struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
+                       struct gpfs_ace_v4 *prev = gpfs_ace_ptr(gacl, i - 1);
                        if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
                            prev->aceFlags == gace->aceFlags &&
                            prev->aceIFlags == gace->aceIFlags &&
@@ -377,7 +434,7 @@ static int gpfs_get_nfs4_acl(TALLOC_CTX *mem_ctx, const char *fname, SMB4ACL_T *
                            gace->aceWho == prev->aceWho) {
                                /* it's redundant - skip it */
                                continue;
-                       }                                                
+                       }
                }
 
                smbace.aceType = gace->aceType;
@@ -484,32 +541,37 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
        return map_nt_error_from_unix(errno);
 }
 
-static bool gpfsacl_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
+static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx,
+                                               files_struct *fsp,
+                                               SMB4ACL_T *smbacl,
+                                               bool controlflags)
 {
-       int ret;
-       gpfs_aclLen_t gacl_len;
-       SMB4ACE_T       *smbace;
        struct gpfs_acl *gacl;
-       TALLOC_CTX *mem_ctx  = talloc_tos();
+       gpfs_aclLen_t gacl_len;
+       SMB4ACE_T *smbace;
 
-       gacl_len = offsetof(gpfs_acl_t, ace_v4) + smb_get_naces(smbacl) *
-               sizeof(gpfs_ace_v4_t);
+       gacl_len = offsetof(gpfs_acl_t, ace_v4) + sizeof(unsigned int)
+               + smb_get_naces(smbacl) * sizeof(gpfs_ace_v4_t);
 
        gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len);
        if (gacl == NULL) {
                DEBUG(0, ("talloc failed\n"));
                errno = ENOMEM;
-               return False;
+               return NULL;
        }
 
-       gacl->acl_len = gacl_len;
-       gacl->acl_level = 0;
+       gacl->acl_level = 0; /* GPFS_ACL_LEVEL_BASE */
        gacl->acl_version = GPFS_ACL_VERSION_NFS4;
        gacl->acl_type = GPFS_ACL_TYPE_NFS4;
        gacl->acl_nace = 0; /* change later... */
 
+       if (controlflags) {
+               gacl->acl_level = 1; /* GPFS_ACL_LEVEL_V4FLAGS */
+               sd2gpfs_control(smbacl4_get_controlflags(smbacl), gacl);
+       }
+
        for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
-               struct gpfs_ace_v4 *gace = &gacl->ace_v4[gacl->acl_nace];
+               struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, gacl->acl_nace);
                SMB_ACE4PROP_T  *aceprop = smb_get_ace4(smbace);
 
                gace->aceType = aceprop->aceType;
@@ -567,9 +629,38 @@ static bool gpfsacl_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
 
                gacl->acl_nace++;
        }
+       gacl->acl_len = (char *)gpfs_ace_ptr(gacl, gacl->acl_nace)
+               - (char *)gacl;
+       return gacl;
+}
 
+static bool gpfsacl_process_smbacl(vfs_handle_struct *handle,
+                                  files_struct *fsp,
+                                  SMB4ACL_T *smbacl)
+{
+       int ret;
+       struct gpfs_acl *gacl;
+       TALLOC_CTX *mem_ctx = talloc_tos();
+
+       gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, true);
+       if (gacl == NULL) { /* out of memory */
+               return False;
+       }
        ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
                               GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA, gacl);
+
+       if ((ret != 0) && (errno == EINVAL)) {
+               DEBUG(10, ("Retry without nfs41 control flags\n"));
+               talloc_free(gacl);
+               gacl = vfs_gpfs_smbacl2gpfsacl(mem_ctx, fsp, smbacl, false);
+               if (gacl == NULL) { /* out of memory */
+                       return False;
+               }
+               ret = smbd_gpfs_putacl(fsp->fsp_name->base_name,
+                                      GPFS_PUTACL_STRUCT | GPFS_ACL_SAMBA,
+                                      gacl);
+       }
+
        if (ret != 0) {
                DEBUG(8, ("gpfs_putacl failed with %s\n", strerror(errno)));
                gpfs_dumpacl(8, gacl);