diff options
Diffstat (limited to 'source4/smb_server/search.c')
-rw-r--r-- | source4/smb_server/search.c | 160 |
1 files changed, 104 insertions, 56 deletions
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; } |