1/* 2 Unix SMB/CIFS implementation. 3 SMBsearch handling 4 Copyright (C) Andrew Tridgell 2003 5 Copyright (C) James J Myers 2003 <myersjj@samba.org> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20/* 21 This file handles the parsing of transact2 requests 22*/ 23 24#include "includes.h" 25#include "smb_server/smb_server.h" 26#include "ntvfs/ntvfs.h" 27 28 29/* a structure to encapsulate the state information about 30 * an in-progress search first/next operation */ 31struct search_state { 32 struct smbsrv_request *req; 33 union smb_search_data *file; 34 uint16_t last_entry_offset; 35}; 36 37/* 38 fill a single entry in a search find reply 39*/ 40static bool find_fill_info(struct smbsrv_request *req, 41 const union smb_search_data *file) 42{ 43 uint8_t *p; 44 45 if (req->out.data_size + 43 > req_max_data(req)) { 46 return false; 47 } 48 49 req_grow_data(req, req->out.data_size + 43); 50 p = req->out.data + req->out.data_size - 43; 51 52 SCVAL(p, 0, file->search.id.reserved); 53 memcpy(p+1, file->search.id.name, 11); 54 SCVAL(p, 12, file->search.id.handle); 55 SIVAL(p, 13, file->search.id.server_cookie); 56 SIVAL(p, 17, file->search.id.client_cookie); 57 SCVAL(p, 21, file->search.attrib); 58 srv_push_dos_date(req->smb_conn, p, 22, file->search.write_time); 59 SIVAL(p, 26, file->search.size); 60 memset(p+30, ' ', 12); 61 memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 12)); 62 SCVAL(p,42,0); 63 64 return true; 65} 66 67/* callback function for search first/next */ 68static bool find_callback(void *private_data, const union smb_search_data *file) 69{ 70 struct search_state *state = (struct search_state *)private_data; 71 72 return find_fill_info(state->req, file); 73} 74 75/**************************************************************************** 76 Reply to a search first (async reply) 77****************************************************************************/ 78static void reply_search_first_send(struct ntvfs_request *ntvfs) 79{ 80 struct smbsrv_request *req; 81 union smb_search_first *sf; 82 83 SMBSRV_CHECK_ASYNC_STATUS(sf, union smb_search_first); 84 85 SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count); 86 87 smbsrv_send_reply(req); 88} 89 90/**************************************************************************** 91 Reply to a search next (async reply) 92****************************************************************************/ 93static void reply_search_next_send(struct ntvfs_request *ntvfs) 94{ 95 struct smbsrv_request *req; 96 union smb_search_next *sn; 97 98 SMBSRV_CHECK_ASYNC_STATUS(sn, union smb_search_next); 99 100 SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count); 101 102 smbsrv_send_reply(req); 103} 104 105/**************************************************************************** 106 Reply to a search. 107****************************************************************************/ 108void smbsrv_reply_search(struct smbsrv_request *req) 109{ 110 union smb_search_first *sf; 111 uint16_t resume_key_length; 112 struct search_state *state; 113 uint8_t *p; 114 enum smb_search_level level = RAW_SEARCH_SEARCH; 115 uint8_t op = CVAL(req->in.hdr,HDR_COM); 116 117 if (op == SMBffirst) { 118 level = RAW_SEARCH_FFIRST; 119 } else if (op == SMBfunique) { 120 level = RAW_SEARCH_FUNIQUE; 121 } 122 123 /* parse request */ 124 if (req->in.wct != 2) { 125 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 126 return; 127 } 128 129 SMBSRV_TALLOC_IO_PTR(sf, union smb_search_first); 130 131 p = req->in.data; 132 p += req_pull_ascii4(&req->in.bufinfo, &sf->search_first.in.pattern, 133 p, STR_TERMINATE); 134 if (!sf->search_first.in.pattern) { 135 smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); 136 return; 137 } 138 139 if (req_data_oob(&req->in.bufinfo, p, 3)) { 140 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 141 return; 142 } 143 if (*p != 5) { 144 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 145 return; 146 } 147 resume_key_length = SVAL(p, 1); 148 p += 3; 149 150 /* setup state for callback */ 151 state = talloc(req, struct search_state); 152 if (!state) { 153 smbsrv_send_error(req, NT_STATUS_NO_MEMORY); 154 return; 155 } 156 157 state->req = req; 158 state->file = NULL; 159 state->last_entry_offset = 0; 160 161 /* construct reply */ 162 smbsrv_setup_reply(req, 1, 0); 163 SSVAL(req->out.vwv, VWV(0), 0); 164 req_append_var_block(req, NULL, 0); 165 166 if (resume_key_length != 0) { 167 union smb_search_next *sn; 168 169 if (resume_key_length != 21 || 170 req_data_oob(&req->in.bufinfo, p, 21) || 171 level == RAW_SEARCH_FUNIQUE) { 172 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 173 return; 174 } 175 176 /* do a search next operation */ 177 SMBSRV_TALLOC_IO_PTR(sn, union smb_search_next); 178 SMBSRV_SETUP_NTVFS_REQUEST(reply_search_next_send, NTVFS_ASYNC_STATE_MAY_ASYNC); 179 180 sn->search_next.in.id.reserved = CVAL(p, 0); 181 memcpy(sn->search_next.in.id.name, p+1, 11); 182 sn->search_next.in.id.handle = CVAL(p, 12); 183 sn->search_next.in.id.server_cookie = IVAL(p, 13); 184 sn->search_next.in.id.client_cookie = IVAL(p, 17); 185 186 sn->search_next.level = level; 187 sn->search_next.data_level = RAW_SEARCH_DATA_SEARCH; 188 sn->search_next.in.max_count = SVAL(req->in.vwv, VWV(0)); 189 sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1)); 190 191 /* call backend */ 192 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_next(req->ntvfs, sn, state, find_callback)); 193 } else { 194 SMBSRV_SETUP_NTVFS_REQUEST(reply_search_first_send, NTVFS_ASYNC_STATE_MAY_ASYNC); 195 196 /* do a search first operation */ 197 sf->search_first.level = level; 198 sf->search_first.data_level = RAW_SEARCH_DATA_SEARCH; 199 sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1)); 200 sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0)); 201 202 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_first(req->ntvfs, sf, state, find_callback)); 203 } 204} 205 206 207/**************************************************************************** 208 Reply to a fclose (async reply) 209****************************************************************************/ 210static void reply_fclose_send(struct ntvfs_request *ntvfs) 211{ 212 struct smbsrv_request *req; 213 214 SMBSRV_CHECK_ASYNC_STATUS_SIMPLE; 215 216 /* construct reply */ 217 smbsrv_setup_reply(req, 1, 0); 218 219 SSVAL(req->out.vwv, VWV(0), 0); 220 221 smbsrv_send_reply(req); 222} 223 224 225/**************************************************************************** 226 Reply to fclose (stop directory search). 227****************************************************************************/ 228void smbsrv_reply_fclose(struct smbsrv_request *req) 229{ 230 union smb_search_close *sc; 231 uint16_t resume_key_length; 232 uint8_t *p; 233 const char *pattern; 234 235 /* parse request */ 236 if (req->in.wct != 2) { 237 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 238 return; 239 } 240 241 SMBSRV_TALLOC_IO_PTR(sc, union smb_search_close); 242 SMBSRV_SETUP_NTVFS_REQUEST(reply_fclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC); 243 244 p = req->in.data; 245 p += req_pull_ascii4(&req->in.bufinfo, &pattern, p, STR_TERMINATE); 246 if (pattern && *pattern) { 247 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 248 return; 249 } 250 251 if (req_data_oob(&req->in.bufinfo, p, 3)) { 252 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 253 return; 254 } 255 if (*p != 5) { 256 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 257 return; 258 } 259 resume_key_length = SVAL(p, 1); 260 p += 3; 261 262 if (resume_key_length != 21) { 263 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 264 return; 265 } 266 267 if (req_data_oob(&req->in.bufinfo, p, 21)) { 268 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); 269 return; 270 } 271 272 sc->fclose.level = RAW_FINDCLOSE_FCLOSE; 273 sc->fclose.in.max_count = SVAL(req->in.vwv, VWV(0)); 274 sc->fclose.in.search_attrib = SVAL(req->in.vwv, VWV(1)); 275 sc->fclose.in.id.reserved = CVAL(p, 0); 276 memcpy(sc->fclose.in.id.name, p+1, 11); 277 sc->fclose.in.id.handle = CVAL(p, 12); 278 sc->fclose.in.id.server_cookie = IVAL(p, 13); 279 sc->fclose.in.id.client_cookie = IVAL(p, 17); 280 281 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, sc)); 282 283} 284