summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/smb_interfaces.h22
-rw-r--r--source4/include/trans2.h1
-rw-r--r--source4/lib/data_blob.c13
-rw-r--r--source4/libcli/raw/rawfileinfo.c2
-rw-r--r--source4/libcli/raw/rawsearch.c61
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c10
-rw-r--r--source4/ntvfs/posix/pvfs_search.c21
-rw-r--r--source4/smb_server/trans2.c42
-rw-r--r--source4/torture/raw/eas.c8
-rw-r--r--source4/torture/raw/search.c118
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);