diff options
-rw-r--r-- | source4/include/smb_interfaces.h | 49 | ||||
-rw-r--r-- | source4/libcli/clilist.c | 6 | ||||
-rw-r--r-- | source4/libcli/raw/rawsearch.c | 92 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 110 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 2 | ||||
-rw-r--r-- | source4/smb_server/reply.c | 2 | ||||
-rw-r--r-- | source4/smb_server/request.c | 2 | ||||
-rw-r--r-- | source4/smb_server/search.c | 160 | ||||
-rw-r--r-- | source4/smb_server/trans2.c | 4 | ||||
-rw-r--r-- | source4/torture/raw/search.c | 21 |
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; |