diff options
-rw-r--r-- | source4/include/smb_interfaces.h | 22 | ||||
-rw-r--r-- | source4/include/trans2.h | 1 | ||||
-rw-r--r-- | source4/lib/data_blob.c | 13 | ||||
-rw-r--r-- | source4/libcli/raw/rawfileinfo.c | 2 | ||||
-rw-r--r-- | source4/libcli/raw/rawsearch.c | 61 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_qfileinfo.c | 10 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 21 | ||||
-rw-r--r-- | source4/smb_server/trans2.c | 42 | ||||
-rw-r--r-- | source4/torture/raw/eas.c | 8 | ||||
-rw-r--r-- | source4/torture/raw/search.c | 118 |
10 files changed, 283 insertions, 15 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 9916bf2385..91ed102d6a 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -1675,6 +1675,7 @@ enum smb_search_level {RAW_SEARCH_GENERIC = 0xF000, RAW_SEARCH_FUNIQUE, /* SMBfunique */ RAW_SEARCH_STANDARD = SMB_FIND_STANDARD, RAW_SEARCH_EA_SIZE = SMB_FIND_EA_SIZE, + RAW_SEARCH_EA_LIST = SMB_FIND_EA_LIST, RAW_SEARCH_DIRECTORY_INFO = SMB_FIND_DIRECTORY_INFO, RAW_SEARCH_FULL_DIRECTORY_INFO = SMB_FIND_FULL_DIRECTORY_INFO, RAW_SEARCH_NAME_INFO = SMB_FIND_NAME_INFO, @@ -1715,6 +1716,10 @@ union smb_search_first { uint16_t flags; uint32_t storage_type; const char *pattern; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + uint_t num_names; + struct ea_name *ea_names; } in; struct { uint16_t handle; @@ -1761,6 +1766,10 @@ union smb_search_next { uint32_t resume_key; uint16_t flags; const char *last_name; + + /* the ea names are only used for RAW_SEARCH_EA_LIST */ + uint_t num_names; + struct ea_name *ea_names; } in; struct { uint16_t count; @@ -1805,6 +1814,19 @@ union smb_search_data { WIRE_STRING name; } ea_size; + /* trans2 findfirst RAW_SEARCH_EA_LIST level */ + struct { + uint32_t resume_key; + time_t create_time; + time_t access_time; + time_t write_time; + uint32_t size; + uint32_t alloc_size; + uint16_t attrib; + struct smb_ea_list eas; + WIRE_STRING name; + } ea_list; + /* RAW_SEARCH_DIRECTORY_INFO interface */ struct { uint32_t file_index; diff --git a/source4/include/trans2.h b/source4/include/trans2.h index 9afb9d4c2d..06251ddefe 100644 --- a/source4/include/trans2.h +++ b/source4/include/trans2.h @@ -253,6 +253,7 @@ Found 0 aliased levels */ #define SMB_FIND_STANDARD 1 #define SMB_FIND_EA_SIZE 2 +#define SMB_FIND_EA_LIST 3 #define SMB_FIND_DIRECTORY_INFO 0x101 #define SMB_FIND_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_NAME_INFO 0x103 diff --git a/source4/lib/data_blob.c b/source4/lib/data_blob.c index a4506fee45..1551879933 100644 --- a/source4/lib/data_blob.c +++ b/source4/lib/data_blob.c @@ -160,3 +160,16 @@ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, DATA_BLOB *blob) return hex_string; } + +/* + useful for constructing data blobs in test suites, while + avoiding const warnings +*/ +DATA_BLOB data_blob_string_const(const char *str) +{ + DATA_BLOB blob; + blob.data = discard_const(str); + blob.length = strlen(str); + return blob; +} + diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c index 8f694a23d8..ad7b9b900a 100644 --- a/source4/libcli/raw/rawfileinfo.c +++ b/source4/libcli/raw/rawfileinfo.c @@ -550,7 +550,7 @@ NTSTATUS smb_raw_fileinfo(struct smbcli_tree *tree, Query path info (async send) ****************************************************************************/ struct smbcli_request *smb_raw_pathinfo_send(struct smbcli_tree *tree, - union smb_fileinfo *parms) + union smb_fileinfo *parms) { DATA_BLOB data; struct smbcli_request *req; diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c index d55a47ca26..3c271253e5 100644 --- a/source4/libcli/raw/rawsearch.c +++ b/source4/libcli/raw/rawsearch.c @@ -210,6 +210,15 @@ static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree, tp.in.max_param = 10; tp.in.max_data = smb_raw_max_trans_data(tree, 10); tp.in.setup = &setup; + + if (info_level == RAW_SEARCH_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2ffirst.in.num_names, + io->t2ffirst.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); if (!tp.in.params.data) { @@ -223,7 +232,7 @@ static NTSTATUS smb_raw_search_first_blob(struct smbcli_tree *tree, SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type); smbcli_blob_append_string(tree->session, mem_ctx, &tp.in.params, - io->t2ffirst.in.pattern, STR_TERMINATE); + io->t2ffirst.in.pattern, STR_TERMINATE); status = smb_raw_trans2(tree, mem_ctx, &tp); if (!NT_STATUS_IS_OK(status)) { @@ -262,6 +271,15 @@ static NTSTATUS smb_raw_search_next_blob(struct smbcli_tree *tree, tp.in.max_param = 10; tp.in.max_data = smb_raw_max_trans_data(tree, 10); tp.in.setup = &setup; + + if (info_level == RAW_SEARCH_EA_LIST) { + if (!ea_push_name_list(mem_ctx, + &tp.in.data, + io->t2fnext.in.num_names, + io->t2fnext.in.ea_names)) { + return NT_STATUS_NO_MEMORY; + } + } tp.in.params = data_blob_talloc(mem_ctx, NULL, 12); if (!tp.in.params.data) { @@ -306,6 +324,9 @@ static int parse_trans2_search(struct smbcli_tree *tree, union smb_search_data *data) { uint_t len, ofs; + uint32_t ea_size; + DATA_BLOB eablob; + NTSTATUS status; switch (level) { case RAW_SEARCH_GENERIC: @@ -360,6 +381,44 @@ static int parse_trans2_search(struct smbcli_tree *tree, 26, 27, STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); return len + 27 + 1; + case RAW_SEARCH_EA_LIST: + if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + if (blob->length < 4) return -1; + data->ea_list.resume_key = IVAL(blob->data, 0); + blob->data += 4; + blob->length -= 4; + } + if (blob->length < 28) return -1; + data->ea_list.create_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 0); + data->ea_list.access_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 4); + data->ea_list.write_time = raw_pull_dos_date2(tree->session->transport, + blob->data + 8); + data->ea_list.size = IVAL(blob->data, 12); + data->ea_list.alloc_size = IVAL(blob->data, 16); + data->ea_list.attrib = SVAL(blob->data, 20); + ea_size = IVAL(blob->data, 22); + if (ea_size > 0xFFFF) { + return -1; + } + eablob.data = blob->data + 22; + eablob.length = ea_size; + if (eablob.length > blob->length - 24) { + return -1; + } + status = ea_pull_list(&eablob, mem_ctx, + &data->ea_list.eas.num_eas, + &data->ea_list.eas.eas); + if (!NT_STATUS_IS_OK(status)) { + return -1; + } + len = smbcli_blob_pull_string(tree->session, mem_ctx, blob, + &data->ea_list.name, + 22+ea_size, 23+ea_size, + STR_LEN8BIT | STR_TERMINATE | STR_NOALIGN); + return len + ea_size + 23 + 1; + case RAW_SEARCH_DIRECTORY_INFO: if (blob->length < 65) return -1; ofs = IVAL(blob->data, 0); diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index ae55ad5e98..75a9909492 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -27,11 +27,11 @@ /* reply to a RAW_FILEINFO_EA_LIST call */ -static NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, - struct pvfs_filename *name, int fd, - uint_t num_names, - struct ea_name *names, - struct smb_ea_list *eas) +NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, + struct pvfs_filename *name, int fd, + uint_t num_names, + struct ea_name *names, + struct smb_ea_list *eas) { NTSTATUS status; int i; diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c index c336035218..34f5f2208e 100644 --- a/source4/ntvfs/posix/pvfs_search.c +++ b/source4/ntvfs/posix/pvfs_search.c @@ -35,6 +35,8 @@ struct pvfs_search_state { uint16_t must_attrib; struct pvfs_dir *dir; time_t last_used; + uint_t num_ea_names; + struct ea_name *ea_names; }; @@ -118,6 +120,20 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs, file->ea_size.name.s = fname; return NT_STATUS_OK; + case RAW_SEARCH_EA_LIST: + file->ea_list.resume_key = dir_index; + file->ea_list.create_time = nt_time_to_unix(name->dos.create_time); + file->ea_list.access_time = nt_time_to_unix(name->dos.access_time); + file->ea_list.write_time = nt_time_to_unix(name->dos.write_time); + file->ea_list.size = name->st.st_size; + file->ea_list.alloc_size = name->dos.alloc_size; + file->ea_list.attrib = name->dos.attrib; + file->ea_list.name.s = fname; + return pvfs_query_ea_list(pvfs, file, name, -1, + search->num_ea_names, + search->ea_names, + &file->ea_list.eas); + case RAW_SEARCH_DIRECTORY_INFO: file->directory_info.file_index = dir_index; file->directory_info.create_time = name->dos.create_time; @@ -471,6 +487,8 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs, search->search_attrib = search_attrib; search->must_attrib = 0; search->last_used = 0; + search->num_ea_names = io->t2ffirst.in.num_names; + search->ea_names = io->t2ffirst.in.ea_names; talloc_set_destructor(search, pvfs_search_destructor); @@ -550,6 +568,9 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs, return status; } + search->num_ea_names = io->t2fnext.in.num_names; + search->ea_names = io->t2fnext.in.ea_names; + status = pvfs_search_fill(pvfs, req, io->t2fnext.in.max_count, search, io->generic.level, &reply_count, search_private, callback); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/smb_server/trans2.c b/source4/smb_server/trans2.c index 0c827c92a1..12a4be0e35 100644 --- a/source4/smb_server/trans2.c +++ b/source4/smb_server/trans2.c @@ -1011,6 +1011,7 @@ static void find_fill_info(struct smbsrv_request *req, { uint8_t *data; uint_t ofs = trans->out.data.length; + uint32_t ea_size; switch (state->level) { case RAW_SEARCH_SEARCH: @@ -1061,6 +1062,29 @@ static void find_fill_info(struct smbsrv_request *req, trans->out.data.data[trans->out.data.length-1] = 0; break; + case RAW_SEARCH_EA_LIST: + ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas); + if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) { + trans2_grow_data(req, trans, ofs + 27 + ea_size); + SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key); + ofs += 4; + } else { + trans2_grow_data(req, trans, ofs + 23 + ea_size); + } + data = trans->out.data.data + ofs; + srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time); + srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time); + srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time); + SIVAL(data, 12, file->ea_list.size); + SIVAL(data, 16, file->ea_list.alloc_size); + SSVAL(data, 20, file->ea_list.attrib); + ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas); + trans2_append_data_string(req, trans, &file->ea_list.name, + ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN); + trans2_grow_data(req, trans, trans->out.data.length + 1); + trans->out.data.data[trans->out.data.length-1] = 0; + break; + case RAW_SEARCH_DIRECTORY_INFO: trans2_grow_data(req, trans, ofs + 64); data = trans->out.data.data + ofs; @@ -1233,6 +1257,15 @@ static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct smb_trans2 * return NT_STATUS_INVALID_LEVEL; } + if (search.t2ffirst.level == RAW_SEARCH_EA_LIST) { + status = ea_pull_name_list(&trans->in.data, req, + &search.t2ffirst.in.num_names, + &search.t2ffirst.in.ea_names); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + /* setup the private state structure that the backend will give us in the callback */ state.req = req; state.trans = trans; @@ -1294,6 +1327,15 @@ static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct smb_trans2 *t return NT_STATUS_INVALID_LEVEL; } + if (search.t2fnext.level == RAW_SEARCH_EA_LIST) { + status = ea_pull_name_list(&trans->in.data, req, + &search.t2fnext.in.num_names, + &search.t2fnext.in.ea_names); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + /* setup the private state structure that the backend will give us in the callback */ state.req = req; state.trans = trans; diff --git a/source4/torture/raw/eas.c b/source4/torture/raw/eas.c index 572a551d17..2361091a9b 100644 --- a/source4/torture/raw/eas.c +++ b/source4/torture/raw/eas.c @@ -34,14 +34,6 @@ goto done; \ }} while (0) -static DATA_BLOB data_blob_string_const(const char *str) -{ - DATA_BLOB blob; - blob.data = discard_const(str); - blob.length = strlen(str); - return blob; -} - static BOOL check_ea(struct smbcli_state *cli, const char *fname, const char *eaname, const char *value) { diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index 395b9ff559..ada71f3ee7 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -548,6 +548,13 @@ static NTSTATUS multiple_search(struct smbcli_state *cli, ret = False; \ }} while (0) +#define CHECK_STRING(v, correct) do { \ + if (StrCaseCmp(v, correct) != 0) { \ + printf("(%s) Incorrect value %s='%s' - should be '%s'\n", \ + __location__, #v, v, correct); \ + ret = False; \ + }} while (0) + static int search_both_compare(union smb_search_data *d1, union smb_search_data *d2) { @@ -1171,6 +1178,116 @@ done: } +/* + testing of the rather strange ea_list level +*/ +static BOOL test_ea_list(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + int fnum; + BOOL ret = True; + NTSTATUS status; + union smb_search_first io; + union smb_search_next nxt; + struct multiple_result result; + union smb_setfileinfo setfile; + + if (!torture_setup_dir(cli, BASEDIR)) { + return False; + } + + printf("Testing RAW_SEARCH_EA_LIST level\n"); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file1.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file2.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + fnum = smbcli_open(cli->tree, BASEDIR "\\file3.txt", O_CREAT|O_RDWR, DENY_NONE); + smbcli_close(cli->tree, fnum); + + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.file.fname = BASEDIR "\\file2.txt"; + setfile.ea_set.in.num_eas = 2; + setfile.ea_set.in.eas = talloc_array_p(mem_ctx, struct ea_struct, 2); + setfile.ea_set.in.eas[0].flags = 0; + setfile.ea_set.in.eas[0].name.s = "EA ONE"; + setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE 1"); + setfile.ea_set.in.eas[1].flags = 0; + setfile.ea_set.in.eas[1].name.s = "SECOND EA"; + setfile.ea_set.in.eas[1].value = data_blob_string_const("Value Two"); + + status = smb_raw_setpathinfo(cli->tree, &setfile); + CHECK_STATUS(status, NT_STATUS_OK); + + setfile.generic.file.fname = BASEDIR "\\file3.txt"; + status = smb_raw_setpathinfo(cli->tree, &setfile); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(result); + result.mem_ctx = mem_ctx; + + io.t2ffirst.level = RAW_SEARCH_EA_LIST; + io.t2ffirst.in.search_attrib = 0; + io.t2ffirst.in.max_count = 2; + io.t2ffirst.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME; + io.t2ffirst.in.storage_type = 0; + io.t2ffirst.in.pattern = BASEDIR "\\*"; + io.t2ffirst.in.num_names = 2; + io.t2ffirst.in.ea_names = talloc_array_p(mem_ctx, struct ea_name, 2); + io.t2ffirst.in.ea_names[0].name.s = "SECOND EA"; + io.t2ffirst.in.ea_names[1].name.s = "THIRD EA"; + + status = smb_raw_search_first(cli->tree, mem_ctx, + &io, &result, multiple_search_callback); + CHECK_STATUS(status, NT_STATUS_OK); + + nxt.t2fnext.level = RAW_SEARCH_EA_LIST; + nxt.t2fnext.in.handle = io.t2ffirst.out.handle; + nxt.t2fnext.in.max_count = 2; + nxt.t2fnext.in.resume_key = result.list[1].ea_list.resume_key; + nxt.t2fnext.in.flags = FLAG_TRANS2_FIND_REQUIRE_RESUME | FLAG_TRANS2_FIND_CONTINUE; + nxt.t2fnext.in.last_name = "file2.txt"; + nxt.t2fnext.in.num_names = 2; + nxt.t2fnext.in.ea_names = talloc_array_p(mem_ctx, struct ea_name, 2); + nxt.t2fnext.in.ea_names[0].name.s = "SECOND EA"; + nxt.t2fnext.in.ea_names[1].name.s = "THIRD EA"; + + status = smb_raw_search_next(cli->tree, mem_ctx, + &nxt, &result, multiple_search_callback); + CHECK_STATUS(status, NT_STATUS_OK); + + + CHECK_VALUE(result.count, 3); + CHECK_VALUE(result.list[0].ea_list.eas.num_eas, 2); + CHECK_STRING(result.list[0].ea_list.name.s, "file1.txt"); + CHECK_STRING(result.list[0].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[0].ea_list.eas.eas[0].value.length, 0); + CHECK_STRING(result.list[0].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[0].ea_list.eas.eas[1].value.length, 0); + + CHECK_STRING(result.list[1].ea_list.name.s, "file2.txt"); + CHECK_STRING(result.list[1].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[1].ea_list.eas.eas[0].value.length, 9); + CHECK_STRING(result.list[1].ea_list.eas.eas[0].value.data, "Value Two"); + CHECK_STRING(result.list[1].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[1].ea_list.eas.eas[1].value.length, 0); + + CHECK_STRING(result.list[2].ea_list.name.s, "file3.txt"); + CHECK_STRING(result.list[2].ea_list.eas.eas[0].name.s, "SECOND EA"); + CHECK_VALUE(result.list[2].ea_list.eas.eas[0].value.length, 9); + CHECK_STRING(result.list[2].ea_list.eas.eas[0].value.data, "Value Two"); + CHECK_STRING(result.list[2].ea_list.eas.eas[1].name.s, "THIRD EA"); + CHECK_VALUE(result.list[2].ea_list.eas.eas[1].value.length, 0); + +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + + return ret; +} + + /* basic testing of all RAW_SEARCH_* calls using a single file @@ -1193,6 +1310,7 @@ BOOL torture_raw_search(void) ret &= test_modify_search(cli, mem_ctx); ret &= test_many_dirs(cli, mem_ctx); ret &= test_os2_delete(cli, mem_ctx); + ret &= test_ea_list(cli, mem_ctx); torture_close_connection(cli); talloc_destroy(mem_ctx); |