2 Unix SMB/CIFS implementation.
5 Copyright (C) Stefan Metzmacher 2009
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/>.
22 #include "smbd/globals.h"
23 #include "../source4/libcli/smb2/smb2_constants.h"
25 static struct tevent_req
*smbd_smb2_find_send(TALLOC_CTX
*mem_ctx
,
26 struct tevent_context
*ev
,
27 struct smbd_smb2_request
*smb2req
,
28 uint8_t in_file_info_class
,
30 uint32_t in_file_index
,
31 uint64_t in_file_id_volatile
,
32 uint32_t in_output_buffer_length
,
33 const char *in_file_name
);
34 static NTSTATUS
smbd_smb2_find_recv(struct tevent_req
*req
,
36 DATA_BLOB
*out_output_buffer
);
38 static void smbd_smb2_request_find_done(struct tevent_req
*subreq
);
39 NTSTATUS
smbd_smb2_request_process_find(struct smbd_smb2_request
*req
)
42 const uint8_t *inbody
;
43 int i
= req
->current_idx
;
44 size_t expected_body_size
= 0x21;
46 uint8_t in_file_info_class
;
48 uint32_t in_file_index
;
49 uint64_t in_file_id_persistent
;
50 uint64_t in_file_id_volatile
;
51 uint16_t in_file_name_offset
;
52 uint16_t in_file_name_length
;
53 DATA_BLOB in_file_name_buffer
;
54 char *in_file_name_string
;
55 size_t in_file_name_string_size
;
56 uint32_t in_output_buffer_length
;
57 struct tevent_req
*subreq
;
60 inhdr
= (const uint8_t *)req
->in
.vector
[i
+0].iov_base
;
61 if (req
->in
.vector
[i
+1].iov_len
!= (expected_body_size
& 0xFFFFFFFE)) {
62 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
65 inbody
= (const uint8_t *)req
->in
.vector
[i
+1].iov_base
;
67 body_size
= SVAL(inbody
, 0x00);
68 if (body_size
!= expected_body_size
) {
69 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
72 in_file_info_class
= CVAL(inbody
, 0x02);
73 in_flags
= CVAL(inbody
, 0x03);
74 in_file_index
= IVAL(inbody
, 0x04);
75 in_file_id_persistent
= BVAL(inbody
, 0x08);
76 in_file_id_volatile
= BVAL(inbody
, 0x10);
77 in_file_name_offset
= SVAL(inbody
, 0x18);
78 in_file_name_length
= SVAL(inbody
, 0x1A);
79 in_output_buffer_length
= IVAL(inbody
, 0x1C);
81 if (in_file_name_offset
== 0 && in_file_name_length
== 0) {
83 } else if (in_file_name_offset
!=
84 (SMB2_HDR_BODY
+ (body_size
& 0xFFFFFFFE))) {
85 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
88 if (in_file_name_length
> req
->in
.vector
[i
+2].iov_len
) {
89 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
92 in_file_name_buffer
.data
= (uint8_t *)req
->in
.vector
[i
+2].iov_base
;
93 in_file_name_buffer
.length
= in_file_name_length
;
95 ok
= convert_string_talloc(req
, CH_UTF16
, CH_UNIX
,
96 in_file_name_buffer
.data
,
97 in_file_name_buffer
.length
,
99 &in_file_name_string_size
, false);
101 return smbd_smb2_request_error(req
, NT_STATUS_ILLEGAL_CHARACTER
);
104 if (req
->compat_chain_fsp
) {
106 } else if (in_file_id_persistent
!= 0) {
107 return smbd_smb2_request_error(req
, NT_STATUS_FILE_CLOSED
);
110 subreq
= smbd_smb2_find_send(req
,
111 req
->sconn
->smb2
.event_ctx
,
117 in_output_buffer_length
,
118 in_file_name_string
);
119 if (subreq
== NULL
) {
120 return smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
122 tevent_req_set_callback(subreq
, smbd_smb2_request_find_done
, req
);
124 if (tevent_req_is_in_progress(subreq
)) {
125 return smbd_smb2_request_pending_queue(req
);
131 static void smbd_smb2_request_find_done(struct tevent_req
*subreq
)
133 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
134 struct smbd_smb2_request
);
135 int i
= req
->current_idx
;
139 uint16_t out_output_buffer_offset
;
140 DATA_BLOB out_output_buffer
= data_blob_null
;
142 NTSTATUS error
; /* transport error */
144 status
= smbd_smb2_find_recv(subreq
,
148 if (!NT_STATUS_IS_OK(status
)) {
149 error
= smbd_smb2_request_error(req
, status
);
150 if (!NT_STATUS_IS_OK(error
)) {
151 smbd_server_connection_terminate(req
->sconn
,
158 out_output_buffer_offset
= SMB2_HDR_BODY
+ 0x08;
160 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
162 outbody
= data_blob_talloc(req
->out
.vector
, NULL
, 0x08);
163 if (outbody
.data
== NULL
) {
164 error
= smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
165 if (!NT_STATUS_IS_OK(error
)) {
166 smbd_server_connection_terminate(req
->sconn
,
173 SSVAL(outbody
.data
, 0x00, 0x08 + 1); /* struct size */
174 SSVAL(outbody
.data
, 0x02,
175 out_output_buffer_offset
); /* output buffer offset */
176 SIVAL(outbody
.data
, 0x04,
177 out_output_buffer
.length
); /* output buffer length */
179 outdyn
= out_output_buffer
;
181 error
= smbd_smb2_request_done(req
, outbody
, &outdyn
);
182 if (!NT_STATUS_IS_OK(error
)) {
183 smbd_server_connection_terminate(req
->sconn
,
189 struct smbd_smb2_find_state
{
190 struct smbd_smb2_request
*smb2req
;
191 DATA_BLOB out_output_buffer
;
194 static struct tevent_req
*smbd_smb2_find_send(TALLOC_CTX
*mem_ctx
,
195 struct tevent_context
*ev
,
196 struct smbd_smb2_request
*smb2req
,
197 uint8_t in_file_info_class
,
199 uint32_t in_file_index
,
200 uint64_t in_file_id_volatile
,
201 uint32_t in_output_buffer_length
,
202 const char *in_file_name
)
204 struct tevent_req
*req
;
205 struct smbd_smb2_find_state
*state
;
206 struct smb_request
*smbreq
;
207 connection_struct
*conn
= smb2req
->tcon
->compat_conn
;
210 req
= tevent_req_create(mem_ctx
, &state
,
211 struct smbd_smb2_find_state
);
215 state
->smb2req
= smb2req
;
216 state
->out_output_buffer
= data_blob_null
;
218 DEBUG(10,("smbd_smb2_find_send: file_id[0x%016llX]\n",
219 (unsigned long long)in_file_id_volatile
));
221 smbreq
= smbd_smb2_fake_smb_request(smb2req
);
222 if (tevent_req_nomem(smbreq
, req
)) {
223 return tevent_req_post(req
, ev
);
226 fsp
= file_fsp(smbreq
, (uint16_t)in_file_id_volatile
);
228 tevent_req_nterror(req
, NT_STATUS_FILE_CLOSED
);
229 return tevent_req_post(req
, ev
);
231 if (conn
!= fsp
->conn
) {
232 tevent_req_nterror(req
, NT_STATUS_FILE_CLOSED
);
233 return tevent_req_post(req
, ev
);
235 if (smb2req
->session
->vuid
!= fsp
->vuid
) {
236 tevent_req_nterror(req
, NT_STATUS_FILE_CLOSED
);
237 return tevent_req_post(req
, ev
);
240 tevent_req_nterror(req
, NT_STATUS_NOT_IMPLEMENTED
);
241 return tevent_req_post(req
, ev
);
244 static NTSTATUS
smbd_smb2_find_recv(struct tevent_req
*req
,
246 DATA_BLOB
*out_output_buffer
)
249 struct smbd_smb2_find_state
*state
= tevent_req_data(req
,
250 struct smbd_smb2_find_state
);
252 if (tevent_req_is_nterror(req
, &status
)) {
253 tevent_req_received(req
);
257 *out_output_buffer
= state
->out_output_buffer
;
258 talloc_steal(mem_ctx
, out_output_buffer
->data
);
260 tevent_req_received(req
);