From c8c7fb2492d3f19939df67f98e4ea6ad423274da Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Nov 2005 09:25:25 +0000 Subject: r11775: added support for creating files on SMB2 with initial EA lists and an ACL (This used to be commit ff197092988cee64742f83df23c43ae664a196f9) --- source4/libcli/smb2/create.c | 65 ++++++++++++++++++++++++++++++++++++++-- source4/libcli/smb2/request.c | 6 ++++ source4/libcli/smb2/smb2_calls.h | 5 +++- source4/torture/smb2/connect.c | 14 --------- source4/torture/smb2/scan.c | 44 +++++++++++++++++++++++++++ source4/torture/smb2/setinfo.c | 2 ++ source4/torture/smb2/util.c | 54 +++++++++++++++++---------------- source4/torture/torture.c | 1 + 8 files changed, 148 insertions(+), 43 deletions(-) (limited to 'source4') diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index 47fd208643..647b408c68 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -25,6 +25,37 @@ #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" +#define CREATE_TAG_EA 0x41747845 /* "ExtA" */ +#define CREATE_TAG_SD 0x6341784D /* "MxAc" */ + +/* + add a blob to a smb2_create attribute blob +*/ +static NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, + uint32_t tag, + DATA_BLOB add, BOOL last) +{ + NTSTATUS status; + uint32_t ofs = blob->length; + status = data_blob_realloc(mem_ctx, blob, blob->length + 0x18 + add.length); + NT_STATUS_NOT_OK_RETURN(status); + + if (last) { + SIVAL(blob->data, ofs+0x00, 0); + } else { + SIVAL(blob->data, ofs+0x00, 0x18 + add.length); + } + SSVAL(blob->data, ofs+0x04, 0x10); /* offset of tag */ + SIVAL(blob->data, ofs+0x06, 0x04); /* tag length */ + SSVAL(blob->data, ofs+0x0A, 0x18); /* offset of data */ + SIVAL(blob->data, ofs+0x0C, add.length); + SIVAL(blob->data, ofs+0x10, tag); + SIVAL(blob->data, ofs+0x14, 0); /* pad? */ + memcpy(blob->data+ofs+0x18, add.data, add.length); + + return NT_STATUS_OK; +} + /* send a create request */ @@ -32,6 +63,7 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create { struct smb2_request *req; NTSTATUS status; + DATA_BLOB blob = data_blob(NULL, 0); req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, 1); if (req == NULL) return NULL; @@ -54,7 +86,36 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create return NULL; } - status = smb2_push_o32s32_blob(&req->out, 0x30, io->in.blob); + if (io->in.eas.num_eas != 0) { + DATA_BLOB b = data_blob_talloc(req, NULL, + ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas)); + ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas); + status = smb2_create_blob_add(req, &blob, CREATE_TAG_EA, b, False); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + data_blob_free(&b); + } + + if (io->in.sd != NULL) { + DATA_BLOB b; + status = ndr_push_struct_blob(&b, req, io->in.sd, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + status = smb2_create_blob_add(req, &blob, CREATE_TAG_SD, b, True); + } else { + status = smb2_create_blob_add(req, &blob, CREATE_TAG_SD, data_blob(NULL, 0), True); + } + + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + status = smb2_push_o32s32_blob(&req->out, 0x30, blob); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; @@ -74,7 +135,7 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct NTSTATUS status; if (!smb2_request_receive(req) || - smb2_request_is_error(req)) { + !smb2_request_is_ok(req)) { return smb2_request_destroy(req); } diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index 41e2ad74e2..3f09c9aeec 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -160,6 +160,12 @@ BOOL smb2_request_is_error(struct smb2_request *req) return NT_STATUS_IS_ERR(req->status); } +/* Return true if the last packet was OK */ +BOOL smb2_request_is_ok(struct smb2_request *req) +{ + return NT_STATUS_IS_OK(req->status); +} + /* check if a range in the reply body is out of bounds */ diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h index 1ef056da13..53f7a45d88 100644 --- a/source4/libcli/smb2/smb2_calls.h +++ b/source4/libcli/smb2/smb2_calls.h @@ -130,7 +130,10 @@ struct smb2_create { /* dynamic body */ const char *fname; - DATA_BLOB blob; + /* optional list of extended attributes and security + descriptor */ + struct smb_ea_list eas; + struct security_descriptor *sd; } in; struct { diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index 54f2920600..2307d8fffb 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -133,19 +133,6 @@ static struct smb2_handle torture_smb2_create(struct smb2_tree *tree, struct smb2_create io; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(tree); - DATA_BLOB blob = data_blob(NULL, 0); - -#if 0 /* TODO: find out what this blob mean */ - uint8_t buf[0x18]; - - SIVAL(buf, 0x00, 0x00000000); - SIVAL(buf, 0x04, 0x00040010); - SIVAL(buf, 0x08, 0x00180000); - SIVAL(buf, 0x0C, 0x00000000); - SBVAL(buf, 0x10, 0x006C00466341784DLLU); - - blob = data_blob_const(buf, 0x18) -#endif ZERO_STRUCT(io); io.in.oplock_flags = 0; @@ -158,7 +145,6 @@ static struct smb2_handle torture_smb2_create(struct smb2_tree *tree, NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = NTCREATEX_OPTIONS_WRITE_THROUGH; io.in.fname = fname; - io.in.blob = blob; status = smb2_create(tree, tmp_ctx, &io); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/torture/smb2/scan.c b/source4/torture/smb2/scan.c index f3a7cd4aa9..908dac3e11 100644 --- a/source4/torture/smb2/scan.c +++ b/source4/torture/smb2/scan.c @@ -96,6 +96,50 @@ BOOL torture_smb2_getinfo_scan(void) return True; } +/* + scan for valid SMB2 setinfo levels +*/ +BOOL torture_smb2_setinfo_scan(void) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + struct smb2_tree *tree; + NTSTATUS status; + struct smb2_setinfo io; + struct smb2_handle handle; + int c, i; + + if (!torture_smb2_connection(mem_ctx, &tree)) { + return False; + } + + if (!torture_setup_complex_file(FNAME)) { + printf("Failed to setup complex file '%s'\n", FNAME); + } + torture_setup_complex_file(FNAME ":2ndstream"); + + torture_smb2_testfile(tree, FNAME, &handle); + + ZERO_STRUCT(io); + io.in.blob = data_blob_talloc(mem_ctx, NULL, 1024); + + for (c=1;c<5;c++) { + for (i=0;i<0x100;i++) { + io.in.level = (i<<8) | c; + io.in.handle = handle; + status = smb2_setinfo(tree, &io); + if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS) && + !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { + printf("file level 0x%04x - %s\n", + io.in.level, nt_errstr(status)); + } + } + } + + talloc_free(mem_ctx); + + return True; +} + /* scan for valid SMB2 opcodes */ diff --git a/source4/torture/smb2/setinfo.c b/source4/torture/smb2/setinfo.c index a743c2e5d9..5d0055a1bb 100644 --- a/source4/torture/smb2/setinfo.c +++ b/source4/torture/smb2/setinfo.c @@ -134,6 +134,8 @@ BOOL torture_smb2_setinfo(void) goto done; \ }} while (0) + + torture_smb2_all_info(tree, handle); printf("test basic_information level\n"); basetime += 86400; diff --git a/source4/torture/smb2/util.c b/source4/torture/smb2/util.c index bb239bdd1b..56309929ad 100644 --- a/source4/torture/smb2/util.c +++ b/source4/torture/smb2/util.c @@ -60,7 +60,6 @@ NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname) NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; io.in.fname = fname; - io.in.blob = data_blob(NULL, 0); status = smb2_create(tree, tree, &io); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { @@ -93,6 +92,7 @@ NTSTATUS smb2_util_write(struct smb2_tree *tree, */ NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, struct smb2_handle *handle) { + TALLOC_CTX *tmp_ctx = talloc_new(tree); char buf[7] = "abc"; struct smb2_create io; union smb_setfileinfo setfile; @@ -110,9 +110,33 @@ NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, str NTCREATEX_SHARE_ACCESS_WRITE; io.in.create_options = 0; io.in.fname = fname; - io.in.blob = data_blob(NULL, 0); - status = smb2_create(tree, tree, &io); + io.in.sd = security_descriptor_create(tmp_ctx, + NULL, NULL, + SID_NT_AUTHENTICATED_USERS, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_FILE_ALL | SEC_STD_ALL, + 0, + SID_WORLD, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_RIGHTS_FILE_READ | SEC_STD_ALL, + 0, + NULL); + + if (strchr(fname, ':') == NULL) { + /* setup some EAs */ + io.in.eas.num_eas = 2; + io.in.eas.eas = talloc_array(tmp_ctx, struct ea_struct, 2); + io.in.eas.eas[0].flags = 0; + io.in.eas.eas[0].name.s = "EAONE"; + io.in.eas.eas[0].value = data_blob_talloc(tmp_ctx, "VALUE1", 6); + io.in.eas.eas[1].flags = 0; + io.in.eas.eas[1].name.s = "SECONDEA"; + io.in.eas.eas[1].value = data_blob_talloc(tmp_ctx, "ValueTwo", 8); + } + + status = smb2_create(tree, tmp_ctx, &io); + talloc_free(tmp_ctx); NT_STATUS_NOT_OK_RETURN(status); *handle = io.out.handle; @@ -120,26 +144,6 @@ NTSTATUS smb2_create_complex_file(struct smb2_tree *tree, const char *fname, str status = smb2_util_write(tree, *handle, buf, 0, sizeof(buf)); NT_STATUS_NOT_OK_RETURN(status); -#if 0 - if (strchr(fname, ':') == NULL) { - /* setup some EAs */ - setfile.generic.level = RAW_SFILEINFO_EA_SET; - setfile.generic.file.fnum = fnum; - setfile.ea_set.in.num_eas = 2; - setfile.ea_set.in.eas = talloc_array(mem_ctx, struct ea_struct, 2); - setfile.ea_set.in.eas[0].flags = 0; - setfile.ea_set.in.eas[0].name.s = "EAONE"; - setfile.ea_set.in.eas[0].value = data_blob_talloc(mem_ctx, "VALUE1", 6); - setfile.ea_set.in.eas[1].flags = 0; - setfile.ea_set.in.eas[1].name.s = "SECONDEA"; - setfile.ea_set.in.eas[1].value = data_blob_talloc(mem_ctx, "ValueTwo", 8); - status = smb_raw_setfileinfo(cli->tree, &setfile); - if (!NT_STATUS_IS_OK(status)) { - printf("Failed to setup EAs\n"); - } - } -#endif - /* make sure all the timestamps aren't the same, and are also in different DST zones*/ setfile.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; @@ -294,9 +298,8 @@ NTSTATUS torture_smb2_testfile(struct smb2_tree *tree, const char *fname, NTCREATEX_SHARE_ACCESS_DELETE| NTCREATEX_SHARE_ACCESS_READ| NTCREATEX_SHARE_ACCESS_WRITE; - io.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE; + io.in.create_options = 0; io.in.fname = fname; - io.in.blob = data_blob(NULL, 0); status = smb2_create(tree, tree, &io); NT_STATUS_NOT_OK_RETURN(status); @@ -330,7 +333,6 @@ NTSTATUS torture_smb2_testdir(struct smb2_tree *tree, const char *fname, io.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE; io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; io.in.fname = fname; - io.in.blob = data_blob(NULL, 0); status = smb2_create(tree, tree, &io); NT_STATUS_NOT_OK_RETURN(status); diff --git a/source4/torture/torture.c b/source4/torture/torture.c index 3a9fba7dff..434bca2500 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -2255,6 +2255,7 @@ static struct { {"SMB2-CONNECT", torture_smb2_connect, 0}, {"SMB2-SCAN", torture_smb2_scan, 0}, {"SMB2-SCANGETINFO", torture_smb2_getinfo_scan, 0}, + {"SMB2-SCANSETINFO", torture_smb2_setinfo_scan, 0}, {"SMB2-GETINFO", torture_smb2_getinfo, 0}, {"SMB2-SETINFO", torture_smb2_setinfo, 0}, -- cgit