]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_error_inject: add unlinkat hook
authorRalph Boehme <slow@samba.org>
Mon, 25 Jan 2021 10:46:30 +0000 (11:46 +0100)
committerJeremy Allison <jra@samba.org>
Tue, 26 Jan 2021 02:55:28 +0000 (02:55 +0000)
Note that a failure is only injected if the owner of the parent directory is not
the same as the current user.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14617

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/modules/vfs_error_inject.c

index 2230b8a29910bcfa0f938680383739bef862911b..31257cc1d00ba1ef0dbb834e870e342854e0b758 100644 (file)
@@ -30,6 +30,7 @@ struct unix_error_map {
        {       "ESTALE",       ESTALE  },
        {       "EBADF",        EBADF   },
        {       "EINTR",        EINTR   },
+       {       "EACCES",       EACCES  },
 };
 
 static int find_unix_error_from_string(const char *err_str)
@@ -123,10 +124,53 @@ static int vfs_error_inject_openat(struct vfs_handle_struct *handle,
        return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
 }
 
+static int vfs_error_inject_unlinkat(struct 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 *parent_fname = NULL;
+       int error = inject_unix_error("unlinkat", handle);
+       int ret;
+       bool ok;
+
+       if (error == 0) {
+               return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
+       }
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               return -1;
+       }
+
+       ok = parent_smb_fname(full_fname, full_fname, &parent_fname, NULL);
+       if (!ok) {
+               TALLOC_FREE(full_fname);
+               return -1;
+       }
+
+       ret = SMB_VFS_STAT(handle->conn, parent_fname);
+       if (ret != 0) {
+               TALLOC_FREE(full_fname);
+               return -1;
+       }
+
+       if (parent_fname->st.st_ex_uid == get_current_uid(dirfsp->conn)) {
+               return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags);
+       }
+
+       errno = error;
+       return -1;
+}
+
 static struct vfs_fn_pointers vfs_error_inject_fns = {
        .chdir_fn = vfs_error_inject_chdir,
        .pwrite_fn = vfs_error_inject_pwrite,
        .openat_fn = vfs_error_inject_openat,
+       .unlinkat_fn = vfs_error_inject_unlinkat,
 };
 
 static_decl_vfs;