2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
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.
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.
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/>.
21 This file handles the parsing of transact2 requests
25 #include "smb_server/smb_server.h"
26 #include "ntvfs/ntvfs.h"
29 /* a structure to encapsulate the state information about
30 * an in-progress search first/next operation */
32 struct smbsrv_request
*req
;
33 union smb_search_data
*file
;
34 uint16_t last_entry_offset
;
38 fill a single entry in a search find reply
40 static bool find_fill_info(struct smbsrv_request
*req
,
41 const union smb_search_data
*file
)
45 if (req
->out
.data_size
+ 43 > req_max_data(req
)) {
49 req_grow_data(req
, req
->out
.data_size
+ 43);
50 p
= req
->out
.data
+ req
->out
.data_size
- 43;
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));
67 /* callback function for search first/next */
68 static bool find_callback(void *private_data
, const union smb_search_data
*file
)
70 struct search_state
*state
= (struct search_state
*)private_data
;
72 return find_fill_info(state
->req
, file
);
75 /****************************************************************************
76 Reply to a search first (async reply)
77 ****************************************************************************/
78 static void reply_search_first_send(struct ntvfs_request
*ntvfs
)
80 struct smbsrv_request
*req
;
81 union smb_search_first
*sf
;
83 SMBSRV_CHECK_ASYNC_STATUS(sf
, union smb_search_first
);
85 SSVAL(req
->out
.vwv
, VWV(0), sf
->search_first
.out
.count
);
87 smbsrv_send_reply(req
);
90 /****************************************************************************
91 Reply to a search next (async reply)
92 ****************************************************************************/
93 static void reply_search_next_send(struct ntvfs_request
*ntvfs
)
95 struct smbsrv_request
*req
;
96 union smb_search_next
*sn
;
98 SMBSRV_CHECK_ASYNC_STATUS(sn
, union smb_search_next
);
100 SSVAL(req
->out
.vwv
, VWV(0), sn
->search_next
.out
.count
);
102 smbsrv_send_reply(req
);
105 /****************************************************************************
107 ****************************************************************************/
108 void smbsrv_reply_search(struct smbsrv_request
*req
)
110 union smb_search_first
*sf
;
111 uint16_t resume_key_length
;
112 struct search_state
*state
;
114 enum smb_search_level level
= RAW_SEARCH_SEARCH
;
115 uint8_t op
= CVAL(req
->in
.hdr
,HDR_COM
);
117 if (op
== SMBffirst
) {
118 level
= RAW_SEARCH_FFIRST
;
119 } else if (op
== SMBfunique
) {
120 level
= RAW_SEARCH_FUNIQUE
;
124 if (req
->in
.wct
!= 2) {
125 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
129 SMBSRV_TALLOC_IO_PTR(sf
, union smb_search_first
);
132 p
+= req_pull_ascii4(&req
->in
.bufinfo
, &sf
->search_first
.in
.pattern
,
134 if (!sf
->search_first
.in
.pattern
) {
135 smbsrv_send_error(req
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
139 if (req_data_oob(&req
->in
.bufinfo
, p
, 3)) {
140 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
144 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
147 resume_key_length
= SVAL(p
, 1);
150 /* setup state for callback */
151 state
= talloc(req
, struct search_state
);
153 smbsrv_send_error(req
, NT_STATUS_NO_MEMORY
);
159 state
->last_entry_offset
= 0;
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);
166 if (resume_key_length
!= 0) {
167 union smb_search_next
*sn
;
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
);
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
);
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);
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));
192 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_next(req
->ntvfs
, sn
, state
, find_callback
));
194 SMBSRV_SETUP_NTVFS_REQUEST(reply_search_first_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
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));
202 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_first(req
->ntvfs
, sf
, state
, find_callback
));
207 /****************************************************************************
208 Reply to a fclose (async reply)
209 ****************************************************************************/
210 static void reply_fclose_send(struct ntvfs_request
*ntvfs
)
212 struct smbsrv_request
*req
;
214 SMBSRV_CHECK_ASYNC_STATUS_SIMPLE
;
216 /* construct reply */
217 smbsrv_setup_reply(req
, 1, 0);
219 SSVAL(req
->out
.vwv
, VWV(0), 0);
221 smbsrv_send_reply(req
);
225 /****************************************************************************
226 Reply to fclose (stop directory search).
227 ****************************************************************************/
228 void smbsrv_reply_fclose(struct smbsrv_request
*req
)
230 union smb_search_close
*sc
;
231 uint16_t resume_key_length
;
236 if (req
->in
.wct
!= 2) {
237 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
241 SMBSRV_TALLOC_IO_PTR(sc
, union smb_search_close
);
242 SMBSRV_SETUP_NTVFS_REQUEST(reply_fclose_send
, NTVFS_ASYNC_STATE_MAY_ASYNC
);
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
);
251 if (req_data_oob(&req
->in
.bufinfo
, p
, 3)) {
252 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
256 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
259 resume_key_length
= SVAL(p
, 1);
262 if (resume_key_length
!= 21) {
263 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
267 if (req_data_oob(&req
->in
.bufinfo
, p
, 21)) {
268 smbsrv_send_error(req
, NT_STATUS_INVALID_PARAMETER
);
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);
281 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_search_close(req
->ntvfs
, sc
));