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_create_send(TALLOC_CTX
*mem_ctx
,
26 struct tevent_context
*ev
,
27 struct smbd_smb2_request
*smb2req
,
28 uint8_t in_oplock_level
,
29 uint32_t in_impersonation_level
,
30 uint32_t in_desired_access
,
31 uint32_t in_file_attributes
,
32 uint32_t in_share_access
,
33 uint32_t in_create_disposition
,
34 uint32_t in_create_options
,
36 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
37 uint8_t *out_oplock_level
,
38 uint32_t *out_create_action
,
39 NTTIME
*out_creation_time
,
40 NTTIME
*out_last_access_time
,
41 NTTIME
*out_last_write_time
,
42 NTTIME
*out_change_time
,
43 uint64_t *out_allocation_size
,
44 uint64_t *out_end_of_file
,
45 uint32_t *out_file_attributes
,
46 uint64_t *out_file_id_volatile
);
48 static void smbd_smb2_request_create_done(struct tevent_req
*subreq
);
49 NTSTATUS
smbd_smb2_request_process_create(struct smbd_smb2_request
*req
)
51 const uint8_t *inbody
;
52 int i
= req
->current_idx
;
53 size_t expected_body_size
= 0x39;
55 uint8_t in_oplock_level
;
56 uint32_t in_impersonation_level
;
57 uint32_t in_desired_access
;
58 uint32_t in_file_attributes
;
59 uint32_t in_share_access
;
60 uint32_t in_create_disposition
;
61 uint32_t in_create_options
;
62 uint16_t in_name_offset
;
63 uint16_t in_name_length
;
64 DATA_BLOB in_name_buffer
;
66 size_t in_name_string_size
;
68 struct tevent_req
*subreq
;
70 if (req
->in
.vector
[i
+1].iov_len
!= (expected_body_size
& 0xFFFFFFFE)) {
71 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
74 inbody
= (const uint8_t *)req
->in
.vector
[i
+1].iov_base
;
76 body_size
= SVAL(inbody
, 0x00);
77 if (body_size
!= expected_body_size
) {
78 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
81 in_oplock_level
= CVAL(inbody
, 0x03);
82 in_impersonation_level
= IVAL(inbody
, 0x04);
83 in_desired_access
= IVAL(inbody
, 0x18);
84 in_file_attributes
= IVAL(inbody
, 0x1C);
85 in_share_access
= IVAL(inbody
, 0x20);
86 in_create_disposition
= IVAL(inbody
, 0x24);
87 in_create_options
= IVAL(inbody
, 0x28);
88 in_name_offset
= SVAL(inbody
, 0x2C);
89 in_name_length
= SVAL(inbody
, 0x2E);
91 if (in_name_offset
!= (SMB2_HDR_BODY
+ (body_size
& 0xFFFFFFFE))) {
92 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
95 if (in_name_length
> req
->in
.vector
[i
+2].iov_len
) {
96 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
99 in_name_buffer
.data
= (uint8_t *)req
->in
.vector
[i
+2].iov_base
;
100 in_name_buffer
.length
= in_name_length
;
102 ok
= convert_string_talloc(req
, CH_UTF16
, CH_UNIX
,
104 in_name_buffer
.length
,
106 &in_name_string_size
, false);
108 return smbd_smb2_request_error(req
, NT_STATUS_ILLEGAL_CHARACTER
);
111 subreq
= smbd_smb2_create_send(req
,
112 req
->conn
->smb2
.event_ctx
,
115 in_impersonation_level
,
119 in_create_disposition
,
122 if (subreq
== NULL
) {
123 return smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
125 tevent_req_set_callback(subreq
, smbd_smb2_request_create_done
, req
);
129 static void smbd_smb2_request_create_done(struct tevent_req
*subreq
)
131 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
132 struct smbd_smb2_request
);
133 int i
= req
->current_idx
;
137 uint8_t out_oplock_level
;
138 uint32_t out_create_action
;
139 NTTIME out_creation_time
;
140 NTTIME out_last_access_time
;
141 NTTIME out_last_write_time
;
142 NTTIME out_change_time
;
143 uint64_t out_allocation_size
;
144 uint64_t out_end_of_file
;
145 uint32_t out_file_attributes
;
146 uint64_t out_file_id_volatile
;
148 NTSTATUS error
; /* transport error */
150 status
= smbd_smb2_create_recv(subreq
,
154 &out_last_access_time
,
155 &out_last_write_time
,
157 &out_allocation_size
,
159 &out_file_attributes
,
160 &out_file_id_volatile
);
162 if (!NT_STATUS_IS_OK(status
)) {
163 error
= smbd_smb2_request_error(req
, status
);
164 if (!NT_STATUS_IS_OK(error
)) {
165 smbd_server_connection_terminate(req
->conn
,
172 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
174 outbody
= data_blob_talloc(req
->out
.vector
, NULL
, 0x58);
175 if (outbody
.data
== NULL
) {
176 error
= smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
177 if (!NT_STATUS_IS_OK(error
)) {
178 smbd_server_connection_terminate(req
->conn
,
185 SSVAL(outbody
.data
, 0x00, 0x58 + 1); /* struct size */
186 SCVAL(outbody
.data
, 0x02,
187 out_oplock_level
); /* oplock level */
188 SCVAL(outbody
.data
, 0x03, 0); /* reserved */
189 SIVAL(outbody
.data
, 0x04,
190 out_create_action
); /* create action */
191 SBVAL(outbody
.data
, 0x08,
192 out_creation_time
); /* creation time */
193 SBVAL(outbody
.data
, 0x10,
194 out_last_access_time
); /* last access time */
195 SBVAL(outbody
.data
, 0x18,
196 out_last_write_time
); /* last write time */
197 SBVAL(outbody
.data
, 0x20,
198 out_change_time
); /* change time */
199 SBVAL(outbody
.data
, 0x28,
200 out_allocation_size
); /* allocation size */
201 SBVAL(outbody
.data
, 0x30,
202 out_end_of_file
); /* end of file */
203 SIVAL(outbody
.data
, 0x38,
204 out_file_attributes
); /* file attributes */
205 SIVAL(outbody
.data
, 0x3C, 0); /* reserved */
206 SBVAL(outbody
.data
, 0x40, 0); /* file id (persistent) */
207 SBVAL(outbody
.data
, 0x48,
208 out_file_id_volatile
); /* file id (volatile) */
209 SIVAL(outbody
.data
, 0x50, 0); /* create contexts offset */
210 SIVAL(outbody
.data
, 0x54, 0); /* create contexts length */
212 outdyn
= data_blob_const(NULL
, 0);
214 error
= smbd_smb2_request_done(req
, outbody
, &outdyn
);
215 if (!NT_STATUS_IS_OK(error
)) {
216 smbd_server_connection_terminate(req
->conn
,
222 struct smbd_smb2_create_state
{
223 struct smbd_smb2_request
*smb2req
;
224 uint8_t out_oplock_level
;
225 uint32_t out_create_action
;
226 NTTIME out_creation_time
;
227 NTTIME out_last_access_time
;
228 NTTIME out_last_write_time
;
229 NTTIME out_change_time
;
230 uint64_t out_allocation_size
;
231 uint64_t out_end_of_file
;
232 uint32_t out_file_attributes
;
233 uint64_t out_file_id_volatile
;
236 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
237 struct tevent_context
*ev
,
238 struct smbd_smb2_request
*smb2req
,
239 uint8_t in_oplock_level
,
240 uint32_t in_impersonation_level
,
241 uint32_t in_desired_access
,
242 uint32_t in_file_attributes
,
243 uint32_t in_share_access
,
244 uint32_t in_create_disposition
,
245 uint32_t in_create_options
,
248 struct tevent_req
*req
;
249 struct smbd_smb2_create_state
*state
;
251 struct smb_request
*smbreq
;
252 files_struct
*result
;
254 SMB_STRUCT_STAT sbuf
;
255 struct smb_filename
*smb_fname
= NULL
;
257 req
= tevent_req_create(mem_ctx
, &state
,
258 struct smbd_smb2_create_state
);
262 state
->smb2req
= smb2req
;
264 DEBUG(10,("smbd_smb2_create: name[%s]\n",
267 smbreq
= smbd_smb2_fake_smb_request(smb2req
);
268 if (tevent_req_nomem(smbreq
, req
)) {
272 if (IS_IPC(smbreq
->conn
)) {
273 const char *pipe_name
= in_name
;
275 if (!lp_nt_pipe_support()) {
276 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
280 /* Strip \\ off the name. */
281 if (pipe_name
[0] == '\\') {
285 status
= open_np_file(smbreq
, pipe_name
, &result
);
286 if (!NT_STATUS_IS_OK(status
)) {
287 tevent_req_nterror(req
, status
);
290 info
= FILE_WAS_OPENED
;
292 } else if (CAN_PRINT(smbreq
->conn
)) {
293 status
= file_new(smbreq
, smbreq
->conn
, &result
);
294 if(!NT_STATUS_IS_OK(status
)) {
295 tevent_req_nterror(req
, status
);
299 status
= print_fsp_open(smbreq
,
305 if (!NT_STATUS_IS_OK(status
)) {
306 file_free(smbreq
, result
);
307 tevent_req_nterror(req
, status
);
310 info
= FILE_WAS_CREATED
;
314 /* these are ignored for SMB2 */
315 in_create_options
&= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
316 in_create_options
&= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
318 status
= filename_convert(talloc_tos(),
320 smbreq
->flags2
& FLAGS2_DFS_PATHNAMES
,
324 if (!NT_STATUS_IS_OK(status
)) {
325 tevent_req_nterror(req
, status
);
329 status
= SMB_VFS_CREATE_FILE(smbreq
->conn
,
331 0, /* root_dir_fid */
335 in_create_disposition
,
338 0, /* oplock_request */
339 0, /* allocation_size */
340 NULL
, /* security_descriptor */
344 if (!NT_STATUS_IS_OK(status
)) {
345 tevent_req_nterror(req
, status
);
348 sbuf
= smb_fname
->st
;
351 smb2req
->compat_chain_fsp
= smbreq
->chain_fsp
;
353 state
->out_oplock_level
= 0;
354 if ((in_create_disposition
== FILE_SUPERSEDE
)
355 && (info
== FILE_WAS_OVERWRITTEN
)) {
356 state
->out_create_action
= FILE_WAS_SUPERSEDED
;
358 state
->out_create_action
= info
;
360 unix_timespec_to_nt_time(&state
->out_creation_time
, sbuf
.st_ex_btime
);
361 unix_timespec_to_nt_time(&state
->out_last_access_time
, sbuf
.st_ex_atime
);
362 unix_timespec_to_nt_time(&state
->out_last_write_time
,sbuf
.st_ex_mtime
);
363 unix_timespec_to_nt_time(&state
->out_change_time
, sbuf
.st_ex_ctime
);
364 state
->out_allocation_size
= sbuf
.st_ex_blksize
* sbuf
.st_ex_blocks
;
365 state
->out_end_of_file
= sbuf
.st_ex_size
;
366 state
->out_file_attributes
= dos_mode(result
->conn
,
369 if (state
->out_file_attributes
== 0) {
370 state
->out_file_attributes
= FILE_ATTRIBUTE_NORMAL
;
372 state
->out_file_id_volatile
= result
->fnum
;
374 tevent_req_done(req
);
376 TALLOC_FREE(smb_fname
);
377 return tevent_req_post(req
, ev
);
380 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
381 uint8_t *out_oplock_level
,
382 uint32_t *out_create_action
,
383 NTTIME
*out_creation_time
,
384 NTTIME
*out_last_access_time
,
385 NTTIME
*out_last_write_time
,
386 NTTIME
*out_change_time
,
387 uint64_t *out_allocation_size
,
388 uint64_t *out_end_of_file
,
389 uint32_t *out_file_attributes
,
390 uint64_t *out_file_id_volatile
)
393 struct smbd_smb2_create_state
*state
= tevent_req_data(req
,
394 struct smbd_smb2_create_state
);
396 if (tevent_req_is_nterror(req
, &status
)) {
397 tevent_req_received(req
);
401 *out_oplock_level
= state
->out_oplock_level
;
402 *out_create_action
= state
->out_create_action
;
403 *out_creation_time
= state
->out_creation_time
;
404 *out_last_access_time
= state
->out_last_access_time
;
405 *out_last_write_time
= state
->out_last_write_time
;
406 *out_change_time
= state
->out_change_time
;
407 *out_allocation_size
= state
->out_allocation_size
;
408 *out_end_of_file
= state
->out_end_of_file
;
409 *out_file_attributes
= state
->out_file_attributes
;
410 *out_file_id_volatile
= state
->out_file_id_volatile
;
412 tevent_req_received(req
);