summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/include/smb_interfaces.h49
-rw-r--r--source4/libcli/clilist.c6
-rw-r--r--source4/libcli/raw/rawsearch.c92
-rw-r--r--source4/ntvfs/posix/pvfs_search.c110
-rw-r--r--source4/ntvfs/posix/vfs_posix.h2
-rw-r--r--source4/smb_server/reply.c2
-rw-r--r--source4/smb_server/request.c2
-rw-r--r--source4/smb_server/search.c160
-rw-r--r--source4/smb_server/trans2.c4
-rw-r--r--source4/torture/raw/search.c21
10 files changed, 331 insertions, 117 deletions
diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h
index 14f8ecfc13..72ca1477dc 100644
--- a/source4/include/smb_interfaces.h
+++ b/source4/include/smb_interfaces.h
@@ -1694,17 +1694,18 @@ struct smb_notify {
enum smb_search_level {RAW_SEARCH_GENERIC = 0xF000,
- RAW_SEARCH_SEARCH, /* SMBsearch */
- RAW_SEARCH_FCLOSE, /* SMBfclose */
- RAW_SEARCH_STANDARD = SMB_FIND_STANDARD,
- RAW_SEARCH_EA_SIZE = SMB_FIND_EA_SIZE,
- 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,
- RAW_SEARCH_BOTH_DIRECTORY_INFO = SMB_FIND_BOTH_DIRECTORY_INFO,
- RAW_SEARCH_ID_FULL_DIRECTORY_INFO = SMB_FIND_ID_FULL_DIRECTORY_INFO,
- RAW_SEARCH_ID_BOTH_DIRECTORY_INFO = SMB_FIND_ID_BOTH_DIRECTORY_INFO,
- RAW_SEARCH_UNIX_INFO = SMB_FIND_UNIX_INFO};
+ RAW_SEARCH_SEARCH, /* SMBsearch */
+ RAW_SEARCH_FFIRST, /* SMBffirst */
+ RAW_SEARCH_FUNIQUE, /* SMBfunique */
+ RAW_SEARCH_STANDARD = SMB_FIND_STANDARD,
+ RAW_SEARCH_EA_SIZE = SMB_FIND_EA_SIZE,
+ 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,
+ RAW_SEARCH_BOTH_DIRECTORY_INFO = SMB_FIND_BOTH_DIRECTORY_INFO,
+ RAW_SEARCH_ID_FULL_DIRECTORY_INFO = SMB_FIND_ID_FULL_DIRECTORY_INFO,
+ RAW_SEARCH_ID_BOTH_DIRECTORY_INFO = SMB_FIND_ID_BOTH_DIRECTORY_INFO,
+ RAW_SEARCH_UNIX_INFO = SMB_FIND_UNIX_INFO};
/* union for file search */
@@ -1713,7 +1714,8 @@ union smb_search_first {
enum smb_search_level level;
} generic;
- /* search (old) findfirst interface */
+ /* search (old) findfirst interface.
+ Also used for ffirst and funique. */
struct {
enum smb_search_level level;
@@ -1752,14 +1754,21 @@ union smb_search_next {
enum smb_search_level level;
} generic;
- /* search (old) findnext interface */
+ /* search (old) findnext interface. Also used
+ for ffirst when continuing */
struct {
enum smb_search_level level;
struct {
uint16_t max_count;
uint16_t search_attrib;
- DATA_BLOB search_id;
+ struct smb_search_id {
+ uint8_t reserved;
+ char name[11];
+ uint8_t handle;
+ uint32_t server_cookie;
+ uint32_t client_cookie;
+ } id;
} in;
struct {
uint16_t count;
@@ -1791,7 +1800,7 @@ union smb_search_data {
uint16_t attrib;
time_t write_time;
uint32_t size;
- DATA_BLOB search_id; /* used to resume search from this point */
+ struct smb_search_id id;
char *name;
} search;
@@ -1920,7 +1929,7 @@ union smb_search_data {
};
-enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_CLOSE};
+enum smb_search_close_level {RAW_FINDCLOSE_GENERIC, RAW_FINDCLOSE_FCLOSE, RAW_FINDCLOSE_FINDCLOSE};
/* union for file search close */
union smb_search_close {
@@ -1933,14 +1942,12 @@ union smb_search_close {
enum smb_search_close_level level;
struct {
+ /* max_count and search_attrib are not used, but are present */
uint16_t max_count;
uint16_t search_attrib;
- DATA_BLOB search_id;
+ struct smb_search_id id;
} in;
- struct {
- uint16_t count;
- } out;
- } search_next;
+ } fclose;
/* SMBfindclose interface */
struct {
diff --git a/source4/libcli/clilist.c b/source4/libcli/clilist.c
index 0e2cdabc0a..91a989d361 100644
--- a/source4/libcli/clilist.c
+++ b/source4/libcli/clilist.c
@@ -29,7 +29,7 @@ struct search_private {
int total_received; /* total received all together */
enum smb_search_level info_level;
const char *last_name; /* used to continue trans2 search */
- DATA_BLOB status; /* used for old-style search */
+ struct smb_search_id id; /* used for old-style search */
};
@@ -238,7 +238,7 @@ static BOOL smbcli_list_old_callback(void *private, union smb_search_data *file)
state->total_received++;
state->ff_searchcount++;
- state->status = file->search.search_id; /* return resume info */
+ state->id = file->search.id; /* return resume info */
return True;
}
@@ -294,7 +294,7 @@ int smbcli_list_old(struct smbcli_tree *tree, const char *Mask, uint16_t attribu
next_parms.search_next.level = RAW_SEARCH_SEARCH;
next_parms.search_next.in.max_count = num_asked;
next_parms.search_next.in.search_attrib = attribute;
- next_parms.search_next.in.search_id = state.status;
+ next_parms.search_next.in.id = state.id;
status = smb_raw_search_next(tree, state.mem_ctx,
&next_parms,
diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c
index 67410283ed..df44dbffa4 100644
--- a/source4/libcli/raw/rawsearch.c
+++ b/source4/libcli/raw/rawsearch.c
@@ -42,11 +42,15 @@ static void smb_raw_search_backend(struct smbcli_request *req,
p = req->in.data + 3;
for (i=0; i < count; i++) {
- search_data.search.search_id = smbcli_req_pull_blob(req, mem_ctx, p, 21);
- search_data.search.attrib = CVAL(p, 21);
- search_data.search.write_time = raw_pull_dos_date(req->transport,
- p + 22);
- search_data.search.size = IVAL(p, 26);
+ search_data.search.id.reserved = CVAL(p, 0);
+ memcpy(search_data.search.id.name, p+1, 11);
+ search_data.search.id.handle = CVAL(p, 12);
+ search_data.search.id.server_cookie = IVAL(p, 13);
+ search_data.search.id.client_cookie = IVAL(p, 17);
+ search_data.search.attrib = CVAL(p, 21);
+ search_data.search.write_time = raw_pull_dos_date(req->transport,
+ p + 22);
+ search_data.search.size = IVAL(p, 26);
smbcli_req_pull_ascii(req, mem_ctx, &search_data.search.name, p+30, 13, STR_ASCII);
if (!callback(private, &search_data)) {
break;
@@ -65,8 +69,15 @@ static NTSTATUS smb_raw_search_first_old(struct smbcli_tree *tree,
{
struct smbcli_request *req;
-
- req = smbcli_request_setup(tree, SMBsearch, 2, 0);
+ uint8_t op = SMBsearch;
+
+ if (io->generic.level == RAW_SEARCH_FFIRST) {
+ op = SMBffirst;
+ } else if (io->generic.level == RAW_SEARCH_FUNIQUE) {
+ op = SMBfunique;
+ }
+
+ req = smbcli_request_setup(tree, op, 2, 0);
if (!req) {
return NT_STATUS_NO_MEMORY;
}
@@ -99,8 +110,14 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
{
struct smbcli_request *req;
+ uint8_t var_block[21];
+ uint8_t op = SMBsearch;
+
+ if (io->generic.level == RAW_SEARCH_FFIRST) {
+ op = SMBffirst;
+ }
- req = smbcli_request_setup(tree, SMBsearch, 2, 0);
+ req = smbcli_request_setup(tree, op, 2, 0);
if (!req) {
return NT_STATUS_NO_MEMORY;
}
@@ -108,7 +125,14 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
smbcli_req_append_ascii4(req, "", STR_TERMINATE);
- smbcli_req_append_var_block(req, io->search_next.in.search_id.data, 21);
+
+ SCVAL(var_block, 0, io->search_next.in.id.reserved);
+ memcpy(&var_block[1], io->search_next.in.id.name, 11);
+ SCVAL(var_block, 12, io->search_next.in.id.handle);
+ SIVAL(var_block, 13, io->search_next.in.id.server_cookie);
+ SIVAL(var_block, 17, io->search_next.in.id.client_cookie);
+
+ smbcli_req_append_var_block(req, var_block, 21);
if (!smbcli_request_send(req) ||
!smbcli_request_receive(req)) {
@@ -123,6 +147,43 @@ static NTSTATUS smb_raw_search_next_old(struct smbcli_tree *tree,
return smbcli_request_destroy(req);
}
+
+/****************************************************************************
+ Old style search next.
+****************************************************************************/
+static NTSTATUS smb_raw_search_close_old(struct smbcli_tree *tree,
+ union smb_search_close *io)
+{
+ struct smbcli_request *req;
+ uint8_t var_block[21];
+
+ req = smbcli_request_setup(tree, SMBfclose, 2, 0);
+ if (!req) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(req->out.vwv, VWV(0), io->fclose.in.max_count);
+ SSVAL(req->out.vwv, VWV(1), io->fclose.in.search_attrib);
+ smbcli_req_append_ascii4(req, "", STR_TERMINATE);
+
+ SCVAL(var_block, 0, io->fclose.in.id.reserved);
+ memcpy(&var_block[1], io->fclose.in.id.name, 11);
+ SCVAL(var_block, 12, io->fclose.in.id.handle);
+ SIVAL(var_block, 13, io->fclose.in.id.server_cookie);
+ SIVAL(var_block, 17, io->fclose.in.id.client_cookie);
+
+ smbcli_req_append_var_block(req, var_block, 21);
+
+ if (!smbcli_request_send(req) ||
+ !smbcli_request_receive(req)) {
+ return smbcli_request_destroy(req);
+ }
+
+ return smbcli_request_destroy(req);
+}
+
+
+
/****************************************************************************
Very raw search first - returns param/data blobs.
****************************************************************************/
@@ -245,6 +306,8 @@ static int parse_trans2_search(struct smbcli_tree *tree,
switch (level) {
case RAW_SEARCH_GENERIC:
case RAW_SEARCH_SEARCH:
+ case RAW_SEARCH_FFIRST:
+ case RAW_SEARCH_FUNIQUE:
/* handled elsewhere */
return -1;
@@ -499,7 +562,9 @@ NTSTATUS smb_raw_search_first(struct smbcli_tree *tree,
DATA_BLOB p_blob, d_blob;
NTSTATUS status;
- if (io->generic.level == RAW_SEARCH_SEARCH) {
+ if (io->generic.level == RAW_SEARCH_SEARCH ||
+ io->generic.level == RAW_SEARCH_FFIRST ||
+ io->generic.level == RAW_SEARCH_FUNIQUE) {
return smb_raw_search_first_old(tree, mem_ctx, io, private, callback);
}
if (io->generic.level >= RAW_SEARCH_GENERIC) {
@@ -543,7 +608,8 @@ NTSTATUS smb_raw_search_next(struct smbcli_tree *tree,
DATA_BLOB p_blob, d_blob;
NTSTATUS status;
- if (io->generic.level == RAW_SEARCH_SEARCH) {
+ if (io->generic.level == RAW_SEARCH_SEARCH ||
+ io->generic.level == RAW_SEARCH_FFIRST) {
return smb_raw_search_next_old(tree, mem_ctx, io, private, callback);
}
if (io->generic.level >= RAW_SEARCH_GENERIC) {
@@ -582,6 +648,10 @@ NTSTATUS smb_raw_search_close(struct smbcli_tree *tree,
union smb_search_close *io)
{
struct smbcli_request *req;
+
+ if (io->generic.level == RAW_FINDCLOSE_FCLOSE) {
+ return smb_raw_search_close_old(tree, io);
+ }
req = smbcli_request_setup(tree, SMBfindclose, 1, 0);
if (!req) {
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index 548d7ad77e..3004e92d51 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -102,31 +102,14 @@ NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *i
NTSTATUS status;
struct pvfs_filename *name;
- switch (io->generic.level) {
- case RAW_SEARCH_SEARCH:
+ if (io->generic.level == RAW_SEARCH_SEARCH) {
max_count = io->search_first.in.max_count;
search_attrib = io->search_first.in.search_attrib;
pattern = io->search_first.in.pattern;
- break;
-
- case RAW_SEARCH_STANDARD:
- case RAW_SEARCH_EA_SIZE:
- case RAW_SEARCH_DIRECTORY_INFO:
- case RAW_SEARCH_FULL_DIRECTORY_INFO:
- case RAW_SEARCH_NAME_INFO:
- case RAW_SEARCH_BOTH_DIRECTORY_INFO:
- case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
- case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
- case RAW_SEARCH_UNIX_INFO:
+ } else {
max_count = io->t2ffirst.in.max_count;
search_attrib = io->t2ffirst.in.search_attrib;
pattern = io->t2ffirst.in.pattern;
- break;
-
- case RAW_SEARCH_FCLOSE:
- case RAW_SEARCH_GENERIC:
- DEBUG(0,("WARNING: Invalid search class %d in pvfs_search_first\n", io->generic.level));
- return NT_STATUS_INVALID_INFO_CLASS;
}
/* resolve the cifs name to a posix name */
@@ -232,7 +215,94 @@ NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
void *search_private,
BOOL (*callback)(void *, union smb_search_data *))
{
- return NT_STATUS_NOT_IMPLEMENTED;
+#if 0
+ struct pvfs_state *pvfs = req->tcon->ntvfs_private;
+ struct search_state *search;
+ union smb_search_data file;
+ uint_t max_count;
+ uint16_t handle;
+ int i;
+
+ if (io->generic.level == RAW_SEARCH_SEARCH) {
+ max_count = io->search_next.in.max_count;
+ search_attrib = io->search_next.in.search_attrib;
+ } else {
+ handle = io->t2fnext.in.handle;
+ }
+
+ if (io->generic.level != RAW_SEARCH_BOTH_DIRECTORY_INFO) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ for (search=private->search; search; search = search->next) {
+ if (search->handle == io->t2fnext.in.handle) break;
+ }
+
+ if (!search) {
+ /* we didn't find the search handle */
+ return NT_STATUS_FOOBAR;
+ }
+
+ dir = search->dir;
+
+ /* the client might be asking for something other than just continuing
+ with the search */
+ if (!(io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) &&
+ (io->t2fnext.in.flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) &&
+ io->t2fnext.in.last_name && *io->t2fnext.in.last_name) {
+ /* look backwards first */
+ for (i=search->current_index; i > 0; i--) {
+ if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
+ search->current_index = i;
+ goto found;
+ }
+ }
+
+ /* then look forwards */
+ for (i=search->current_index+1; i <= dir->count; i++) {
+ if (strcmp(io->t2fnext.in.last_name, dir->files[i-1].name) == 0) {
+ search->current_index = i;
+ goto found;
+ }
+ }
+ }
+
+found:
+ max_count = search->current_index + io->t2fnext.in.max_count;
+
+ if (max_count > dir->count) {
+ max_count = dir->count;
+ }
+
+ for (i = search->current_index; i < max_count;i++) {
+ ZERO_STRUCT(file);
+ unix_to_nt_time(&file.both_directory_info.create_time, dir->files[i].st.st_ctime);
+ unix_to_nt_time(&file.both_directory_info.access_time, dir->files[i].st.st_atime);
+ unix_to_nt_time(&file.both_directory_info.write_time, dir->files[i].st.st_mtime);
+ unix_to_nt_time(&file.both_directory_info.change_time, dir->files[i].st.st_mtime);
+ file.both_directory_info.name.s = dir->files[i].name;
+ file.both_directory_info.short_name.s = dir->files[i].name;
+ file.both_directory_info.size = dir->files[i].st.st_size;
+ file.both_directory_info.attrib = pvfs_unix_to_dos_attrib(dir->files[i].st.st_mode);
+
+ if (!callback(search_private, &file)) {
+ break;
+ }
+ }
+
+ io->t2fnext.out.count = i - search->current_index;
+ io->t2fnext.out.end_of_search = (i == dir->count) ? 1 : 0;
+
+ search->current_index = i;
+
+ /* work out if we are going to keep the search state */
+ if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
+ ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) {
+ DLIST_REMOVE(private->search, search);
+ talloc_free(search);
+ }
+#endif
+ return NT_STATUS_OK;
}
/* close a search */
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 12955ced5c..8b7ddfad88 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -92,9 +92,9 @@ struct pvfs_dir {
/* the state of a search started with pvfs_search_first() */
struct pvfs_search_state {
struct pvfs_search_state *next, *prev;
- uint16_t search_attrib;
uint16_t handle;
uint_t current_index;
+ uint16_t search_attrib;
struct pvfs_dir *dir;
};
diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c
index 5827d64bcd..a1922d54c1 100644
--- a/source4/smb_server/reply.c
+++ b/source4/smb_server/reply.c
@@ -2136,7 +2136,7 @@ void reply_findclose(struct smbsrv_request *req)
NTSTATUS status;
union smb_search_close io;
- io.findclose.level = RAW_FINDCLOSE_CLOSE;
+ io.findclose.level = RAW_FINDCLOSE_FINDCLOSE;
/* parse request */
REQ_CHECK_WCT(req, 1);
diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c
index 80663b9ccc..07b2ee0575 100644
--- a/source4/smb_server/request.c
+++ b/source4/smb_server/request.c
@@ -395,7 +395,7 @@ size_t req_push_str(struct smbsrv_request *req, char *dest, const char *str, int
return the number of bytes added
*/
size_t req_append_bytes(struct smbsrv_request *req,
- const uint8_t *bytes, size_t byte_len)
+ const uint8_t *bytes, size_t byte_len)
{
req_grow_allocation(req, byte_len + req->out.data_size);
memcpy(req->out.data + req->out.data_size, bytes, byte_len);
diff --git a/source4/smb_server/search.c b/source4/smb_server/search.c
index e18ecda887..a99958d6c6 100644
--- a/source4/smb_server/search.c
+++ b/source4/smb_server/search.c
@@ -42,8 +42,8 @@
}} while (0)
/* useful wrapper for talloc with NO_MEMORY reply */
-#define REQ_TALLOC(ptr, size) do { \
- ptr = talloc(req, size); \
+#define REQ_TALLOC(ptr) do { \
+ ptr = talloc(req, sizeof(*(ptr))); \
if (!ptr) { \
req_reply_error(req, NT_STATUS_NO_MEMORY); \
return; \
@@ -68,23 +68,21 @@ struct search_state {
static void find_fill_info(struct smbsrv_request *req,
union smb_search_data *file)
{
- char *p = req->out.data + req->out.data_size;
- uint32_t dos_date;
- char search_name[13];
+ char *p;
- DEBUG(9,("find_fill_info: input file data: attr=0x%x size=%u time=0x%x name=%13s\n",
- file->search.attrib, file->search.size,
- (uint32_t)file->search.write_time, file->search.name));
-
- p += req_append_bytes(req, file->search.search_id.data, 21);
- p += req_append_bytes(req, (char*)&file->search.attrib, 1);
- srv_push_dos_date(req->smb_conn, (uint8_t *)&dos_date, 0, file->search.write_time);
- p += req_append_bytes(req, (char*)&dos_date, 4);
- p += req_append_bytes(req, (char*)&file->search.size, 4);
- memset(&search_name[0], ' ', 13);
- memcpy(&search_name[0], file->search.name,
- MAX(13, strlen(file->search.name)));
- p += req_append_bytes(req, &search_name[0], 13);
+ req_grow_data(req, req->out.data_size + 43);
+ p = req->out.data + req->out.data_size - 43;
+
+ SCVAL(p, 0, file->search.id.reserved);
+ memcpy(p+1, file->search.id.name, 11);
+ SCVAL(p, 12, file->search.id.handle);
+ SIVAL(p, 13, file->search.id.server_cookie);
+ SIVAL(p, 17, file->search.id.client_cookie);
+ SCVAL(p, 21, file->search.attrib);
+ srv_push_dos_date(req->smb_conn, p, 22, file->search.write_time);
+ SIVAL(p, 26, file->search.size);
+ memset(p+30, ' ', 13);
+ memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 13));
}
/* callback function for search first/next */
@@ -104,12 +102,20 @@ void reply_search(struct smbsrv_request *req)
{
union smb_search_first *sf;
union smb_search_next *sn;
- DATA_BLOB resume_key;
uint16_t resume_key_length;
struct search_state state;
char *p;
+ NTSTATUS status;
+ enum smb_search_level level = RAW_SEARCH_SEARCH;
+ uint8_t op = CVAL(req->in.hdr,HDR_COM);
+
+ if (op == SMBffirst) {
+ level = RAW_SEARCH_FFIRST;
+ } else if (op == SMBfunique) {
+ level = RAW_SEARCH_FUNIQUE;
+ }
- REQ_TALLOC(sf, sizeof(*sf));
+ REQ_TALLOC(sf);
/* parse request */
if (req->in.wct != 2) {
@@ -119,18 +125,22 @@ void reply_search(struct smbsrv_request *req)
p = req->in.data;
p += req_pull_ascii4(req, &sf->search_first.in.pattern,
- p, STR_TERMINATE);
+ p, STR_TERMINATE);
if (!sf->search_first.in.pattern) {
req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
return;
}
- /* pull in type 5 byte and length */
- if (!req_pull_blob(req, p, 3, &resume_key))
+
+ if (req_data_oob(req, p, 3)) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
- resume_key_length = SVAL(resume_key.data, 1);
+ return;
+ }
+ if (*p != 5) {
+ req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ resume_key_length = SVAL(p, 1);
p += 3;
- DEBUG(19,("reply_search: pattern=%s, key_length=%d\n",
- sf->search_first.in.pattern, resume_key_length));
/* setup state for callback */
state.req = req;
@@ -141,34 +151,46 @@ void reply_search(struct smbsrv_request *req)
req_setup_reply(req, 1, 0);
req_append_var_block(req, NULL, 0);
- if (resume_key_length > 0) {
- /* do a search next operation */
- REQ_TALLOC(sn, sizeof(*sn));
- sn->search_next.level = RAW_SEARCH_SEARCH;
- req->async.private = sn;
- if (!req_pull_blob(req, req->in.data, resume_key_length,
- &(sn->search_next.in.search_id)))
+ if (resume_key_length != 0) {
+ if (resume_key_length != 21 ||
+ req_data_oob(req, p, 21) ||
+ level == RAW_SEARCH_FUNIQUE) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
- sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
+ return;
+ }
+
+ /* do a search next operation */
+ REQ_TALLOC(sn);
+
+ sn->search_next.in.id.reserved = CVAL(p, 0);
+ memcpy(sn->search_next.in.id.name, p+1, 11);
+ sn->search_next.in.id.handle = CVAL(p, 12);
+ sn->search_next.in.id.server_cookie = IVAL(p, 13);
+ sn->search_next.in.id.client_cookie = IVAL(p, 17);
+
+ sn->search_next.level = level;
sn->search_next.in.max_count = SVAL(req->in.vwv, VWV(0));
+ sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
/* call backend */
- req->async.status = req->tcon->ntvfs_ops->search_next(req,
- sn, &state, find_callback);
+ status = req->tcon->ntvfs_ops->search_next(req, sn, &state, find_callback);
SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
} else {
/* do a search first operation */
- req->async.private = sf;
- sf->search_first.level = RAW_SEARCH_SEARCH;
+ sf->search_first.level = level;
sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0));
/* call backend */
- req->async.status = req->tcon->ntvfs_ops->search_first(req,
- sf, &state, find_callback);
+ status = req->tcon->ntvfs_ops->search_first(req, sf, &state, find_callback);
SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
}
+ if (!NT_STATUS_IS_OK(status)) {
+ req_reply_error(req, status);
+ return;
+ }
+
req_send_reply(req);
}
@@ -183,6 +205,8 @@ static void reply_fclose_send(struct smbsrv_request *req)
/* construct reply */
req_setup_reply(req, 1, 0);
+ SSVAL(req->out.vwv, VWV(0), 0);
+
req_send_reply(req);
}
@@ -192,11 +216,12 @@ static void reply_fclose_send(struct smbsrv_request *req)
****************************************************************************/
void reply_fclose(struct smbsrv_request *req)
{
- union smb_search_next *sn;
- DATA_BLOB resume_key;
+ union smb_search_close *sc;
uint16_t resume_key_length;
+ char *p;
+ const char *pattern;
- REQ_TALLOC(sn, sizeof(*sn));
+ REQ_TALLOC(sc);
/* parse request */
if (req->in.wct != 2) {
@@ -204,26 +229,49 @@ void reply_fclose(struct smbsrv_request *req)
return;
}
- sn->search_next.level = RAW_SEARCH_FCLOSE;
+ p = req->in.data;
+ p += req_pull_ascii4(req, &pattern, p, STR_TERMINATE);
+ if (pattern && *pattern) {
+ req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
- /* pull in type 5 byte and length */
- if (!req_pull_blob(req, req->in.data, 3, &resume_key))
+ if (req_data_oob(req, p, 3)) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
- resume_key_length = SVAL(resume_key.data, 1);
- if (resume_key_length > 0) {
- /* do a search close operation */
- if (!req_pull_blob(req, req->in.data, resume_key_length,
- &(sn->search_next.in.search_id)))
- req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
- } else
+ return;
+ }
+ if (*p != 5) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ resume_key_length = SVAL(p, 1);
+ p += 3;
+
+ if (resume_key_length != 21) {
+ req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ if (req_data_oob(req, p, 21)) {
+ req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ sc->fclose.level = RAW_FINDCLOSE_FCLOSE;
+ sc->fclose.in.max_count = SVAL(req->in.vwv, VWV(0));
+ sc->fclose.in.search_attrib = SVAL(req->in.vwv, VWV(1));
+ sc->fclose.in.id.reserved = CVAL(p, 0);
+ memcpy(sc->fclose.in.id.name, p+1, 11);
+ sc->fclose.in.id.handle = CVAL(p, 12);
+ sc->fclose.in.id.server_cookie = IVAL(p, 13);
+ sc->fclose.in.id.client_cookie = IVAL(p, 17);
+ /* do a search close operation */
req->async.send_fn = reply_fclose_send;
- req->async.private = sn;
+ req->async.private = sc;
/* call backend */
- req->async.status = req->tcon->ntvfs_ops->search_next(req, sn,
- NULL, NULL);
+ req->async.status = req->tcon->ntvfs_ops->search_close(req, sc);
REQ_ASYNC_TAIL;
}
diff --git a/source4/smb_server/trans2.c b/source4/smb_server/trans2.c
index 57a385fe27..6e02ddc90d 100644
--- a/source4/smb_server/trans2.c
+++ b/source4/smb_server/trans2.c
@@ -885,6 +885,8 @@ static void find_fill_info(struct smbsrv_request *req,
switch (state->level) {
case RAW_SEARCH_SEARCH:
+ case RAW_SEARCH_FFIRST:
+ case RAW_SEARCH_FUNIQUE:
case RAW_SEARCH_GENERIC:
/* handled elsewhere */
break;
@@ -926,6 +928,8 @@ static void find_fill_info(struct smbsrv_request *req,
SIVAL(data, 22, file->ea_size.ea_size);
trans2_append_data_string(req, trans, &file->ea_size.name,
ofs + 26, 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:
diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c
index d1619d9191..3a469b3a2d 100644
--- a/source4/torture/raw/search.c
+++ b/source4/torture/raw/search.c
@@ -45,10 +45,13 @@ static NTSTATUS single_search(struct smbcli_state *cli,
union smb_search_data *data)
{
union smb_search_first io;
+ union smb_search_close c;
NTSTATUS status;
io.generic.level = level;
- if (level == RAW_SEARCH_SEARCH) {
+ if (level == RAW_SEARCH_SEARCH ||
+ level == RAW_SEARCH_FFIRST ||
+ level == RAW_SEARCH_FUNIQUE) {
io.search_first.in.max_count = 1;
io.search_first.in.search_attrib = 0;
io.search_first.in.pattern = pattern;
@@ -62,6 +65,14 @@ static NTSTATUS single_search(struct smbcli_state *cli,
status = smb_raw_search_first(cli->tree, mem_ctx,
&io, (void *)data, single_search_callback);
+
+ if (NT_STATUS_IS_OK(status) && level == RAW_SEARCH_FFIRST) {
+ c.fclose.level = RAW_FINDCLOSE_FCLOSE;
+ c.fclose.in.max_count = 1;
+ c.fclose.in.search_attrib = 0;
+ c.fclose.in.id = data->search.id;
+ status = smb_raw_search_close(cli->tree, &c);
+ }
return status;
}
@@ -74,6 +85,8 @@ static struct {
NTSTATUS status;
union smb_search_data data;
} levels[] = {
+ {"FFIRST", RAW_SEARCH_FFIRST, },
+ {"FUNIQUE", RAW_SEARCH_FUNIQUE, },
{"SEARCH", RAW_SEARCH_SEARCH, },
{"STANDARD", RAW_SEARCH_STANDARD, },
{"EA_SIZE", RAW_SEARCH_EA_SIZE, },
@@ -151,7 +164,9 @@ static BOOL test_one_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
levels[i].level, &levels[i].data);
expected_status = NT_STATUS_NO_SUCH_FILE;
- if (levels[i].level == RAW_SEARCH_SEARCH) {
+ if (levels[i].level == RAW_SEARCH_SEARCH ||
+ levels[i].level == RAW_SEARCH_FFIRST ||
+ levels[i].level == RAW_SEARCH_FUNIQUE) {
expected_status = STATUS_NO_MORE_FILES;
}
if (!NT_STATUS_EQUAL(status, expected_status)) {
@@ -447,7 +462,7 @@ static NTSTATUS multiple_search(struct smbcli_state *cli,
if (level == RAW_SEARCH_SEARCH) {
io2.search_next.in.max_count = per_search;
io2.search_next.in.search_attrib = 0;
- io2.search_next.in.search_id = result->list[result->count-1].search.search_id;
+ io2.search_next.in.id = result->list[result->count-1].search.id;
} else {
io2.t2fnext.in.handle = io.t2ffirst.out.handle;
io2.t2fnext.in.max_count = per_search;