summaryrefslogtreecommitdiffstats
path: root/source4/smb_server/smb/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smb_server/smb/search.c')
-rw-r--r--source4/smb_server/smb/search.c283
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));
+
+}