vfs_zfsacl: use handle based facl() call to query ZFS filesytem ACL
authorRalph Boehme <slow@samba.org>
Thu, 20 Aug 2020 14:18:35 +0000 (16:18 +0200)
committerKarolin Seeger <kseeger@samba.org>
Fri, 30 Oct 2020 13:54:18 +0000 (13:54 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14470

Pair-Programmed-With: Andrew Walker <awalker@ixsystems.com>
Signed-off-by: Ralph Boehme <slow@samba.org>
Signed-off-by: Andrew Walker <awalker@ixsystems.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
(backported from commit f763b1e43640082af80c855a4a519f7747a6c87c)
[slow@samba.org: conflict in zfs_get_nt_acl_common() due to *AT changes in 4.13]

source3/modules/vfs_zfsacl.c

index 524881ab4af0d7d21ab74609ac90d4788050654d..d3da725783858b8a8782914d6790cfee23a09afa 100644 (file)
@@ -49,11 +49,12 @@ struct zfsacl_config_data {
 static NTSTATUS zfs_get_nt_acl_common(struct connection_struct *conn,
                                      TALLOC_CTX *mem_ctx,
                                      const struct smb_filename *smb_fname,
+                                     const ace_t *acebuf,
+                                     int naces,
                                      struct SMB4ACL_T **ppacl,
                                      struct zfsacl_config_data *config)
 {
-       int naces, i;
-       ace_t *acebuf;
+       int i;
        struct SMB4ACL_T *pacl;
        SMB_STRUCT_STAT sbuf;
        const SMB_STRUCT_STAT *psbuf = NULL;
@@ -76,30 +77,8 @@ static NTSTATUS zfs_get_nt_acl_common(struct connection_struct *conn,
        }
        is_dir = S_ISDIR(psbuf->st_ex_mode);
 
-       /* read the number of file aces */
-       if((naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL)) == -1) {
-               if(errno == ENOSYS) {
-                       DEBUG(9, ("acl(ACE_GETACLCNT, %s): Operation is not "
-                                 "supported on the filesystem where the file "
-                                 "reside\n", smb_fname->base_name));
-               } else {
-                       DEBUG(9, ("acl(ACE_GETACLCNT, %s): %s ", smb_fname->base_name,
-                                       strerror(errno)));
-               }
-               return map_nt_error_from_unix(errno);
-       }
-       /* allocate the field of ZFS aces */
        mem_ctx = talloc_tos();
-       acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces);
-       if(acebuf == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       /* read the aces into the field */
-       if(acl(smb_fname->base_name, ACE_GETACL, naces, acebuf) < 0) {
-               DEBUG(9, ("acl(ACE_GETACL, %s): %s ", smb_fname->base_name,
-                               strerror(errno)));
-               return map_nt_error_from_unix(errno);
-       }
+
        /* create SMB4ACL data */
        if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -163,7 +142,7 @@ static NTSTATUS zfs_get_nt_acl_common(struct connection_struct *conn,
 static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
                               struct SMB4ACL_T *smbacl)
 {
-       int naces = smb_get_naces(smbacl), i;
+       int naces = smb_get_naces(smbacl), i, rv;
        ace_t *acebuf;
        struct SMB4ACE_T *smbace;
        TALLOC_CTX      *mem_ctx;
@@ -222,7 +201,13 @@ static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
        SMB_ASSERT(i == naces);
 
        /* store acl */
-       if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) {
+       if (fsp->fh->fd != -1) {
+               rv = facl(fsp->fh->fd, ACE_SETACL, naces, acebuf);
+       }
+       else {
+               rv = acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf);
+       }
+       if (rv != 0) {
                if(errno == ENOSYS) {
                        DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not "
                                  "supported on the filesystem where the file "
@@ -231,7 +216,7 @@ static bool zfs_process_smbacl(vfs_handle_struct *handle, files_struct *fsp,
                        DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp),
                                  strerror(errno)));
                }
-               return 0;
+               return false;
        }
 
        return True;
@@ -259,6 +244,81 @@ static NTSTATUS zfs_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
                                zfs_process_smbacl);
 }
 
+static int get_zfsacl(TALLOC_CTX *mem_ctx,
+                     const struct smb_filename *smb_fname,
+                     ace_t **outbuf)
+{
+       int naces, rv;
+       ace_t *acebuf = NULL;
+
+       naces = acl(smb_fname->base_name, ACE_GETACLCNT, 0, NULL);
+       if (naces == -1) {
+               int dbg_level = 10;
+
+               if (errno == ENOSYS) {
+                       dbg_level = 1;
+               }
+               DEBUG(dbg_level, ("acl(ACE_GETACLCNT, %s): %s ",
+                                 smb_fname->base_name, strerror(errno)));
+               return naces;
+       }
+       acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
+       if (acebuf == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       rv = acl(smb_fname->base_name, ACE_GETACL, naces, acebuf);
+       if (rv == -1) {
+               DBG_DEBUG("acl(ACE_GETACL, %s) failed: %s ",
+                         smb_fname->base_name, strerror(errno));
+               return -1;
+       }
+
+       *outbuf = acebuf;
+       return naces;
+}
+
+static int fget_zfsacl(TALLOC_CTX *mem_ctx,
+                      struct files_struct *fsp,
+                      ace_t **outbuf)
+{
+       int naces, rv;
+       ace_t *acebuf = NULL;
+
+       if (fsp->fh->fd == -1) {
+               return get_zfsacl(mem_ctx, fsp->fsp_name, outbuf);
+       }
+
+       naces = facl(fsp->fh->fd, ACE_GETACLCNT, 0, NULL);
+       if (naces == -1) {
+               int dbg_level = 10;
+
+               if (errno == ENOSYS) {
+                       dbg_level = 1;
+               }
+               DEBUG(dbg_level, ("facl(ACE_GETACLCNT, %s): %s ",
+                                 fsp_str_dbg(fsp), strerror(errno)));
+               return naces;
+       }
+
+       acebuf = talloc_size(mem_ctx, sizeof(ace_t)*naces);
+       if (acebuf == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       rv = facl(fsp->fh->fd, ACE_GETACL, naces, acebuf);
+       if (rv == -1) {
+               DBG_DEBUG("acl(ACE_GETACL, %s): %s ",
+                         fsp_str_dbg(fsp), strerror(errno));
+               return -1;
+       }
+
+       *outbuf = acebuf;
+       return naces;
+}
+
 static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
                                   struct files_struct *fsp,
                                   uint32_t security_info,
@@ -268,6 +328,8 @@ static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
        struct SMB4ACL_T *pacl;
        NTSTATUS status;
        struct zfsacl_config_data *config = NULL;
+       ace_t *acebuf = NULL;
+       int naces;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct zfsacl_config_data,
@@ -275,9 +337,9 @@ static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
 
        TALLOC_CTX *frame = talloc_stackframe();
 
-       status = zfs_get_nt_acl_common(handle->conn, frame,
-                                      fsp->fsp_name, &pacl, config);
-       if (!NT_STATUS_IS_OK(status)) {
+       naces = fget_zfsacl(talloc_tos(), fsp, &acebuf);
+       if (naces == -1) {
+               status = map_nt_error_from_unix(errno);
                TALLOC_FREE(frame);
                if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
                        return status;
@@ -295,6 +357,18 @@ static NTSTATUS zfsacl_fget_nt_acl(struct vfs_handle_struct *handle,
                return NT_STATUS_OK;
        }
 
+       status = zfs_get_nt_acl_common(handle->conn,
+                                      frame,
+                                      fsp->fsp_name,
+                                      acebuf,
+                                      naces,
+                                      &pacl,
+                                      config);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
+
        status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
                                      ppdesc, pacl);
        TALLOC_FREE(frame);
@@ -310,14 +384,18 @@ static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
        struct SMB4ACL_T *pacl;
        NTSTATUS status;
        struct zfsacl_config_data *config = NULL;
+       int naces;
+       ace_t *acebuf = NULL;
+
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct zfsacl_config_data,
                                return NT_STATUS_INTERNAL_ERROR);
 
        TALLOC_CTX *frame = talloc_stackframe();
 
-       status = zfs_get_nt_acl_common(handle->conn, frame, smb_fname, &pacl, config);
-       if (!NT_STATUS_IS_OK(status)) {
+       naces = get_zfsacl(frame, smb_fname, &acebuf);
+       if (naces == -1) {
+               status = map_nt_error_from_unix(errno);
                TALLOC_FREE(frame);
                if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
                        return status;
@@ -341,6 +419,18 @@ static NTSTATUS zfsacl_get_nt_acl(struct vfs_handle_struct *handle,
                return NT_STATUS_OK;
        }
 
+       status = zfs_get_nt_acl_common(handle->conn,
+                                      frame,
+                                      smb_fname,
+                                      acebuf,
+                                      naces,
+                                      &pacl,
+                                      config);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
+
        status = smb_get_nt_acl_nfs4(handle->conn,
                                        smb_fname,
                                        NULL,