r23792: convert Samba4 to GPLv3
[tprouty/samba.git] / source4 / smb_server / smb / search.c
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 static 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 */
68 static BOOL find_callback(void *private, const union smb_search_data *file)
69 {
70         struct search_state *state = (struct search_state *)private;
71
72         return find_fill_info(state->req, file);
73 }
74
75 /****************************************************************************
76  Reply to a search first (async reply)
77 ****************************************************************************/
78 static 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 ****************************************************************************/
93 static 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 ****************************************************************************/
108 void 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, &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, 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, 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 ****************************************************************************/
210 static 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 ****************************************************************************/
228 void 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, &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, 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, 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 }