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