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
== 0 && in_name_length
== 0) {
93 } else if (in_name_offset
!= (SMB2_HDR_BODY
+ (body_size
& 0xFFFFFFFE))) {
94 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
97 if (in_name_length
> req
->in
.vector
[i
+2].iov_len
) {
98 return smbd_smb2_request_error(req
, NT_STATUS_INVALID_PARAMETER
);
101 in_name_buffer
.data
= (uint8_t *)req
->in
.vector
[i
+2].iov_base
;
102 in_name_buffer
.length
= in_name_length
;
104 ok
= convert_string_talloc(req
, CH_UTF16
, CH_UNIX
,
106 in_name_buffer
.length
,
108 &in_name_string_size
, false);
110 return smbd_smb2_request_error(req
, NT_STATUS_ILLEGAL_CHARACTER
);
113 subreq
= smbd_smb2_create_send(req
,
114 req
->sconn
->smb2
.event_ctx
,
117 in_impersonation_level
,
121 in_create_disposition
,
124 if (subreq
== NULL
) {
125 return smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
127 tevent_req_set_callback(subreq
, smbd_smb2_request_create_done
, req
);
129 if (tevent_req_is_in_progress(subreq
)) {
130 return smbd_smb2_request_pending_queue(req
);
136 static void smbd_smb2_request_create_done(struct tevent_req
*subreq
)
138 struct smbd_smb2_request
*req
= tevent_req_callback_data(subreq
,
139 struct smbd_smb2_request
);
140 int i
= req
->current_idx
;
144 uint8_t out_oplock_level
= 0;
145 uint32_t out_create_action
= 0;
146 NTTIME out_creation_time
= 0;
147 NTTIME out_last_access_time
= 0;
148 NTTIME out_last_write_time
= 0;
149 NTTIME out_change_time
= 0;
150 uint64_t out_allocation_size
= 0;
151 uint64_t out_end_of_file
= 0;
152 uint32_t out_file_attributes
= 0;
153 uint64_t out_file_id_volatile
= 0;
155 NTSTATUS error
; /* transport error */
157 status
= smbd_smb2_create_recv(subreq
,
161 &out_last_access_time
,
162 &out_last_write_time
,
164 &out_allocation_size
,
166 &out_file_attributes
,
167 &out_file_id_volatile
);
169 if (!NT_STATUS_IS_OK(status
)) {
170 error
= smbd_smb2_request_error(req
, status
);
171 if (!NT_STATUS_IS_OK(error
)) {
172 smbd_server_connection_terminate(req
->sconn
,
179 outhdr
= (uint8_t *)req
->out
.vector
[i
].iov_base
;
181 outbody
= data_blob_talloc(req
->out
.vector
, NULL
, 0x58);
182 if (outbody
.data
== NULL
) {
183 error
= smbd_smb2_request_error(req
, NT_STATUS_NO_MEMORY
);
184 if (!NT_STATUS_IS_OK(error
)) {
185 smbd_server_connection_terminate(req
->sconn
,
192 SSVAL(outbody
.data
, 0x00, 0x58 + 1); /* struct size */
193 SCVAL(outbody
.data
, 0x02,
194 out_oplock_level
); /* oplock level */
195 SCVAL(outbody
.data
, 0x03, 0); /* reserved */
196 SIVAL(outbody
.data
, 0x04,
197 out_create_action
); /* create action */
198 SBVAL(outbody
.data
, 0x08,
199 out_creation_time
); /* creation time */
200 SBVAL(outbody
.data
, 0x10,
201 out_last_access_time
); /* last access time */
202 SBVAL(outbody
.data
, 0x18,
203 out_last_write_time
); /* last write time */
204 SBVAL(outbody
.data
, 0x20,
205 out_change_time
); /* change time */
206 SBVAL(outbody
.data
, 0x28,
207 out_allocation_size
); /* allocation size */
208 SBVAL(outbody
.data
, 0x30,
209 out_end_of_file
); /* end of file */
210 SIVAL(outbody
.data
, 0x38,
211 out_file_attributes
); /* file attributes */
212 SIVAL(outbody
.data
, 0x3C, 0); /* reserved */
213 SBVAL(outbody
.data
, 0x40, 0); /* file id (persistent) */
214 SBVAL(outbody
.data
, 0x48,
215 out_file_id_volatile
); /* file id (volatile) */
216 SIVAL(outbody
.data
, 0x50, 0); /* create contexts offset */
217 SIVAL(outbody
.data
, 0x54, 0); /* create contexts length */
219 outdyn
= data_blob_const(NULL
, 0);
221 error
= smbd_smb2_request_done(req
, outbody
, &outdyn
);
222 if (!NT_STATUS_IS_OK(error
)) {
223 smbd_server_connection_terminate(req
->sconn
,
229 struct smbd_smb2_create_state
{
230 struct smbd_smb2_request
*smb2req
;
231 uint8_t out_oplock_level
;
232 uint32_t out_create_action
;
233 NTTIME out_creation_time
;
234 NTTIME out_last_access_time
;
235 NTTIME out_last_write_time
;
236 NTTIME out_change_time
;
237 uint64_t out_allocation_size
;
238 uint64_t out_end_of_file
;
239 uint32_t out_file_attributes
;
240 uint64_t out_file_id_volatile
;
243 static struct tevent_req
*smbd_smb2_create_send(TALLOC_CTX
*mem_ctx
,
244 struct tevent_context
*ev
,
245 struct smbd_smb2_request
*smb2req
,
246 uint8_t in_oplock_level
,
247 uint32_t in_impersonation_level
,
248 uint32_t in_desired_access
,
249 uint32_t in_file_attributes
,
250 uint32_t in_share_access
,
251 uint32_t in_create_disposition
,
252 uint32_t in_create_options
,
255 struct tevent_req
*req
;
256 struct smbd_smb2_create_state
*state
;
258 struct smb_request
*smbreq
;
259 files_struct
*result
;
261 SMB_STRUCT_STAT sbuf
;
263 req
= tevent_req_create(mem_ctx
, &state
,
264 struct smbd_smb2_create_state
);
268 state
->smb2req
= smb2req
;
270 DEBUG(10,("smbd_smb2_create: name[%s]\n",
273 smbreq
= smbd_smb2_fake_smb_request(smb2req
);
274 if (tevent_req_nomem(smbreq
, req
)) {
278 if (IS_IPC(smbreq
->conn
)) {
279 const char *pipe_name
= in_name
;
281 if (!lp_nt_pipe_support()) {
282 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
286 /* Strip \\ off the name. */
287 if (pipe_name
[0] == '\\') {
291 status
= open_np_file(smbreq
, pipe_name
, &result
);
292 if (!NT_STATUS_IS_OK(status
)) {
293 tevent_req_nterror(req
, status
);
296 info
= FILE_WAS_OPENED
;
298 } else if (CAN_PRINT(smbreq
->conn
)) {
299 status
= file_new(smbreq
, smbreq
->conn
, &result
);
300 if(!NT_STATUS_IS_OK(status
)) {
301 tevent_req_nterror(req
, status
);
305 status
= print_fsp_open(smbreq
,
311 if (!NT_STATUS_IS_OK(status
)) {
312 file_free(smbreq
, result
);
313 tevent_req_nterror(req
, status
);
316 info
= FILE_WAS_CREATED
;
318 struct smb_filename
*smb_fname
= NULL
;
320 /* these are ignored for SMB2 */
321 in_create_options
&= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
322 in_create_options
&= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
324 status
= filename_convert(talloc_tos(),
326 smbreq
->flags2
& FLAGS2_DFS_PATHNAMES
,
331 if (!NT_STATUS_IS_OK(status
)) {
332 tevent_req_nterror(req
, status
);
333 TALLOC_FREE(smb_fname
);
337 status
= SMB_VFS_CREATE_FILE(smbreq
->conn
,
339 0, /* root_dir_fid */
343 in_create_disposition
,
346 0, /* oplock_request */
347 0, /* allocation_size */
348 NULL
, /* security_descriptor */
352 if (!NT_STATUS_IS_OK(status
)) {
353 tevent_req_nterror(req
, status
);
354 TALLOC_FREE(smb_fname
);
357 sbuf
= smb_fname
->st
;
358 TALLOC_FREE(smb_fname
);
361 smb2req
->compat_chain_fsp
= smbreq
->chain_fsp
;
363 state
->out_oplock_level
= 0;
364 if ((in_create_disposition
== FILE_SUPERSEDE
)
365 && (info
== FILE_WAS_OVERWRITTEN
)) {
366 state
->out_create_action
= FILE_WAS_SUPERSEDED
;
368 state
->out_create_action
= info
;
370 unix_timespec_to_nt_time(&state
->out_creation_time
, sbuf
.st_ex_btime
);
371 unix_timespec_to_nt_time(&state
->out_last_access_time
, sbuf
.st_ex_atime
);
372 unix_timespec_to_nt_time(&state
->out_last_write_time
,sbuf
.st_ex_mtime
);
373 unix_timespec_to_nt_time(&state
->out_change_time
, sbuf
.st_ex_ctime
);
374 state
->out_allocation_size
= sbuf
.st_ex_blksize
* sbuf
.st_ex_blocks
;
375 state
->out_end_of_file
= sbuf
.st_ex_size
;
376 state
->out_file_attributes
= dos_mode(result
->conn
,
378 if (state
->out_file_attributes
== 0) {
379 state
->out_file_attributes
= FILE_ATTRIBUTE_NORMAL
;
381 state
->out_file_id_volatile
= result
->fnum
;
383 tevent_req_done(req
);
385 return tevent_req_post(req
, ev
);
388 static NTSTATUS
smbd_smb2_create_recv(struct tevent_req
*req
,
389 uint8_t *out_oplock_level
,
390 uint32_t *out_create_action
,
391 NTTIME
*out_creation_time
,
392 NTTIME
*out_last_access_time
,
393 NTTIME
*out_last_write_time
,
394 NTTIME
*out_change_time
,
395 uint64_t *out_allocation_size
,
396 uint64_t *out_end_of_file
,
397 uint32_t *out_file_attributes
,
398 uint64_t *out_file_id_volatile
)
401 struct smbd_smb2_create_state
*state
= tevent_req_data(req
,
402 struct smbd_smb2_create_state
);
404 if (tevent_req_is_nterror(req
, &status
)) {
405 tevent_req_received(req
);
409 *out_oplock_level
= state
->out_oplock_level
;
410 *out_create_action
= state
->out_create_action
;
411 *out_creation_time
= state
->out_creation_time
;
412 *out_last_access_time
= state
->out_last_access_time
;
413 *out_last_write_time
= state
->out_last_write_time
;
414 *out_change_time
= state
->out_change_time
;
415 *out_allocation_size
= state
->out_allocation_size
;
416 *out_end_of_file
= state
->out_end_of_file
;
417 *out_file_attributes
= state
->out_file_attributes
;
418 *out_file_id_volatile
= state
->out_file_id_volatile
;
420 tevent_req_received(req
);