s4:kdc: Implement KDC plugin hardware authentication policy
[samba.git] / source3 / modules / vfs_cap.c
index 3f75ba1c2e7bc354112874b3b2370fc869707e78..3553e118cc2cfcd6fce559e8bbe45ba71ff56885 100644 (file)
@@ -46,6 +46,7 @@ static uint64_t cap_disk_free(vfs_handle_struct *handle,
                                        capname,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(capname);
@@ -73,6 +74,7 @@ static int cap_get_quota(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
@@ -82,34 +84,8 @@ static int cap_get_quota(vfs_handle_struct *handle,
        return SMB_VFS_NEXT_GET_QUOTA(handle, cap_smb_fname, qtype, id, dq);
 }
 
-static DIR *cap_opendir(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       const char *mask,
-                       uint32_t attr)
-{
-       char *capname = capencode(talloc_tos(), smb_fname->base_name);
-       struct smb_filename *cap_smb_fname = NULL;
-
-       if (!capname) {
-               errno = ENOMEM;
-               return NULL;
-       }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       capname,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(capname);
-               errno = ENOMEM;
-               return NULL;
-       }
-       return SMB_VFS_NEXT_OPENDIR(handle, cap_smb_fname, mask, attr);
-}
-
-static struct dirent *cap_readdir(vfs_handle_struct *handle,
-                                     DIR *dirp,
-                                     SMB_STRUCT_STAT *sbuf)
+static struct dirent *
+cap_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp)
 {
        struct dirent *result;
        struct dirent *newdirent;
@@ -117,7 +93,7 @@ static struct dirent *cap_readdir(vfs_handle_struct *handle,
        size_t newnamelen;
        DEBUG(3,("cap: cap_readdir\n"));
 
-       result = SMB_VFS_NEXT_READDIR(handle, dirp, NULL);
+       result = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp);
        if (!result) {
                return NULL;
        }
@@ -139,32 +115,6 @@ static struct dirent *cap_readdir(vfs_handle_struct *handle,
        return newdirent;
 }
 
-static int cap_mkdir(vfs_handle_struct *handle,
-               const struct smb_filename *smb_fname,
-               mode_t mode)
-{
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       struct smb_filename *cap_smb_fname = NULL;
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-
-       return SMB_VFS_NEXT_MKDIR(handle, cap_smb_fname, mode);
-}
-
 static int cap_mkdirat(vfs_handle_struct *handle,
                struct files_struct *dirfsp,
                const struct smb_filename *smb_fname,
@@ -182,6 +132,7 @@ static int cap_mkdirat(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
@@ -195,54 +146,45 @@ static int cap_mkdirat(vfs_handle_struct *handle,
                        mode);
 }
 
-static int cap_rmdir(vfs_handle_struct *handle,
-               const struct smb_filename *smb_fname)
+static int cap_openat(vfs_handle_struct *handle,
+                     const struct files_struct *dirfsp,
+                     const struct smb_filename *smb_fname_in,
+                     files_struct *fsp,
+                     const struct vfs_open_how *how)
 {
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       struct smb_filename *cap_smb_fname = NULL;
+       char *cappath = NULL;
+       struct smb_filename *smb_fname = NULL;
+       int ret;
+       int saved_errno = 0;
 
-       if (!cappath) {
+       cappath = capencode(talloc_tos(), smb_fname_in->base_name);
+       if (cappath == NULL) {
                errno = ENOMEM;
                return -1;
        }
 
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
+       smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
+       if (smb_fname == NULL) {
                TALLOC_FREE(cappath);
                errno = ENOMEM;
                return -1;
        }
-
-       return SMB_VFS_NEXT_RMDIR(handle, cap_smb_fname);
-}
-
-static int cap_open(vfs_handle_struct *handle, struct smb_filename *smb_fname,
-                   files_struct *fsp, int flags, mode_t mode)
-{
-       char *cappath;
-       char *tmp_base_name = NULL;
-       int ret;
-
-       cappath = capencode(talloc_tos(), smb_fname->base_name);
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       tmp_base_name = smb_fname->base_name;
        smb_fname->base_name = cappath;
 
-       DEBUG(3,("cap: cap_open for %s\n", smb_fname_str_dbg(smb_fname)));
-       ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-
-       smb_fname->base_name = tmp_base_name;
+       DBG_DEBUG("cap_open for %s\n", smb_fname_str_dbg(smb_fname));
+       ret = SMB_VFS_NEXT_OPENAT(handle,
+                                 dirfsp,
+                                 smb_fname,
+                                 fsp,
+                                 how);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
        TALLOC_FREE(cappath);
-
+       TALLOC_FREE(smb_fname);
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
        return ret;
 }
 
@@ -256,22 +198,41 @@ static int cap_renameat(vfs_handle_struct *handle,
        char *capnew = NULL;
        struct smb_filename *smb_fname_src_tmp = NULL;
        struct smb_filename *smb_fname_dst_tmp = NULL;
+       struct smb_filename *full_fname_src = NULL;
+       struct smb_filename *full_fname_dst = NULL;
        int ret = -1;
+       int saved_errno = 0;
 
-       capold = capencode(talloc_tos(), smb_fname_src->base_name);
-       capnew = capencode(talloc_tos(), smb_fname_dst->base_name);
+       full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 srcfsp,
+                                                 smb_fname_src);
+       if (full_fname_src == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dstfsp,
+                                                 smb_fname_dst);
+       if (full_fname_dst == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       capold = capencode(talloc_tos(), full_fname_src->base_name);
+       capnew = capencode(talloc_tos(), full_fname_dst->base_name);
        if (!capold || !capnew) {
                errno = ENOMEM;
                goto out;
        }
 
        /* Setup temporary smb_filename structs. */
-       smb_fname_src_tmp = cp_smb_filename(talloc_tos(), smb_fname_src);
+       smb_fname_src_tmp = cp_smb_filename(talloc_tos(), full_fname_src);
        if (smb_fname_src_tmp == NULL) {
                errno = ENOMEM;
                goto out;
        }
-       smb_fname_dst_tmp = cp_smb_filename(talloc_tos(), smb_fname_dst);
+       smb_fname_dst_tmp = cp_smb_filename(talloc_tos(), full_fname_dst);
        if (smb_fname_dst_tmp == NULL) {
                errno = ENOMEM;
                goto out;
@@ -281,17 +242,28 @@ static int cap_renameat(vfs_handle_struct *handle,
        smb_fname_dst_tmp->base_name = capnew;
 
        ret = SMB_VFS_NEXT_RENAMEAT(handle,
-                               srcfsp,
+                               srcfsp->conn->cwd_fsp,
                                smb_fname_src_tmp,
-                               dstfsp,
+                               dstfsp->conn->cwd_fsp,
                                smb_fname_dst_tmp);
 
  out:
+
+       if (ret != 0) {
+               saved_errno = errno;
+       }
+
+       TALLOC_FREE(full_fname_src);
+       TALLOC_FREE(full_fname_dst);
        TALLOC_FREE(capold);
        TALLOC_FREE(capnew);
        TALLOC_FREE(smb_fname_src_tmp);
        TALLOC_FREE(smb_fname_dst_tmp);
 
+       if (ret != 0) {
+               errno = saved_errno;
+       }
+
        return ret;
 }
 
@@ -343,21 +315,33 @@ static int cap_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
        return ret;
 }
 
-static int cap_unlink(vfs_handle_struct *handle,
-                     const struct smb_filename *smb_fname)
+static int cap_unlinkat(vfs_handle_struct *handle,
+                       struct files_struct *dirfsp,
+                       const struct smb_filename *smb_fname,
+                       int flags)
 {
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *smb_fname_tmp = NULL;
        char *cappath = NULL;
        int ret;
 
-       cappath = capencode(talloc_tos(), smb_fname->base_name);
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               return -1;
+       }
+
+       cappath = capencode(talloc_tos(), full_fname->base_name);
        if (!cappath) {
+               TALLOC_FREE(full_fname);
                errno = ENOMEM;
                return -1;
        }
 
        /* Setup temporary smb_filename structs. */
-       smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
+       smb_fname_tmp = cp_smb_filename(talloc_tos(), full_fname);
+       TALLOC_FREE(full_fname);
        if (smb_fname_tmp == NULL) {
                errno = ENOMEM;
                return -1;
@@ -365,79 +349,15 @@ static int cap_unlink(vfs_handle_struct *handle,
 
        smb_fname_tmp->base_name = cappath;
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                       dirfsp->conn->cwd_fsp,
+                       smb_fname_tmp,
+                       flags);
 
        TALLOC_FREE(smb_fname_tmp);
        return ret;
 }
 
-static int cap_chmod(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       mode_t mode)
-{
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       int ret;
-       int saved_errno;
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-
-       ret = SMB_VFS_NEXT_CHMOD(handle, cap_smb_fname, mode);
-       saved_errno = errno;
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(cap_smb_fname);
-       errno = saved_errno;
-       return ret;
-}
-
-static int cap_chown(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       uid_t uid,
-                       gid_t gid)
-{
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       int ret;
-       int saved_errno;
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-
-       ret = SMB_VFS_NEXT_CHOWN(handle, cap_smb_fname, uid, gid);
-       saved_errno = errno;
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(cap_smb_fname);
-       errno = saved_errno;
-       return ret;
-}
-
 static int cap_lchown(vfs_handle_struct *handle,
                        const struct smb_filename *smb_fname,
                        uid_t uid,
@@ -457,6 +377,7 @@ static int cap_lchown(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
@@ -490,6 +411,7 @@ static int cap_chdir(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
@@ -508,71 +430,77 @@ static int cap_chdir(vfs_handle_struct *handle,
        return ret;
 }
 
-static int cap_ntimes(vfs_handle_struct *handle,
-                     const struct smb_filename *smb_fname,
-                     struct smb_file_time *ft)
+static int cap_symlinkat(vfs_handle_struct *handle,
+                       const struct smb_filename *link_contents,
+                       struct files_struct *dirfsp,
+                       const struct smb_filename *new_smb_fname)
 {
-       struct smb_filename *smb_fname_tmp = NULL;
-       char *cappath = NULL;
+       struct smb_filename *full_fname = NULL;
+       char *capold = capencode(talloc_tos(), link_contents->base_name);
+       char *capnew = NULL;
+       struct smb_filename *new_link_target = NULL;
+       struct smb_filename *new_cap_smb_fname = NULL;
+       int saved_errno = 0;
        int ret;
 
-       cappath = capencode(talloc_tos(), smb_fname->base_name);
-
-       if (!cappath) {
+       if (capold == NULL) {
                errno = ENOMEM;
                return -1;
        }
 
-       /* Setup temporary smb_filename structs. */
-       smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
-       if (smb_fname_tmp == NULL) {
-               errno = ENOMEM;
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dirfsp,
+                                               new_smb_fname);
+       if (full_fname == NULL) {
                return -1;
        }
 
-       smb_fname_tmp->base_name = cappath;
-
-       ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname_tmp, ft);
-
-       TALLOC_FREE(smb_fname_tmp);
-       return ret;
-}
-
-static int cap_symlinkat(vfs_handle_struct *handle,
-                       const char *link_contents,
-                       struct files_struct *dirfsp,
-                       const struct smb_filename *new_smb_fname)
-{
-       char *capold = capencode(talloc_tos(), link_contents);
-       char *capnew = capencode(talloc_tos(), new_smb_fname->base_name);
-       struct smb_filename *new_cap_smb_fname = NULL;
-       int saved_errno = 0;
-       int ret;
+       capnew = capencode(talloc_tos(), full_fname->base_name);
+       if (!capnew) {
+               TALLOC_FREE(full_fname);
+               errno = ENOMEM;
+               return -1;
+       }
 
-       if (!capold || !capnew) {
+       new_link_target = synthetic_smb_fname(talloc_tos(),
+                                             capold,
+                                             NULL,
+                                             NULL,
+                                             new_smb_fname->twrp,
+                                             new_smb_fname->flags);
+       if (new_link_target == NULL) {
+               TALLOC_FREE(full_fname);
+               TALLOC_FREE(capold);
+               TALLOC_FREE(capnew);
                errno = ENOMEM;
                return -1;
        }
+
        new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
                                        capnew,
                                        NULL,
                                        NULL,
+                                       new_smb_fname->twrp,
                                        new_smb_fname->flags);
        if (new_cap_smb_fname == NULL) {
+               TALLOC_FREE(full_fname);
                TALLOC_FREE(capold);
                TALLOC_FREE(capnew);
+               TALLOC_FREE(new_link_target);
                errno = ENOMEM;
                return -1;
        }
        ret = SMB_VFS_NEXT_SYMLINKAT(handle,
-                       capold,
-                       dirfsp,
+                       new_link_target,
+                       handle->conn->cwd_fsp,
                        new_cap_smb_fname);
        if (ret == -1) {
                saved_errno = errno;
        }
+       TALLOC_FREE(full_fname);
        TALLOC_FREE(capold);
        TALLOC_FREE(capnew);
+       TALLOC_FREE(new_link_target);
        TALLOC_FREE(new_cap_smb_fname);
        if (saved_errno != 0) {
                errno = saved_errno;
@@ -581,17 +509,27 @@ static int cap_symlinkat(vfs_handle_struct *handle,
 }
 
 static int cap_readlinkat(vfs_handle_struct *handle,
-                       files_struct *dirfsp,
+                       const struct files_struct *dirfsp,
                        const struct smb_filename *smb_fname,
                        char *buf,
                        size_t bufsiz)
 {
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *cap_smb_fname = NULL;
+       char *cappath = NULL;
        int saved_errno = 0;
        int ret;
 
-       if (!cappath) {
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dirfsp,
+                                               smb_fname);
+       if (full_fname == NULL) {
+               return -1;
+       }
+
+       cappath = capencode(talloc_tos(), full_fname->base_name);
+       if (cappath == NULL) {
+               TALLOC_FREE(full_fname);
                errno = ENOMEM;
                return -1;
        }
@@ -599,20 +537,23 @@ static int cap_readlinkat(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
+               TALLOC_FREE(full_fname);
                TALLOC_FREE(cappath);
                errno = ENOMEM;
                return -1;
        }
        ret = SMB_VFS_NEXT_READLINKAT(handle,
-                       dirfsp,
+                       handle->conn->cwd_fsp,
                        cap_smb_fname,
                        buf,
                        bufsiz);
        if (ret == -1) {
                saved_errno = errno;
        }
+       TALLOC_FREE(full_fname);
        TALLOC_FREE(cappath);
        TALLOC_FREE(cap_smb_fname);
        if (saved_errno != 0) {
@@ -628,49 +569,70 @@ static int cap_linkat(vfs_handle_struct *handle,
                const struct smb_filename *new_smb_fname,
                int flags)
 {
-       char *capold = capencode(talloc_tos(), old_smb_fname->base_name);
-       char *capnew = capencode(talloc_tos(), new_smb_fname->base_name);
+       struct smb_filename *old_full_fname = NULL;
+       struct smb_filename *new_full_fname = NULL;
+       char *capold = NULL;
+       char *capnew = NULL;
        struct smb_filename *old_cap_smb_fname = NULL;
        struct smb_filename *new_cap_smb_fname = NULL;
        int saved_errno = 0;
        int ret;
 
-       if (!capold || !capnew) {
-               errno = ENOMEM;
-               return -1;
-       }
+       /* Process 'old' name. */
+       old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               srcfsp,
+                                               old_smb_fname);
+        if (old_full_fname == NULL) {
+               goto nomem_out;
+        }
+       capold = capencode(talloc_tos(), old_full_fname->base_name);
+       if (capold == NULL) {
+               goto nomem_out;
+       }
+       TALLOC_FREE(old_full_fname);
        old_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
                                        capold,
                                        NULL,
                                        NULL,
+                                       old_smb_fname->twrp,
                                        old_smb_fname->flags);
        if (old_cap_smb_fname == NULL) {
-               TALLOC_FREE(capold);
-               TALLOC_FREE(capnew);
-               errno = ENOMEM;
-               return -1;
+               goto nomem_out;
        }
+
+       /* Process 'new' name. */
+       new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dstfsp,
+                                               new_smb_fname);
+        if (new_full_fname == NULL) {
+               goto nomem_out;
+        }
+       capnew = capencode(talloc_tos(), new_full_fname->base_name);
+       if (capnew == NULL) {
+               goto nomem_out;
+       }
+       TALLOC_FREE(new_full_fname);
        new_cap_smb_fname = synthetic_smb_fname(talloc_tos(),
                                        capnew,
                                        NULL,
                                        NULL,
+                                       new_smb_fname->twrp,
                                        new_smb_fname->flags);
        if (new_cap_smb_fname == NULL) {
-               TALLOC_FREE(capold);
-               TALLOC_FREE(capnew);
-               TALLOC_FREE(old_cap_smb_fname);
-               errno = ENOMEM;
-               return -1;
+               goto nomem_out;
        }
+
        ret = SMB_VFS_NEXT_LINKAT(handle,
-                       srcfsp,
+                       handle->conn->cwd_fsp,
                        old_cap_smb_fname,
-                       dstfsp,
+                       handle->conn->cwd_fsp,
                        new_cap_smb_fname,
                        flags);
        if (ret == -1) {
                saved_errno = errno;
        }
+       TALLOC_FREE(old_full_fname);
+       TALLOC_FREE(old_full_fname);
        TALLOC_FREE(capold);
        TALLOC_FREE(capnew);
        TALLOC_FREE(old_cap_smb_fname);
@@ -679,6 +641,17 @@ static int cap_linkat(vfs_handle_struct *handle,
                errno = saved_errno;
        }
        return ret;
+
+  nomem_out:
+
+       TALLOC_FREE(old_full_fname);
+       TALLOC_FREE(old_full_fname);
+       TALLOC_FREE(capold);
+       TALLOC_FREE(capnew);
+       TALLOC_FREE(old_cap_smb_fname);
+       TALLOC_FREE(new_cap_smb_fname);
+       errno = ENOMEM;
+       return -1;
 }
 
 static int cap_mknodat(vfs_handle_struct *handle,
@@ -687,12 +660,22 @@ static int cap_mknodat(vfs_handle_struct *handle,
                mode_t mode,
                SMB_DEV_T dev)
 {
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
+       char *cappath = NULL;
        int ret;
        int saved_errno = 0;
 
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dirfsp,
+                                               smb_fname);
+        if (full_fname == NULL) {
+                return -1;
+        }
+
+       cappath = capencode(talloc_tos(), full_fname->base_name);
        if (!cappath) {
+               TALLOC_FREE(full_fname);
                errno = ENOMEM;
                return -1;
        }
@@ -700,20 +683,23 @@ static int cap_mknodat(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
+               TALLOC_FREE(full_fname);
                TALLOC_FREE(cappath);
                errno = ENOMEM;
                return -1;
        }
        ret = SMB_VFS_NEXT_MKNODAT(handle,
-                       dirfsp,
+                       handle->conn->cwd_fsp,
                        cap_smb_fname,
                        mode,
                        dev);
        if (ret == -1) {
                saved_errno = errno;
        }
+       TALLOC_FREE(full_fname);
        TALLOC_FREE(cappath);
        TALLOC_FREE(cap_smb_fname);
        if (saved_errno != 0) {
@@ -740,6 +726,7 @@ static struct smb_filename *cap_realpath(vfs_handle_struct *handle,
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
@@ -758,156 +745,29 @@ static struct smb_filename *cap_realpath(vfs_handle_struct *handle,
        return return_fname;
 }
 
-static SMB_ACL_T cap_sys_acl_get_file(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               SMB_ACL_TYPE_T type,
-                               TALLOC_CTX *mem_ctx)
-{
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       SMB_ACL_T ret;
-       int saved_errno = 0;
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return (SMB_ACL_T)NULL;
-       }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return (SMB_ACL_T)NULL;
-       }
-       ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, cap_smb_fname,
-                               type, mem_ctx);
-       if (ret == NULL) {
-               saved_errno = errno;
-       }
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(cap_smb_fname);
-       if (saved_errno != 0) {
-               errno = saved_errno;
-       }
-       return ret;
-}
-
-static int cap_sys_acl_set_file(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       SMB_ACL_TYPE_T acltype,
-                       SMB_ACL_T theacl)
+static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
 {
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       int ret;
-       int saved_errno = 0;
+       char *cappath = capencode(talloc_tos(), path);
 
        if (!cappath) {
                errno = ENOMEM;
                return -1;
        }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-       ret =  SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, cap_smb_fname,
-                               acltype, theacl);
-       if (ret == -1) {
-               saved_errno = errno;
-       }
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(cap_smb_fname);
-       if (saved_errno != 0) {
-               errno = saved_errno;
-       }
-       return ret;
+        return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
 }
 
-static int cap_sys_acl_delete_def_file(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname)
+static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
 {
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       int ret;
-       int saved_errno = 0;
+       char *cappath = capencode(talloc_tos(), path);
 
        if (!cappath) {
                errno = ENOMEM;
                return -1;
        }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-       ret = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, cap_smb_fname);
-       if (ret == -1) {
-               saved_errno = errno;
-       }
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(cap_smb_fname);
-       if (saved_errno) {
-               errno = saved_errno;
-       }
-       return ret;
-}
-
-static ssize_t cap_getxattr(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       const char *name,
-                       void *value,
-                       size_t size)
-{
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       char *capname = capencode(talloc_tos(), name);
-       ssize_t ret;
-       int saved_errno = 0;
-
-       if (!cappath || !capname) {
-               errno = ENOMEM;
-               return -1;
-       }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               TALLOC_FREE(capname);
-               errno = ENOMEM;
-               return -1;
-       }
-       ret = SMB_VFS_NEXT_GETXATTR(handle, cap_smb_fname,
-                       capname, value, size);
-       if (ret == -1) {
-               saved_errno = errno;
-       }
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(capname);
-       TALLOC_FREE(cap_smb_fname);
-       if (saved_errno) {
-               errno = saved_errno;
-       }
-       return ret;
+        return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
 }
 
-static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, void *value, size_t size)
+static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
 {
        char *cappath = capencode(talloc_tos(), path);
 
@@ -915,182 +775,119 @@ static ssize_t cap_fgetxattr(vfs_handle_struct *handle, struct files_struct *fsp
                errno = ENOMEM;
                return -1;
        }
-        return SMB_VFS_NEXT_FGETXATTR(handle, fsp, cappath, value, size);
+        return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
 }
 
-static ssize_t cap_listxattr(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               char *list,
-                               size_t size)
+static NTSTATUS cap_create_dfs_pathat(vfs_handle_struct *handle,
+                       files_struct *dirfsp,
+                       const struct smb_filename *smb_fname,
+                       const struct referral *reflist,
+                       size_t referral_count)
 {
-       struct smb_filename *cap_smb_fname = NULL;
        char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       ssize_t ret;
-       int saved_errno = 0;
+       struct smb_filename *cap_smb_fname = NULL;
+       NTSTATUS status;
 
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
+       if (cappath == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
        cap_smb_fname = synthetic_smb_fname(talloc_tos(),
                                        cappath,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (cap_smb_fname == NULL) {
                TALLOC_FREE(cappath);
-               errno = ENOMEM;
-               return -1;
-       }
-       ret = SMB_VFS_NEXT_LISTXATTR(handle, cap_smb_fname, list, size);
-       if (ret == -1) {
-               saved_errno = errno;
+               return NT_STATUS_NO_MEMORY;
        }
+       status = SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
+                       dirfsp,
+                       cap_smb_fname,
+                       reflist,
+                       referral_count);
        TALLOC_FREE(cappath);
        TALLOC_FREE(cap_smb_fname);
-       if (saved_errno) {
-               errno = saved_errno;
-       }
-       return ret;
+       return status;
 }
 
-static int cap_removexattr(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name)
+static NTSTATUS cap_read_dfs_pathat(struct vfs_handle_struct *handle,
+                       TALLOC_CTX *mem_ctx,
+                       struct files_struct *dirfsp,
+                       struct smb_filename *smb_fname,
+                       struct referral **ppreflist,
+                       size_t *preferral_count)
 {
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       char *capname = capencode(talloc_tos(), name);
-       int ret;
-       int saved_errno = 0;
+       char *cappath = NULL;
+       NTSTATUS status;
 
-       if (!cappath || !capname) {
-               errno = ENOMEM;
-               return -1;
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dirfsp,
+                                               smb_fname);
+       if (full_fname == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       cappath = capencode(talloc_tos(), full_fname->base_name);
+       if (cappath == NULL) {
+               TALLOC_FREE(full_fname);
+               return NT_STATUS_NO_MEMORY;
        }
        cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
+                               cappath,
+                               NULL,
+                               NULL,
+                               smb_fname->twrp,
+                               smb_fname->flags);
        if (cap_smb_fname == NULL) {
+               TALLOC_FREE(full_fname);
                TALLOC_FREE(cappath);
-               TALLOC_FREE(capname);
-               errno = ENOMEM;
-               return -1;
-       }
-        ret = SMB_VFS_NEXT_REMOVEXATTR(handle, cap_smb_fname, capname);
-       if (ret == -1) {
-               saved_errno = errno;
+               return NT_STATUS_NO_MEMORY;
        }
-       TALLOC_FREE(cappath);
-       TALLOC_FREE(capname);
-       TALLOC_FREE(cap_smb_fname);
-       if (saved_errno) {
-               errno = saved_errno;
-       }
-       return ret;
-}
 
-static int cap_fremovexattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path)
-{
-       char *cappath = capencode(talloc_tos(), path);
+       status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
+                       mem_ctx,
+                       handle->conn->cwd_fsp,
+                       cap_smb_fname,
+                       ppreflist,
+                       preferral_count);
 
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
+       if (NT_STATUS_IS_OK(status)) {
+               /* Return any stat(2) info. */
+               smb_fname->st = cap_smb_fname->st;
        }
-        return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, cappath);
-}
-
-static int cap_setxattr(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       const char *name,
-                       const void *value,
-                       size_t size,
-                       int flags)
-{
-       struct smb_filename *cap_smb_fname = NULL;
-       char *cappath = capencode(talloc_tos(), smb_fname->base_name);
-       char *capname = capencode(talloc_tos(), name);
-       int ret;
-       int saved_errno = 0;
 
-       if (!cappath || !capname) {
-               errno = ENOMEM;
-               return -1;
-       }
-       cap_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       cappath,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (cap_smb_fname == NULL) {
-               TALLOC_FREE(cappath);
-               TALLOC_FREE(capname);
-               errno = ENOMEM;
-               return -1;
-       }
-       ret = SMB_VFS_NEXT_SETXATTR(handle, cap_smb_fname,
-                               capname, value, size, flags);
-       if (ret == -1) {
-               saved_errno = errno;
-       }
+       TALLOC_FREE(full_fname);
        TALLOC_FREE(cappath);
-       TALLOC_FREE(capname);
        TALLOC_FREE(cap_smb_fname);
-       if (saved_errno) {
-               errno = saved_errno;
-       }
-       return ret;
-}
-
-static int cap_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp, const char *path, const void *value, size_t size, int flags)
-{
-       char *cappath = capencode(talloc_tos(), path);
-
-       if (!cappath) {
-               errno = ENOMEM;
-               return -1;
-       }
-        return SMB_VFS_NEXT_FSETXATTR(handle, fsp, cappath, value, size, flags);
+       return status;
 }
 
 static struct vfs_fn_pointers vfs_cap_fns = {
        .disk_free_fn = cap_disk_free,
        .get_quota_fn = cap_get_quota,
-       .opendir_fn = cap_opendir,
        .readdir_fn = cap_readdir,
-       .mkdir_fn = cap_mkdir,
        .mkdirat_fn = cap_mkdirat,
-       .rmdir_fn = cap_rmdir,
-       .open_fn = cap_open,
+       .openat_fn = cap_openat,
        .renameat_fn = cap_renameat,
        .stat_fn = cap_stat,
        .lstat_fn = cap_lstat,
-       .unlink_fn = cap_unlink,
-       .chmod_fn = cap_chmod,
-       .chown_fn = cap_chown,
+       .unlinkat_fn = cap_unlinkat,
        .lchown_fn = cap_lchown,
        .chdir_fn = cap_chdir,
-       .ntimes_fn = cap_ntimes,
        .symlinkat_fn = cap_symlinkat,
        .readlinkat_fn = cap_readlinkat,
        .linkat_fn = cap_linkat,
        .mknodat_fn = cap_mknodat,
        .realpath_fn = cap_realpath,
-       .sys_acl_get_file_fn = cap_sys_acl_get_file,
-       .sys_acl_set_file_fn = cap_sys_acl_set_file,
-       .sys_acl_delete_def_file_fn = cap_sys_acl_delete_def_file,
-       .getxattr_fn = cap_getxattr,
        .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
        .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
        .fgetxattr_fn = cap_fgetxattr,
-       .listxattr_fn = cap_listxattr,
-       .removexattr_fn = cap_removexattr,
        .fremovexattr_fn = cap_fremovexattr,
-       .setxattr_fn = cap_setxattr,
-       .fsetxattr_fn = cap_fsetxattr
+       .fsetxattr_fn = cap_fsetxattr,
+       .create_dfs_pathat_fn = cap_create_dfs_pathat,
+       .read_dfs_pathat_fn = cap_read_dfs_pathat
 };
 
 static_decl_vfs;