r12528: Add seperate proto headers for ntvfs, tdr, smb_server and nbt_server.
[metze/samba/wip.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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22    This file handles the parsing of transact2 requests
23 */
24
25 #include "includes.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.h"
28
29
30 /* check req->async.status and if not OK then send an error reply */
31 #define CHECK_ASYNC_STATUS do { \
32         if (!NT_STATUS_IS_OK(req->async_states->status)) { \
33                 req_reply_error(req, req->async_states->status); \
34                 return; \
35         }} while (0)
36         
37 /* 
38    check if the backend wants to handle the request asynchronously.
39    if it wants it handled synchronously then call the send function
40    immediately
41 */
42 #define REQ_ASYNC_TAIL do { \
43         if (!(req->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
44                 req->async_states->send_fn(req); \
45         }} while (0)
46
47 /* useful wrapper for talloc with NO_MEMORY reply */
48 #define REQ_TALLOC(ptr) do { \
49         ptr = talloc_size(req, sizeof(*(ptr))); \
50         if (!ptr) { \
51                 req_reply_error(req, NT_STATUS_NO_MEMORY); \
52                 return; \
53         }} while (0)
54                 
55 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
56         if ((blob)->length < (size)) { \
57                 return NT_STATUS_INFO_LENGTH_MISMATCH; \
58         }} while (0)
59
60 /* a structure to encapsulate the state information about 
61  * an in-progress search first/next operation */
62 struct search_state {
63         struct smbsrv_request *req;
64         union smb_search_data *file;
65         uint16_t last_entry_offset;
66 };
67
68 /*
69   fill a single entry in a search find reply 
70 */
71 static BOOL find_fill_info(struct smbsrv_request *req,
72                            union smb_search_data *file)
73 {
74         uint8_t *p;
75
76         if (req->out.data_size + 43 > req_max_data(req)) {
77                 return False;
78         }
79         
80         req_grow_data(req, req->out.data_size + 43);
81         p = req->out.data + req->out.data_size - 43;
82
83         SCVAL(p,  0, file->search.id.reserved);
84         memcpy(p+1, file->search.id.name, 11);
85         SCVAL(p, 12, file->search.id.handle);
86         SIVAL(p, 13, file->search.id.server_cookie);
87         SIVAL(p, 17, file->search.id.client_cookie);
88         SCVAL(p, 21, file->search.attrib);
89         srv_push_dos_date(req->smb_conn, p, 22, file->search.write_time);
90         SIVAL(p, 26, file->search.size);
91         memset(p+30, ' ', 12);
92         memcpy(p+30, file->search.name, MIN(strlen(file->search.name)+1, 12));
93         SCVAL(p,42,0);
94
95         return True;
96 }
97
98 /* callback function for search first/next */
99 static BOOL find_callback(void *private, union smb_search_data *file)
100 {
101         struct search_state *state = (struct search_state *)private;
102
103         return find_fill_info(state->req, file);
104 }
105
106 /****************************************************************************
107  Reply to a search.
108 ****************************************************************************/
109 void reply_search(struct smbsrv_request *req)
110 {
111         union smb_search_first *sf;
112         union smb_search_next *sn;
113         uint16_t resume_key_length;
114         struct search_state state;
115         uint8_t *p;
116         NTSTATUS status;
117         enum smb_search_level level = RAW_SEARCH_SEARCH;
118         uint8_t op = CVAL(req->in.hdr,HDR_COM);
119
120         if (op == SMBffirst) {
121                 level = RAW_SEARCH_FFIRST;
122         } else if (op == SMBfunique) {
123                 level = RAW_SEARCH_FUNIQUE;
124         }
125
126         REQ_TALLOC(sf);
127         
128         /* parse request */
129         if (req->in.wct != 2) {
130                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
131                 return;
132         }
133         
134         p = req->in.data;
135         p += req_pull_ascii4(req, &sf->search_first.in.pattern, 
136                              p, STR_TERMINATE);
137         if (!sf->search_first.in.pattern) {
138                 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
139                 return;
140         }
141
142         if (req_data_oob(req, p, 3)) {
143                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
144                 return;
145         }
146         if (*p != 5) {
147                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
148                 return;
149         }
150         resume_key_length = SVAL(p, 1);
151         p += 3;
152         
153         /* setup state for callback */
154         state.req = req;
155         state.file = NULL;
156         state.last_entry_offset = 0;
157         
158         /* construct reply */
159         req_setup_reply(req, 1, 0);
160         req_append_var_block(req, NULL, 0);
161
162         if (resume_key_length != 0) {
163                 if (resume_key_length != 21 || 
164                     req_data_oob(req, p, 21) ||
165                     level == RAW_SEARCH_FUNIQUE) {
166                         req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
167                         return;
168                 }
169
170                 /* do a search next operation */
171                 REQ_TALLOC(sn);
172
173                 sn->search_next.in.id.reserved      = CVAL(p, 0);
174                 memcpy(sn->search_next.in.id.name,    p+1, 11);
175                 sn->search_next.in.id.handle        = CVAL(p, 12);
176                 sn->search_next.in.id.server_cookie = IVAL(p, 13);
177                 sn->search_next.in.id.client_cookie = IVAL(p, 17);
178
179                 sn->search_next.level = level;
180                 sn->search_next.in.max_count     = SVAL(req->in.vwv, VWV(0));
181                 sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
182                 
183                 /* call backend */
184                 status = ntvfs_search_next(req, sn, &state, find_callback);
185                 SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
186         } else {
187                 /* do a search first operation */
188                 sf->search_first.level = level;
189                 sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
190                 sf->search_first.in.max_count     = SVAL(req->in.vwv, VWV(0));
191                 
192                 /* call backend */
193                 status = ntvfs_search_first(req, sf, &state, find_callback);
194                 SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
195         }
196
197         if (!NT_STATUS_IS_OK(status)) {
198                 req_reply_error(req, status);
199                 return;
200         }
201
202         req_send_reply(req);
203 }
204
205
206 /****************************************************************************
207  Reply to a fclose (async reply)
208 ****************************************************************************/
209 static void reply_fclose_send(struct smbsrv_request *req)
210 {
211         CHECK_ASYNC_STATUS;
212         
213         /* construct reply */
214         req_setup_reply(req, 1, 0);
215
216         SSVAL(req->out.vwv, VWV(0), 0);
217
218         req_send_reply(req);
219 }
220
221
222 /****************************************************************************
223  Reply to fclose (stop directory search).
224 ****************************************************************************/
225 void reply_fclose(struct smbsrv_request *req)
226 {
227         union smb_search_close *sc;
228         uint16_t resume_key_length;
229         uint8_t *p;
230         const char *pattern;
231
232         REQ_TALLOC(sc);
233
234         /* parse request */
235         if (req->in.wct != 2) {
236                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
237                 return;
238         }
239         
240         p = req->in.data;
241         p += req_pull_ascii4(req, &pattern, p, STR_TERMINATE);
242         if (pattern && *pattern) {
243                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
244                 return;
245         }
246         
247         if (req_data_oob(req, p, 3)) {
248                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
249                 return;
250         }
251         if (*p != 5) {
252                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
253                 return;
254         }
255         resume_key_length = SVAL(p, 1);
256         p += 3;
257
258         if (resume_key_length != 21) {
259                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
260                 return;
261         }
262
263         if (req_data_oob(req, p, 21)) {
264                 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
265                 return;
266         }
267
268         sc->fclose.level               = RAW_FINDCLOSE_FCLOSE;
269         sc->fclose.in.max_count        = SVAL(req->in.vwv, VWV(0));
270         sc->fclose.in.search_attrib    = SVAL(req->in.vwv, VWV(1));
271         sc->fclose.in.id.reserved      = CVAL(p, 0);
272         memcpy(sc->fclose.in.id.name,    p+1, 11);
273         sc->fclose.in.id.handle        = CVAL(p, 12);
274         sc->fclose.in.id.server_cookie = IVAL(p, 13);
275         sc->fclose.in.id.client_cookie = IVAL(p, 17);
276
277         /* do a search close operation */
278         req->async_states->state |= NTVFS_ASYNC_STATE_MAY_ASYNC;
279         req->async_states->send_fn = reply_fclose_send;
280         req->async_states->private_data = sc;
281
282         /* call backend */
283         req->async_states->status = ntvfs_search_close(req, sc);
284
285         REQ_ASYNC_TAIL;
286 }