Line data Source code
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 */
31 : struct 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 : */
40 12775 : static bool find_fill_info(struct smbsrv_request *req,
41 : const union smb_search_data *file)
42 : {
43 0 : uint8_t *p;
44 :
45 12775 : if (req->out.data_size + 43 > req_max_data(req)) {
46 0 : return false;
47 : }
48 :
49 12775 : req_grow_data(req, req->out.data_size + 43);
50 12775 : p = req->out.data + req->out.data_size - 43;
51 :
52 12775 : SCVAL(p, 0, file->search.id.reserved);
53 12775 : memcpy(p+1, file->search.id.name, 11);
54 12775 : SCVAL(p, 12, file->search.id.handle);
55 12775 : SIVAL(p, 13, file->search.id.server_cookie);
56 12775 : SIVAL(p, 17, file->search.id.client_cookie);
57 12775 : SCVAL(p, 21, file->search.attrib);
58 12775 : srv_push_dos_date(req->smb_conn, p, 22, file->search.write_time);
59 12775 : SIVAL(p, 26, file->search.size);
60 12775 : memset(p+30, ' ', 12);
61 12775 : memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 12));
62 12775 : SCVAL(p,42,0);
63 :
64 12775 : return true;
65 : }
66 :
67 : /* callback function for search first/next */
68 12775 : static bool find_callback(void *private_data, const union smb_search_data *file)
69 : {
70 12775 : struct search_state *state = (struct search_state *)private_data;
71 :
72 12775 : return find_fill_info(state->req, file);
73 : }
74 :
75 : /****************************************************************************
76 : Reply to a search first (async reply)
77 : ****************************************************************************/
78 36 : static void reply_search_first_send(struct ntvfs_request *ntvfs)
79 : {
80 0 : struct smbsrv_request *req;
81 0 : union smb_search_first *sf;
82 :
83 36 : SMBSRV_CHECK_ASYNC_STATUS(sf, union smb_search_first);
84 :
85 33 : SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
86 :
87 33 : smbsrv_send_reply(req);
88 : }
89 :
90 : /****************************************************************************
91 : Reply to a search next (async reply)
92 : ****************************************************************************/
93 77 : static void reply_search_next_send(struct ntvfs_request *ntvfs)
94 : {
95 0 : struct smbsrv_request *req;
96 0 : union smb_search_next *sn;
97 :
98 77 : SMBSRV_CHECK_ASYNC_STATUS(sn, union smb_search_next);
99 :
100 77 : SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
101 :
102 77 : smbsrv_send_reply(req);
103 : }
104 :
105 : /****************************************************************************
106 : Reply to a search.
107 : ****************************************************************************/
108 113 : void smbsrv_reply_search(struct smbsrv_request *req)
109 : {
110 0 : union smb_search_first *sf;
111 0 : uint16_t resume_key_length;
112 0 : struct search_state *state;
113 0 : uint8_t *p;
114 113 : enum smb_search_level level = RAW_SEARCH_SEARCH;
115 113 : uint8_t op = CVAL(req->in.hdr,HDR_COM);
116 :
117 113 : if (op == SMBffirst) {
118 2 : level = RAW_SEARCH_FFIRST;
119 111 : } else if (op == SMBfunique) {
120 2 : level = RAW_SEARCH_FUNIQUE;
121 : }
122 :
123 : /* parse request */
124 113 : if (req->in.wct != 2) {
125 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
126 0 : return;
127 : }
128 :
129 113 : SMBSRV_TALLOC_IO_PTR(sf, union smb_search_first);
130 :
131 113 : p = req->in.data;
132 113 : p += req_pull_ascii4(&req->in.bufinfo, &sf->search_first.in.pattern,
133 : p, STR_TERMINATE);
134 113 : if (!sf->search_first.in.pattern) {
135 0 : smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
136 0 : return;
137 : }
138 :
139 113 : if (req_data_oob(&req->in.bufinfo, p, 3)) {
140 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
141 0 : return;
142 : }
143 113 : if (*p != 5) {
144 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
145 0 : return;
146 : }
147 113 : resume_key_length = SVAL(p, 1);
148 113 : p += 3;
149 :
150 : /* setup state for callback */
151 113 : state = talloc(req, struct search_state);
152 113 : if (!state) {
153 0 : smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
154 0 : return;
155 : }
156 :
157 113 : state->req = req;
158 113 : state->file = NULL;
159 113 : state->last_entry_offset = 0;
160 :
161 : /* construct reply */
162 113 : smbsrv_setup_reply(req, 1, 0);
163 113 : SSVAL(req->out.vwv, VWV(0), 0);
164 113 : req_append_var_block(req, NULL, 0);
165 :
166 113 : if (resume_key_length != 0) {
167 0 : union smb_search_next *sn;
168 :
169 154 : if (resume_key_length != 21 ||
170 154 : req_data_oob(&req->in.bufinfo, p, 21) ||
171 : level == RAW_SEARCH_FUNIQUE) {
172 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
173 0 : return;
174 : }
175 :
176 : /* do a search next operation */
177 77 : SMBSRV_TALLOC_IO_PTR(sn, union smb_search_next);
178 77 : SMBSRV_SETUP_NTVFS_REQUEST(reply_search_next_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
179 :
180 77 : sn->search_next.in.id.reserved = CVAL(p, 0);
181 77 : memcpy(sn->search_next.in.id.name, p+1, 11);
182 77 : sn->search_next.in.id.handle = CVAL(p, 12);
183 77 : sn->search_next.in.id.server_cookie = IVAL(p, 13);
184 77 : sn->search_next.in.id.client_cookie = IVAL(p, 17);
185 :
186 77 : sn->search_next.level = level;
187 77 : sn->search_next.data_level = RAW_SEARCH_DATA_SEARCH;
188 77 : sn->search_next.in.max_count = SVAL(req->in.vwv, VWV(0));
189 77 : sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
190 :
191 : /* call backend */
192 77 : SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_next(req->ntvfs, sn, state, find_callback));
193 : } else {
194 36 : SMBSRV_SETUP_NTVFS_REQUEST(reply_search_first_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
195 :
196 : /* do a search first operation */
197 36 : sf->search_first.level = level;
198 36 : sf->search_first.data_level = RAW_SEARCH_DATA_SEARCH;
199 36 : sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
200 36 : sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0));
201 :
202 36 : 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 : ****************************************************************************/
210 1 : static void reply_fclose_send(struct ntvfs_request *ntvfs)
211 : {
212 0 : struct smbsrv_request *req;
213 :
214 1 : SMBSRV_CHECK_ASYNC_STATUS_SIMPLE;
215 :
216 : /* construct reply */
217 1 : smbsrv_setup_reply(req, 1, 0);
218 :
219 1 : SSVAL(req->out.vwv, VWV(0), 0);
220 :
221 1 : smbsrv_send_reply(req);
222 : }
223 :
224 :
225 : /****************************************************************************
226 : Reply to fclose (stop directory search).
227 : ****************************************************************************/
228 1 : void smbsrv_reply_fclose(struct smbsrv_request *req)
229 : {
230 0 : union smb_search_close *sc;
231 0 : uint16_t resume_key_length;
232 0 : uint8_t *p;
233 0 : const char *pattern;
234 :
235 : /* parse request */
236 1 : if (req->in.wct != 2) {
237 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
238 0 : return;
239 : }
240 :
241 1 : SMBSRV_TALLOC_IO_PTR(sc, union smb_search_close);
242 1 : SMBSRV_SETUP_NTVFS_REQUEST(reply_fclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
243 :
244 1 : p = req->in.data;
245 1 : p += req_pull_ascii4(&req->in.bufinfo, &pattern, p, STR_TERMINATE);
246 1 : if (pattern && *pattern) {
247 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
248 0 : return;
249 : }
250 :
251 1 : if (req_data_oob(&req->in.bufinfo, p, 3)) {
252 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
253 0 : return;
254 : }
255 1 : if (*p != 5) {
256 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
257 0 : return;
258 : }
259 1 : resume_key_length = SVAL(p, 1);
260 1 : p += 3;
261 :
262 1 : if (resume_key_length != 21) {
263 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
264 0 : return;
265 : }
266 :
267 1 : if (req_data_oob(&req->in.bufinfo, p, 21)) {
268 0 : smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
269 0 : return;
270 : }
271 :
272 1 : sc->fclose.level = RAW_FINDCLOSE_FCLOSE;
273 1 : sc->fclose.in.max_count = SVAL(req->in.vwv, VWV(0));
274 1 : sc->fclose.in.search_attrib = SVAL(req->in.vwv, VWV(1));
275 1 : sc->fclose.in.id.reserved = CVAL(p, 0);
276 1 : memcpy(sc->fclose.in.id.name, p+1, 11);
277 1 : sc->fclose.in.id.handle = CVAL(p, 12);
278 1 : sc->fclose.in.id.server_cookie = IVAL(p, 13);
279 1 : sc->fclose.in.id.client_cookie = IVAL(p, 17);
280 :
281 1 : SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req->ntvfs, sc));
282 :
283 : }
|