VFS: Modify chown to take a const struct smb_filename * instead of const char *
[kai/samba-autobuild/.git] / source3 / modules / vfs_fake_acls.c
index 196215869314c51239f6a0cb11a277fa631357af..cb907d0ca9875fabbb8c450c4622e2a4159b0385 100644 (file)
@@ -115,8 +115,16 @@ static int fake_acls_stat(vfs_handle_struct *handle,
        if (ret == 0) {
                TALLOC_CTX *frame = talloc_stackframe();
                char *path;
+               struct smb_filename smb_fname_base = {
+                       .base_name = smb_fname->base_name
+               };
                NTSTATUS status;
-               status = get_full_smb_filename(frame, smb_fname, &path);
+               /*
+                * As we're calling getxattr directly here
+                * we need to use only the base_name, not
+                * the full name containing any stream name.
+                */
+               status = get_full_smb_filename(frame, &smb_fname_base, &path);
                if (!NT_STATUS_IS_OK(status)) {
                        errno = map_errno_from_nt_status(status);
                        TALLOC_FREE(frame);
@@ -139,6 +147,46 @@ static int fake_acls_stat(vfs_handle_struct *handle,
        return ret;
 }
 
+static int fake_acls_lstat(vfs_handle_struct *handle,
+                          struct smb_filename *smb_fname)
+{
+       int ret = -1;
+
+       ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+       if (ret == 0) {
+               TALLOC_CTX *frame = talloc_stackframe();
+               char *path;
+               struct smb_filename smb_fname_base = {
+                       .base_name = smb_fname->base_name
+               };
+               NTSTATUS status;
+               /*
+                * As we're calling getxattr directly here
+                * we need to use only the base_name, not
+                * the full name containing any stream name.
+                */
+               status = get_full_smb_filename(frame, &smb_fname_base, &path);
+               if (!NT_STATUS_IS_OK(status)) {
+                       errno = map_errno_from_nt_status(status);
+                       TALLOC_FREE(frame);
+                       return -1;
+               }
+
+               /* This isn't quite right (calling getxattr not
+                * lgetxattr), but for the test purposes of this
+                * module (fake NT ACLs from windows clients), it is
+                * close enough.  We removed the l*xattr functions
+                * because linux doesn't support using them, but we
+                * could fake them in xattr_tdb if we really wanted
+                * to.  We ignore errors because the link might not point anywhere */
+               fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid);
+               fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid);
+               TALLOC_FREE(frame);
+       }
+
+       return ret;
+}
+
 static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
 {
        int ret = -1;
@@ -157,11 +205,10 @@ static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STR
        return ret;
 }
 
-static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob)
+static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 {
        enum ndr_err_code ndr_err;
-       /* For now, ACLs are allocated on NULL */
-       struct smb_acl_t *acl = talloc(NULL, struct smb_acl_t);
+       struct smb_acl_t *acl = talloc(mem_ctx, struct smb_acl_t);
        if (!acl) {
                errno = ENOMEM;
                return NULL;
@@ -194,7 +241,10 @@ static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl)
        return blob;
 }
 
-static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type)
+static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle,
+                                           const char *path,
+                                           SMB_ACL_TYPE_T type,
+                                           TALLOC_CTX *mem_ctx)
 {
        DATA_BLOB blob = data_blob_null;
        ssize_t length;
@@ -226,18 +276,20 @@ static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle, co
                return NULL;
        }
        if (length != -1) {
-               acl = fake_acls_blob2acl(&blob);
+               acl = fake_acls_blob2acl(&blob, mem_ctx);
        }
        TALLOC_FREE(frame);
        return acl;
 }
 
-static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle, files_struct *fsp)
+static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle,
+                                         files_struct *fsp,
+                                         TALLOC_CTX *mem_ctx)
 {
        DATA_BLOB blob = data_blob_null;
        ssize_t length;
        const char *name = FAKE_ACL_ACCESS_XATTR;
-       struct smb_acl_t *acl;
+       struct smb_acl_t *acl = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
                
        do {
@@ -256,12 +308,13 @@ static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle, file
                return NULL;
        }
        if (length != -1) {
-               acl = fake_acls_blob2acl(&blob);
+               acl = fake_acls_blob2acl(&blob, mem_ctx);
        }
        TALLOC_FREE(frame);
        return acl;
 }
 
+
 static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
 {
        int ret;
@@ -306,15 +359,87 @@ static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp
 
 static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path)
 {
+       int ret;
        const char *name = FAKE_ACL_DEFAULT_XATTR;
-       return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct smb_filename *smb_fname;
+
+       smb_fname = synthetic_smb_fname(frame, path, NULL, NULL);
+       if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
+               return -1;
+       }
+
+       if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
+       if (ret == -1 && errno == ENOATTR) {
+               ret = 0;
+               errno = 0;
+       }
+
+       TALLOC_FREE(frame);
+       return ret;
+}
+
+static int fake_acls_chown(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       uid_t uid,
+                       gid_t gid)
+{
+       int ret;
+       uint8_t id_buf[4];
+       if (uid != -1) {
+               SIVAL(id_buf, 0, uid);
+               ret = SMB_VFS_NEXT_SETXATTR(handle,
+                               smb_fname->base_name,
+                               FAKE_UID,
+                               id_buf,
+                               sizeof(id_buf),
+                               0);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+       if (gid != -1) {
+               SIVAL(id_buf, 0, gid);
+               ret = SMB_VFS_NEXT_SETXATTR(handle,
+                               smb_fname->base_name,
+                               FAKE_GID,
+                               id_buf,
+                               sizeof(id_buf),
+                               0);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
+       return 0;
 }
 
-static int fake_acls_chown(vfs_handle_struct *handle,  const char *path, uid_t uid, gid_t gid)
+static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid)
 {
        int ret;
        uint8_t id_buf[4];
        if (uid != -1) {
+               /* This isn't quite right (calling setxattr not
+                * lsetxattr), but for the test purposes of this
+                * module (fake NT ACLs from windows clients), it is
+                * close enough.  We removed the l*xattr functions
+                * because linux doesn't support using them, but we
+                * could fake them in xattr_tdb if we really wanted
+                * to.
+                */
                SIVAL(id_buf, 0, uid);
                ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0);
                if (ret != 0) {
@@ -355,13 +480,17 @@ static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t
 
 static struct vfs_fn_pointers vfs_fake_acls_fns = {
        .stat_fn = fake_acls_stat,
+       .lstat_fn = fake_acls_lstat,
        .fstat_fn = fake_acls_fstat,
        .sys_acl_get_file_fn = fake_acls_sys_acl_get_file,
        .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd,
+       .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
+       .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
        .sys_acl_set_file_fn = fake_acls_sys_acl_set_file,
        .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd,
        .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file,
        .chown_fn = fake_acls_chown,
+       .lchown_fn = fake_acls_lchown,
        .fchown_fn = fake_acls_fchown,
        
 };