From 79a220e86c9e794f805751a8f2437f1e84282282 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 8 Jul 2014 05:50:09 +0200 Subject: [PATCH] s4:torture:vfs_fruit: add test reading Netatalk metadata Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison Reviewed-by: Volker Lendecke --- source4/torture/vfs/fruit.c | 355 +++++++++++++++++++++++++++++++++- source4/torture/wscript_build | 2 +- 2 files changed, 355 insertions(+), 2 deletions(-) diff --git a/source4/torture/vfs/fruit.c b/source4/torture/vfs/fruit.c index 2685a8fb4b8..6b2bd89f751 100644 --- a/source4/torture/vfs/fruit.c +++ b/source4/torture/vfs/fruit.c @@ -20,18 +20,369 @@ */ #include "includes.h" +#include "system/filesys.h" +#include "libcli/libcli.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "lib/cmdline/popt_common.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" +#include "MacExtensions.h" #include "torture/torture.h" #include "torture/util.h" #include "torture/smb2/proto.h" #include "torture/vfs/proto.h" +#define BASEDIR "vfs_fruit_dir" + +#define CHECK_STATUS(status, correct) do { \ + if (!NT_STATUS_EQUAL(status, correct)) { \ + torture_result(tctx, TORTURE_FAIL, \ + "(%s) Incorrect status %s - should be %s\n", \ + __location__, nt_errstr(status), nt_errstr(correct)); \ + ret = false; \ + goto done; \ + }} while (0) + +/* + * REVIEW: + * This is hokey, but what else can we do? + */ +#if defined(HAVE_ATTROPEN) || defined(FREEBSD) +#define AFPINFO_EA_NETATALK "org.netatalk.Metadata" +#define AFPRESOURCE_EA_NETATALK "org.netatalk.ResourceFork" +#else +#define AFPINFO_EA_NETATALK "user.org.netatalk.Metadata" +#define AFPRESOURCE_EA_NETATALK "user.org.netatalk.ResourceFork" +#endif + +/* +The metadata xattr char buf below contains the following attributes: + +------------------------------------------------------------------------------- +Entry ID : 00000008 : File Dates Info +Offset : 00000162 : 354 +Length : 00000010 : 16 + +-DATE------: : (GMT) : (Local) +create : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014 +modify : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014 +backup : 80000000 : Unknown or Initial +access : 1B442169 : Mon Jun 30 13:23:53 2014 : Mon Jun 30 15:23:53 2014 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 1B 44 21 69 1B 44 21 69 80 00 00 00 1B 44 21 69 : .D!i.D!i.....D!i + +------------------------------------------------------------------------------- +Entry ID : 00000009 : Finder Info +Offset : 0000007A : 122 +Length : 00000020 : 32 + +-FInfo-----: +Type : 42415252 : BARR +Creator : 464F4F4F : FOOO +isAlias : 0 +Invisible : 1 +hasBundle : 0 +nameLocked : 0 +Stationery : 0 +CustomIcon : 0 +Reserved : 0 +Inited : 0 +NoINITS : 0 +Shared : 0 +SwitchLaunc: 0 +Hidden Ext : 0 +color : 000 : none +isOnDesk : 0 +Location v : 0000 : 0 +Location h : 0000 : 0 +Fldr : 0000 : .. + +-FXInfo----: +Rsvd|IconID: 0000 : 0 +Rsvd : 0000 : .. +Rsvd : 0000 : .. +Rsvd : 0000 : .. +AreInvalid : 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +CustomBadge: 0 +ObjctIsBusy: 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +unknown bit: 0 +RoutingInfo: 0 +unknown bit: 0 +unknown bit: 0 +Rsvd|commnt: 0000 : 0 +PutAway : 00000000 : 0 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 42 41 52 52 46 4F 4F 4F 40 00 00 00 00 00 00 00 : BARRFOOO@....... +00000010 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : ................ + +------------------------------------------------------------------------------- +Entry ID : 0000000E : AFP File Info +Offset : 00000172 : 370 +Length : 00000004 : 4 + +-RAW DUMP--: 0 1 2 3 4 5 6 7 8 9 A B C D E F : (ASCII) +00000000 : 00 00 01 A1 : .... + */ + +char metadata_xattr[] = { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x01, 0x62, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x7a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x00, 0x01, 0x72, 0x00, 0x00, + 0x00, 0x04, 0x80, 0x44, 0x45, 0x56, 0x00, 0x00, + 0x01, 0x76, 0x00, 0x00, 0x00, 0x08, 0x80, 0x49, + 0x4e, 0x4f, 0x00, 0x00, 0x01, 0x7e, 0x00, 0x00, + 0x00, 0x08, 0x80, 0x53, 0x59, 0x4e, 0x00, 0x00, + 0x01, 0x86, 0x00, 0x00, 0x00, 0x08, 0x80, 0x53, + 0x56, 0x7e, 0x00, 0x00, 0x01, 0x8e, 0x00, 0x00, + 0x00, 0x04, 0x42, 0x41, 0x52, 0x52, 0x46, 0x4f, + 0x4f, 0x4f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1b, 0x44, 0x21, 0x69, 0x1b, 0x44, + 0x21, 0x69, 0x80, 0x00, 0x00, 0x00, 0x1b, 0x44, + 0x21, 0x69, 0x00, 0x00, 0x01, 0xa1, 0x00, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x20, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xe3, + 0x86, 0x53, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x01, + 0x00, 0x00 +}; + +/** + * Read 'count' bytes at 'offset' from stream 'fname:sname' and + * compare against buffer 'value' + **/ +static bool check_stream(struct smb2_tree *tree, + const char *location, + struct torture_context *tctx, + TALLOC_CTX *mem_ctx, + const char *fname, + const char *sname, + off_t read_offset, + size_t read_count, + off_t comp_offset, + size_t comp_count, + const char *value) +{ + struct smb2_handle handle; + struct smb2_create create; + struct smb2_read r; + NTSTATUS status; + const char *full_name; + + full_name = talloc_asprintf(mem_ctx, "%s%s", fname, sname); + if (full_name == NULL) { + torture_comment(tctx, "talloc_asprintf error\n"); + return false; + } + ZERO_STRUCT(create); + create.in.desired_access = SEC_FILE_READ_DATA; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.fname = full_name; + + torture_comment(tctx, "Open stream %s\n", full_name); + + status = smb2_create(tree, mem_ctx, &create); + if (!NT_STATUS_IS_OK(status)) { + if (value == NULL) { + return true; + } else { + torture_comment(tctx, "Unable to open stream %s\n", + full_name); + sleep(10000000); + return false; + } + } + + handle = create.out.file.handle; + if (value == NULL) { + return true; + } + + + ZERO_STRUCT(r); + r.in.file.handle = handle; + r.in.length = read_count; + r.in.offset = read_offset; + + status = smb2_read(tree, tree, &r); + + if (!NT_STATUS_IS_OK(status)) { + torture_comment(tctx, "(%s) Failed to read %lu bytes from " + "stream '%s'\n", location, (long)strlen(value), full_name); + return false; + } + + if (memcmp(r.out.data.data + comp_offset, value, comp_count) != 0) { + torture_comment(tctx, "(%s) Bad data in stream\n", location); + return false; + } + + smb2_util_close(tree, handle); + return true; +} + +static bool torture_setup_local_xattr(struct torture_context *tctx, + const char *path_option, + const char *name, + const char *metadata, + size_t size) +{ + int ret = true; + int result; + const char *spath; + char *path; + + spath = torture_setting_string(tctx, path_option, NULL); + if (spath == NULL) { + printf("No sharepath for option %s\n", path_option); + return false; + } + + path = talloc_asprintf(tctx, "%s/%s", spath, name); + + result = setxattr(path, AFPINFO_EA_NETATALK, metadata, size, 0); + if (result != 0) { + ret = false; + } + + TALLOC_FREE(path); + + return ret; +} + +/** + * Create a file or directory + **/ +static bool torture_setup_file(TALLOC_CTX *mem_ctx, struct smb2_tree *tree, + const char *name, bool dir) +{ + struct smb2_create io; + NTSTATUS status; + + smb2_util_unlink(tree, name); + ZERO_STRUCT(io); + io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = 0; + io.in.fname = name; + if (dir) { + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.in.share_access &= ~NTCREATEX_SHARE_ACCESS_DELETE; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.create_disposition = NTCREATEX_DISP_CREATE; + } + + status = smb2_create(tree, mem_ctx, &io); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + status = smb2_util_close(tree, io.out.file.handle); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + return true; +} + +static bool test_read_atalk_metadata(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = BASEDIR "\\torture_read_metadata"; + NTSTATUS status; + struct smb2_handle testdirh; + bool ret = true; + + torture_comment(tctx, "Checking metadata access\n"); + + smb2_util_unlink(tree1, fname); + + status = torture_smb2_testdir(tree1, BASEDIR, &testdirh); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree1, testdirh); + + ret = torture_setup_file(mem_ctx, tree1, fname, false); + if (ret == false) { + goto done; + } + + ret = torture_setup_local_xattr(tctx, "localdir", + BASEDIR "/torture_read_metadata", + metadata_xattr, sizeof(metadata_xattr)); + if (ret == false) { + goto done; + } + + ret &= check_stream(tree1, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 0, 4, "AFP"); + + ret &= check_stream(tree1, __location__, tctx, mem_ctx, fname, AFPINFO_STREAM, + 0, 60, 16, 8, "BARRFOOO"); + +done: + smb2_deltree(tree1, BASEDIR); + talloc_free(mem_ctx); + return ret; +} + /* * Note: This test depends on "vfs objects = catia fruit * streams_xattr". Note: To run this test, use * "--option=torture:share1= * --option=torture:share2= - * --option=torture:localpath=" + * --option=torture:localdir=" */ struct torture_suite *torture_vfs_fruit(void) { @@ -40,5 +391,7 @@ struct torture_suite *torture_vfs_fruit(void) suite->description = talloc_strdup(suite, "vfs_fruit tests"); + torture_suite_add_2ns_smb2_test(suite, "read metadata", test_read_atalk_metadata); + return suite; } diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build index c0de7bbeac0..c13e7d45475 100755 --- a/source4/torture/wscript_build +++ b/source4/torture/wscript_build @@ -151,7 +151,7 @@ bld.SAMBA_MODULE('TORTURE_NTP', ) bld.SAMBA_MODULE('TORTURE_VFS', - source='vfs/vfs.c', + source='vfs/vfs.c vfs/fruit.c', allow_warnings=True, subsystem='smbtorture', deps='LIBCLI_SMB POPT_CREDENTIALS TORTURE_UTIL smbclient-raw TORTURE_RAW', -- 2.34.1