diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source4/smb_server/smb/search.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/smb_server/smb/search.c')
-rw-r--r-- | source4/smb_server/smb/search.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/source4/smb_server/smb/search.c b/source4/smb_server/smb/search.c new file mode 100644 index 0000000..bf47217 --- /dev/null +++ b/source4/smb_server/smb/search.c @@ -0,0 +1,283 @@ +/* + Unix SMB/CIFS implementation. + SMBsearch handling + Copyright (C) Andrew Tridgell 2003 + Copyright (C) James J Myers 2003 <myersjj@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + This file handles the parsing of transact2 requests +*/ + +#include "includes.h" +#include "smb_server/smb_server.h" +#include "ntvfs/ntvfs.h" + + +/* a structure to encapsulate the state information about + * an in-progress search first/next operation */ +struct search_state { + struct smbsrv_request *req; + union smb_search_data *file; + uint16_t last_entry_offset; +}; + +/* + fill a single entry in a search find reply +*/ +static bool find_fill_info(struct smbsrv_request *req, + const union smb_search_data *file) +{ + uint8_t *p; + + if (req->out.data_size + 43 > req_max_data(req)) { + return false; + } + + 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, ' ', 12); + memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 12)); + SCVAL(p,42,0); + + return true; +} + +/* callback function for search first/next */ +static bool find_callback(void *private_data, const union smb_search_data *file) +{ + struct search_state *state = (struct search_state *)private_data; + + return find_fill_info(state->req, file); +} + +/**************************************************************************** + Reply to a search first (async reply) +****************************************************************************/ +static void reply_search_first_send(struct ntvfs_request *ntvfs) +{ + struct smbsrv_request *req; + union smb_search_first *sf; + + SMBSRV_CHECK_ASYNC_STATUS(sf, union smb_search_first); + + SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count); + + smbsrv_send_reply(req); +} + +/**************************************************************************** + Reply to a search next (async reply) +****************************************************************************/ +static void reply_search_next_send(struct ntvfs_request *ntvfs) +{ + struct smbsrv_request *req; + union smb_search_next *sn; + + SMBSRV_CHECK_ASYNC_STATUS(sn, union smb_search_next); + + SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count); + + smbsrv_send_reply(req); +} + +/**************************************************************************** + Reply to a search. +****************************************************************************/ +void smbsrv_reply_search(struct smbsrv_request *req) +{ + union smb_search_first *sf; + uint16_t resume_key_length; + struct search_state *state; + uint8_t *p; + 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; + } + + /* parse request */ + if (req->in.wct != 2) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + SMBSRV_TALLOC_IO_PTR(sf, union smb_search_first); + + p = req->in.data; + p += req_pull_ascii4(&req->in.bufinfo, &sf->search_first.in.pattern, + p, STR_TERMINATE); + if (!sf->search_first.in.pattern) { + smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + if (req_data_oob(&req->in.bufinfo, p, 3)) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + if (*p != 5) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + resume_key_length = SVAL(p, 1); + p += 3; + + /* setup state for callback */ + state = talloc(req, struct search_state); + if (!state) { + smbsrv_send_error(req, NT_STATUS_NO_MEMORY); + return; + } + + state->req = req; + state->file = NULL; + state->last_entry_offset = 0; + + /* construct reply */ + smbsrv_setup_reply(req, 1, 0); + SSVAL(req->out.vwv, VWV(0), 0); + req_append_var_block(req, NULL, 0); + + if (resume_key_length != 0) { + union smb_search_next *sn; + + if (resume_key_length != 21 || + req_data_oob(&req->in.bufinfo, p, 21) || + level == RAW_SEARCH_FUNIQUE) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + /* do a search next operation */ + SMBSRV_TALLOC_IO_PTR(sn, union smb_search_next); + SMBSRV_SETUP_NTVFS_REQUEST(reply_search_next_send, NTVFS_ASYNC_STATE_MAY_ASYNC); + + 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.data_level = RAW_SEARCH_DATA_SEARCH; + 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 */ + SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_next(req->ntvfs, sn, state, find_callback)); + } else { + SMBSRV_SETUP_NTVFS_REQUEST(reply_search_first_send, NTVFS_ASYNC_STATE_MAY_ASYNC); + + /* do a search first operation */ + sf->search_first.level = level; + sf->search_first.data_level = RAW_SEARCH_DATA_SEARCH; + sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1)); + sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0)); + + SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_first(req->ntvfs, sf, state, find_callback)); + } +} + + +/**************************************************************************** + Reply to a fclose (async reply) +****************************************************************************/ +static void reply_fclose_send(struct ntvfs_request *ntvfs) +{ + struct smbsrv_request *req; + + SMBSRV_CHECK_ASYNC_STATUS_SIMPLE; + + /* construct reply */ + smbsrv_setup_reply(req, 1, 0); + + SSVAL(req->out.vwv, VWV(0), 0); + + smbsrv_send_reply(req); +} + + +/**************************************************************************** + Reply to fclose (stop directory search). +****************************************************************************/ +void smbsrv_reply_fclose(struct smbsrv_request *req) +{ + union smb_search_close *sc; + uint16_t resume_key_length; + uint8_t *p; + const char *pattern; + + /* parse request */ + if (req->in.wct != 2) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + SMBSRV_TALLOC_IO_PTR(sc, union smb_search_close); + SMBSRV_SETUP_NTVFS_REQUEST(reply_fclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC); + + p = req->in.data; + p += req_pull_ascii4(&req->in.bufinfo, &pattern, p, STR_TERMINATE); + if (pattern && *pattern) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (req_data_oob(&req->in.bufinfo, p, 3)) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + if (*p != 5) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + resume_key_length = SVAL(p, 1); + p += 3; + + if (resume_key_length != 21) { + smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (req_data_oob(&req->in.bufinfo, p, 21)) { + smbsrv_send_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); + + SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, sc)); + +} |