s3:configure: use correct SONAMEFLAG on Solaris depending on which linker is being...
[Samba.git] / source3 / smbd / smb2_create.c
blobf0afb1f4d1e98fe99090afaf67a1d6581022b32c
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
26 int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
28 switch(in_oplock_level) {
29 case SMB2_OPLOCK_LEVEL_NONE:
30 return NO_OPLOCK;
31 case SMB2_OPLOCK_LEVEL_II:
32 return LEVEL_II_OPLOCK;
33 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
34 return EXCLUSIVE_OPLOCK;
35 case SMB2_OPLOCK_LEVEL_BATCH:
36 return BATCH_OPLOCK;
37 case SMB2_OPLOCK_LEVEL_LEASE:
38 DEBUG(2,("map_smb2_oplock_levels_to_samba: "
39 "LEASE_OPLOCK_REQUESTED\n"));
40 return NO_OPLOCK;
41 default:
42 DEBUG(2,("map_smb2_oplock_levels_to_samba: "
43 "unknown level %u\n",
44 (unsigned int)in_oplock_level));
45 return NO_OPLOCK;
49 uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
51 if (BATCH_OPLOCK_TYPE(oplock_type)) {
52 return SMB2_OPLOCK_LEVEL_BATCH;
53 } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
54 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
55 } else if (LEVEL_II_OPLOCK_TYPE(oplock_type)) {
56 return SMB2_OPLOCK_LEVEL_II;
57 } else {
58 return SMB2_OPLOCK_LEVEL_NONE;
62 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
63 struct tevent_context *ev,
64 struct smbd_smb2_request *smb2req,
65 uint8_t in_oplock_level,
66 uint32_t in_impersonation_level,
67 uint32_t in_desired_access,
68 uint32_t in_file_attributes,
69 uint32_t in_share_access,
70 uint32_t in_create_disposition,
71 uint32_t in_create_options,
72 const char *in_name,
73 struct smb2_create_blobs in_context_blobs);
74 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
75 TALLOC_CTX *mem_ctx,
76 uint8_t *out_oplock_level,
77 uint32_t *out_create_action,
78 NTTIME *out_creation_time,
79 NTTIME *out_last_access_time,
80 NTTIME *out_last_write_time,
81 NTTIME *out_change_time,
82 uint64_t *out_allocation_size,
83 uint64_t *out_end_of_file,
84 uint32_t *out_file_attributes,
85 uint64_t *out_file_id_volatile,
86 struct smb2_create_blobs *out_context_blobs);
88 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq);
89 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
91 const uint8_t *inbody;
92 int i = smb2req->current_idx;
93 size_t expected_body_size = 0x39;
94 size_t body_size;
95 uint8_t in_oplock_level;
96 uint32_t in_impersonation_level;
97 uint32_t in_desired_access;
98 uint32_t in_file_attributes;
99 uint32_t in_share_access;
100 uint32_t in_create_disposition;
101 uint32_t in_create_options;
102 uint16_t in_name_offset;
103 uint16_t in_name_length;
104 DATA_BLOB in_name_buffer;
105 char *in_name_string;
106 size_t in_name_string_size;
107 uint32_t name_offset = 0;
108 uint32_t name_available_length = 0;
109 uint32_t in_context_offset;
110 uint32_t in_context_length;
111 DATA_BLOB in_context_buffer;
112 struct smb2_create_blobs in_context_blobs;
113 uint32_t context_offset = 0;
114 uint32_t context_available_length = 0;
115 uint32_t dyn_offset;
116 NTSTATUS status;
117 bool ok;
118 struct tevent_req *tsubreq;
120 if (smb2req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
121 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
124 inbody = (const uint8_t *)smb2req->in.vector[i+1].iov_base;
126 body_size = SVAL(inbody, 0x00);
127 if (body_size != expected_body_size) {
128 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
131 in_oplock_level = CVAL(inbody, 0x03);
132 in_impersonation_level = IVAL(inbody, 0x04);
133 in_desired_access = IVAL(inbody, 0x18);
134 in_file_attributes = IVAL(inbody, 0x1C);
135 in_share_access = IVAL(inbody, 0x20);
136 in_create_disposition = IVAL(inbody, 0x24);
137 in_create_options = IVAL(inbody, 0x28);
138 in_name_offset = SVAL(inbody, 0x2C);
139 in_name_length = SVAL(inbody, 0x2E);
140 in_context_offset = IVAL(inbody, 0x30);
141 in_context_length = IVAL(inbody, 0x34);
144 * First check if the dynamic name and context buffers
145 * are correctly specified.
147 * Note: That we don't check if the name and context buffers
148 * overlap
151 dyn_offset = SMB2_HDR_BODY + (body_size & 0xFFFFFFFE);
153 if (in_name_offset == 0 && in_name_length == 0) {
154 /* This is ok */
155 name_offset = 0;
156 } else if (in_name_offset < dyn_offset) {
157 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
158 } else {
159 name_offset = in_name_offset - dyn_offset;
162 if (name_offset > smb2req->in.vector[i+2].iov_len) {
163 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
166 name_available_length = smb2req->in.vector[i+2].iov_len - name_offset;
168 if (in_name_length > name_available_length) {
169 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
172 in_name_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base +
173 name_offset;
174 in_name_buffer.length = in_name_length;
176 if (in_context_offset == 0 && in_context_length == 0) {
177 /* This is ok */
178 context_offset = 0;
179 } else if (in_context_offset < dyn_offset) {
180 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
181 } else {
182 context_offset = in_context_offset - dyn_offset;
185 if (context_offset > smb2req->in.vector[i+2].iov_len) {
186 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
189 context_available_length = smb2req->in.vector[i+2].iov_len - context_offset;
191 if (in_context_length > context_available_length) {
192 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
195 in_context_buffer.data = (uint8_t *)smb2req->in.vector[i+2].iov_base +
196 context_offset;
197 in_context_buffer.length = in_context_length;
200 * Now interpret the name and context buffers
203 ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX,
204 in_name_buffer.data,
205 in_name_buffer.length,
206 &in_name_string,
207 &in_name_string_size, false);
208 if (!ok) {
209 return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
212 ZERO_STRUCT(in_context_blobs);
213 status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
214 if (!NT_STATUS_IS_OK(status)) {
215 return smbd_smb2_request_error(smb2req, status);
218 tsubreq = smbd_smb2_create_send(smb2req,
219 smb2req->sconn->smb2.event_ctx,
220 smb2req,
221 in_oplock_level,
222 in_impersonation_level,
223 in_desired_access,
224 in_file_attributes,
225 in_share_access,
226 in_create_disposition,
227 in_create_options,
228 in_name_string,
229 in_context_blobs);
230 if (tsubreq == NULL) {
231 smb2req->subreq = NULL;
232 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
234 tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);
236 return smbd_smb2_request_pending_queue(smb2req, tsubreq);
239 static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req)
241 uint8_t *reqhdr = (uint8_t *)smb2req->out.vector[smb2req->current_idx].iov_base;
242 return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
245 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
247 struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq,
248 struct smbd_smb2_request);
249 int i = smb2req->current_idx;
250 uint8_t *outhdr;
251 DATA_BLOB outbody;
252 DATA_BLOB outdyn;
253 uint8_t out_oplock_level = 0;
254 uint32_t out_create_action = 0;
255 NTTIME out_creation_time = 0;
256 NTTIME out_last_access_time = 0;
257 NTTIME out_last_write_time = 0;
258 NTTIME out_change_time = 0;
259 uint64_t out_allocation_size = 0;
260 uint64_t out_end_of_file = 0;
261 uint32_t out_file_attributes = 0;
262 uint64_t out_file_id_volatile = 0;
263 struct smb2_create_blobs out_context_blobs;
264 DATA_BLOB out_context_buffer;
265 uint16_t out_context_buffer_offset = 0;
266 NTSTATUS status;
267 NTSTATUS error; /* transport error */
269 if (smb2req->cancelled) {
270 uint64_t mid = get_mid_from_smb2req(smb2req);
271 DEBUG(10,("smbd_smb2_request_create_done: cancelled mid %llu\n",
272 (unsigned long long)mid ));
273 error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED);
274 if (!NT_STATUS_IS_OK(error)) {
275 smbd_server_connection_terminate(smb2req->sconn,
276 nt_errstr(error));
277 return;
279 return;
282 status = smbd_smb2_create_recv(tsubreq,
283 smb2req,
284 &out_oplock_level,
285 &out_create_action,
286 &out_creation_time,
287 &out_last_access_time,
288 &out_last_write_time,
289 &out_change_time,
290 &out_allocation_size,
291 &out_end_of_file,
292 &out_file_attributes,
293 &out_file_id_volatile,
294 &out_context_blobs);
295 if (!NT_STATUS_IS_OK(status)) {
296 error = smbd_smb2_request_error(smb2req, status);
297 if (!NT_STATUS_IS_OK(error)) {
298 smbd_server_connection_terminate(smb2req->sconn,
299 nt_errstr(error));
300 return;
302 return;
305 status = smb2_create_blob_push(smb2req, &out_context_buffer, out_context_blobs);
306 if (!NT_STATUS_IS_OK(status)) {
307 error = smbd_smb2_request_error(smb2req, status);
308 if (!NT_STATUS_IS_OK(error)) {
309 smbd_server_connection_terminate(smb2req->sconn,
310 nt_errstr(error));
311 return;
313 return;
316 if (out_context_buffer.length > 0) {
317 out_context_buffer_offset = SMB2_HDR_BODY + 0x58;
320 outhdr = (uint8_t *)smb2req->out.vector[i].iov_base;
322 outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x58);
323 if (outbody.data == NULL) {
324 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
325 if (!NT_STATUS_IS_OK(error)) {
326 smbd_server_connection_terminate(smb2req->sconn,
327 nt_errstr(error));
328 return;
330 return;
333 SSVAL(outbody.data, 0x00, 0x58 + 1); /* struct size */
334 SCVAL(outbody.data, 0x02,
335 out_oplock_level); /* oplock level */
336 SCVAL(outbody.data, 0x03, 0); /* reserved */
337 SIVAL(outbody.data, 0x04,
338 out_create_action); /* create action */
339 SBVAL(outbody.data, 0x08,
340 out_creation_time); /* creation time */
341 SBVAL(outbody.data, 0x10,
342 out_last_access_time); /* last access time */
343 SBVAL(outbody.data, 0x18,
344 out_last_write_time); /* last write time */
345 SBVAL(outbody.data, 0x20,
346 out_change_time); /* change time */
347 SBVAL(outbody.data, 0x28,
348 out_allocation_size); /* allocation size */
349 SBVAL(outbody.data, 0x30,
350 out_end_of_file); /* end of file */
351 SIVAL(outbody.data, 0x38,
352 out_file_attributes); /* file attributes */
353 SIVAL(outbody.data, 0x3C, 0); /* reserved */
354 SBVAL(outbody.data, 0x40, 0); /* file id (persistent) */
355 SBVAL(outbody.data, 0x48,
356 out_file_id_volatile); /* file id (volatile) */
357 SIVAL(outbody.data, 0x50,
358 out_context_buffer_offset); /* create contexts offset */
359 SIVAL(outbody.data, 0x54,
360 out_context_buffer.length); /* create contexts length */
362 outdyn = out_context_buffer;
364 error = smbd_smb2_request_done(smb2req, outbody, &outdyn);
365 if (!NT_STATUS_IS_OK(error)) {
366 smbd_server_connection_terminate(smb2req->sconn,
367 nt_errstr(error));
368 return;
372 struct smbd_smb2_create_state {
373 struct smbd_smb2_request *smb2req;
374 struct smb_request *smb1req;
375 struct timed_event *te;
376 struct timeval request_time;
377 struct file_id id;
378 DATA_BLOB private_data;
379 uint8_t out_oplock_level;
380 uint32_t out_create_action;
381 NTTIME out_creation_time;
382 NTTIME out_last_access_time;
383 NTTIME out_last_write_time;
384 NTTIME out_change_time;
385 uint64_t out_allocation_size;
386 uint64_t out_end_of_file;
387 uint32_t out_file_attributes;
388 uint64_t out_file_id_volatile;
389 struct smb2_create_blobs out_context_blobs;
392 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
393 struct tevent_context *ev,
394 struct smbd_smb2_request *smb2req,
395 uint8_t in_oplock_level,
396 uint32_t in_impersonation_level,
397 uint32_t in_desired_access,
398 uint32_t in_file_attributes,
399 uint32_t in_share_access,
400 uint32_t in_create_disposition,
401 uint32_t in_create_options,
402 const char *in_name,
403 struct smb2_create_blobs in_context_blobs)
405 struct tevent_req *req = NULL;
406 struct smbd_smb2_create_state *state = NULL;
407 NTSTATUS status;
408 struct smb_request *smb1req = NULL;
409 files_struct *result = NULL;
410 int info;
411 struct timespec write_time_ts;
412 struct smb2_create_blobs out_context_blobs;
414 ZERO_STRUCT(out_context_blobs);
416 if (!smb2req->async) {
417 /* New create call. */
418 req = tevent_req_create(mem_ctx, &state,
419 struct smbd_smb2_create_state);
420 if (req == NULL) {
421 return NULL;
423 state->smb2req = smb2req;
424 smb2req->subreq = req; /* So we can find this when going async. */
426 smb1req = smbd_smb2_fake_smb_request(smb2req);
427 if (tevent_req_nomem(smb1req, req)) {
428 return tevent_req_post(req, ev);
430 state->smb1req = smb1req;
431 DEBUG(10,("smbd_smb2_create: name[%s]\n",
432 in_name));
433 } else {
434 /* Re-entrant create call. */
435 req = smb2req->subreq;
436 state = tevent_req_data(req,
437 struct smbd_smb2_create_state);
438 smb1req = state->smb1req;
439 DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
440 in_name ));
443 if (IS_IPC(smb1req->conn)) {
444 const char *pipe_name = in_name;
446 if (!lp_nt_pipe_support()) {
447 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
448 return tevent_req_post(req, ev);
451 /* Strip \\ off the name. */
452 if (pipe_name[0] == '\\') {
453 pipe_name++;
456 status = open_np_file(smb1req, pipe_name, &result);
457 if (!NT_STATUS_IS_OK(status)) {
458 tevent_req_nterror(req, status);
459 return tevent_req_post(req, ev);
461 info = FILE_WAS_OPENED;
462 } else if (CAN_PRINT(smb1req->conn)) {
463 status = file_new(smb1req, smb1req->conn, &result);
464 if(!NT_STATUS_IS_OK(status)) {
465 tevent_req_nterror(req, status);
466 return tevent_req_post(req, ev);
469 status = print_fsp_open(smb1req,
470 smb1req->conn,
471 in_name,
472 smb1req->vuid,
473 result);
474 if (!NT_STATUS_IS_OK(status)) {
475 file_free(smb1req, result);
476 tevent_req_nterror(req, status);
477 return tevent_req_post(req, ev);
479 info = FILE_WAS_CREATED;
480 } else {
481 char *fname;
482 struct smb_filename *smb_fname = NULL;
483 struct smb2_create_blob *exta = NULL;
484 struct ea_list *ea_list = NULL;
485 struct smb2_create_blob *mxac = NULL;
486 NTTIME max_access_time = 0;
487 struct smb2_create_blob *secd = NULL;
488 struct security_descriptor *sec_desc = NULL;
489 struct smb2_create_blob *dhnq = NULL;
490 struct smb2_create_blob *dhnc = NULL;
491 struct smb2_create_blob *alsi = NULL;
492 uint64_t allocation_size = 0;
493 struct smb2_create_blob *twrp = NULL;
494 struct smb2_create_blob *qfid = NULL;
496 exta = smb2_create_blob_find(&in_context_blobs,
497 SMB2_CREATE_TAG_EXTA);
498 mxac = smb2_create_blob_find(&in_context_blobs,
499 SMB2_CREATE_TAG_MXAC);
500 secd = smb2_create_blob_find(&in_context_blobs,
501 SMB2_CREATE_TAG_SECD);
502 dhnq = smb2_create_blob_find(&in_context_blobs,
503 SMB2_CREATE_TAG_DHNQ);
504 dhnc = smb2_create_blob_find(&in_context_blobs,
505 SMB2_CREATE_TAG_DHNC);
506 alsi = smb2_create_blob_find(&in_context_blobs,
507 SMB2_CREATE_TAG_ALSI);
508 twrp = smb2_create_blob_find(&in_context_blobs,
509 SMB2_CREATE_TAG_TWRP);
510 qfid = smb2_create_blob_find(&in_context_blobs,
511 SMB2_CREATE_TAG_QFID);
513 fname = talloc_strdup(state, in_name);
514 if (tevent_req_nomem(fname, req)) {
515 return tevent_req_post(req, ev);
518 if (exta) {
519 if (dhnc) {
520 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
521 return tevent_req_post(req, ev);
524 ea_list = read_nttrans_ea_list(mem_ctx,
525 (const char *)exta->data.data, exta->data.length);
526 if (!ea_list) {
527 DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
528 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
529 return tevent_req_post(req, ev);
533 if (mxac) {
534 if (dhnc) {
535 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
536 return tevent_req_post(req, ev);
539 if (mxac->data.length == 0) {
540 max_access_time = 0;
541 } else if (mxac->data.length == 8) {
542 max_access_time = BVAL(mxac->data.data, 0);
543 } else {
544 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
545 return tevent_req_post(req, ev);
549 if (secd) {
550 enum ndr_err_code ndr_err;
552 if (dhnc) {
553 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
554 return tevent_req_post(req, ev);
557 sec_desc = talloc_zero(state, struct security_descriptor);
558 if (tevent_req_nomem(sec_desc, req)) {
559 return tevent_req_post(req, ev);
562 ndr_err = ndr_pull_struct_blob(&secd->data,
563 sec_desc, NULL, sec_desc,
564 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
565 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
566 DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
567 ndr_errstr(ndr_err)));
568 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
569 return tevent_req_post(req, ev);
573 if (dhnq) {
574 if (dhnc) {
575 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
576 return tevent_req_post(req, ev);
579 if (dhnq->data.length != 16) {
580 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
581 return tevent_req_post(req, ev);
584 * we don't support durable handles yet
585 * and have to ignore this
589 if (dhnc) {
590 if (dhnc->data.length != 16) {
591 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
592 return tevent_req_post(req, ev);
594 /* we don't support durable handles yet */
595 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
596 return tevent_req_post(req, ev);
599 if (alsi) {
600 if (dhnc) {
601 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
602 return tevent_req_post(req, ev);
605 if (alsi->data.length != 8) {
606 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
607 return tevent_req_post(req, ev);
609 allocation_size = BVAL(alsi->data.data, 0);
612 if (twrp) {
613 NTTIME nttime;
614 time_t t;
615 struct tm *tm;
617 if (dhnc) {
618 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
619 return tevent_req_post(req, ev);
622 if (twrp->data.length != 8) {
623 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
624 return tevent_req_post(req, ev);
627 nttime = BVAL(twrp->data.data, 0);
628 t = nt_time_to_unix(nttime);
629 tm = gmtime(&t);
631 TALLOC_FREE(fname);
632 fname = talloc_asprintf(state,
633 "@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s",
634 tm->tm_year + 1900,
635 tm->tm_mon + 1,
636 tm->tm_mday,
637 tm->tm_hour,
638 tm->tm_min,
639 tm->tm_sec,
640 in_name);
641 if (tevent_req_nomem(fname, req)) {
642 return tevent_req_post(req, ev);
646 if (qfid) {
647 if (qfid->data.length != 0) {
648 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
649 return tevent_req_post(req, ev);
653 /* these are ignored for SMB2 */
654 in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
655 in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
657 /* convert '\\' into '/' */
658 status = check_path_syntax(fname);
659 if (!NT_STATUS_IS_OK(status)) {
660 tevent_req_nterror(req, status);
661 return tevent_req_post(req, ev);
664 status = filename_convert(req,
665 smb1req->conn,
666 smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
667 fname,
669 NULL,
670 &smb_fname);
671 if (!NT_STATUS_IS_OK(status)) {
672 tevent_req_nterror(req, status);
673 return tevent_req_post(req, ev);
676 in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
678 status = SMB_VFS_CREATE_FILE(smb1req->conn,
679 smb1req,
680 0, /* root_dir_fid */
681 smb_fname,
682 in_desired_access,
683 in_share_access,
684 in_create_disposition,
685 in_create_options,
686 in_file_attributes,
687 map_smb2_oplock_levels_to_samba(in_oplock_level),
688 allocation_size,
689 0, /* private_flags */
690 sec_desc,
691 ea_list,
692 &result,
693 &info);
694 if (!NT_STATUS_IS_OK(status)) {
695 if (open_was_deferred(smb1req->mid)) {
696 return req;
698 tevent_req_nterror(req, status);
699 return tevent_req_post(req, ev);
702 if (mxac) {
703 NTTIME last_write_time;
705 unix_timespec_to_nt_time(&last_write_time,
706 result->fsp_name->st.st_ex_mtime);
707 if (last_write_time != max_access_time) {
708 uint8_t p[8];
709 uint32_t max_access_granted;
710 DATA_BLOB blob = data_blob_const(p, sizeof(p));
712 status = smbd_check_open_rights(smb1req->conn,
713 result->fsp_name,
714 SEC_FLAG_MAXIMUM_ALLOWED,
715 &max_access_granted);
717 SIVAL(p, 0, NT_STATUS_V(status));
718 SIVAL(p, 4, max_access_granted);
720 status = smb2_create_blob_add(state,
721 &out_context_blobs,
722 SMB2_CREATE_TAG_MXAC,
723 blob);
724 if (!NT_STATUS_IS_OK(status)) {
725 tevent_req_nterror(req, status);
726 return tevent_req_post(req, ev);
731 if (qfid) {
732 uint8_t p[32];
733 DATA_BLOB blob = data_blob_const(p, sizeof(p));
735 ZERO_STRUCT(p);
737 /* TODO: maybe use result->file_id */
738 SIVAL(p, 0, result->fsp_name->st.st_ex_ino);/* FileIndexLow */
739 SIVAL(p, 4, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
741 status = smb2_create_blob_add(state, &out_context_blobs,
742 SMB2_CREATE_TAG_QFID,
743 blob);
744 if (!NT_STATUS_IS_OK(status)) {
745 tevent_req_nterror(req, status);
746 return tevent_req_post(req, ev);
751 smb2req->compat_chain_fsp = smb1req->chain_fsp;
753 state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type);
755 if ((in_create_disposition == FILE_SUPERSEDE)
756 && (info == FILE_WAS_OVERWRITTEN)) {
757 state->out_create_action = FILE_WAS_SUPERSEDED;
758 } else {
759 state->out_create_action = info;
761 state->out_file_attributes = dos_mode(result->conn,
762 result->fsp_name);
763 /* Deal with other possible opens having a modified
764 write time. JRA. */
765 ZERO_STRUCT(write_time_ts);
766 get_file_infos(result->file_id, NULL, &write_time_ts);
767 if (!null_timespec(write_time_ts)) {
768 update_stat_ex_mtime(&result->fsp_name->st, write_time_ts);
771 unix_timespec_to_nt_time(&state->out_creation_time,
772 get_create_timespec(smb1req->conn, result,
773 result->fsp_name));
774 unix_timespec_to_nt_time(&state->out_last_access_time,
775 result->fsp_name->st.st_ex_atime);
776 unix_timespec_to_nt_time(&state->out_last_write_time,
777 result->fsp_name->st.st_ex_mtime);
778 unix_timespec_to_nt_time(&state->out_change_time,
779 get_change_timespec(smb1req->conn, result,
780 result->fsp_name));
781 state->out_allocation_size =
782 result->fsp_name->st.st_ex_blksize *
783 result->fsp_name->st.st_ex_blocks;
784 state->out_end_of_file = result->fsp_name->st.st_ex_size;
785 if (state->out_file_attributes == 0) {
786 state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
788 state->out_file_id_volatile = result->fnum;
789 state->out_context_blobs = out_context_blobs;
791 tevent_req_done(req);
792 return tevent_req_post(req, ev);
795 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
796 TALLOC_CTX *mem_ctx,
797 uint8_t *out_oplock_level,
798 uint32_t *out_create_action,
799 NTTIME *out_creation_time,
800 NTTIME *out_last_access_time,
801 NTTIME *out_last_write_time,
802 NTTIME *out_change_time,
803 uint64_t *out_allocation_size,
804 uint64_t *out_end_of_file,
805 uint32_t *out_file_attributes,
806 uint64_t *out_file_id_volatile,
807 struct smb2_create_blobs *out_context_blobs)
809 NTSTATUS status;
810 struct smbd_smb2_create_state *state = tevent_req_data(req,
811 struct smbd_smb2_create_state);
813 if (tevent_req_is_nterror(req, &status)) {
814 tevent_req_received(req);
815 return status;
818 *out_oplock_level = state->out_oplock_level;
819 *out_create_action = state->out_create_action;
820 *out_creation_time = state->out_creation_time;
821 *out_last_access_time = state->out_last_access_time;
822 *out_last_write_time = state->out_last_write_time;
823 *out_change_time = state->out_change_time;
824 *out_allocation_size = state->out_allocation_size;
825 *out_end_of_file = state->out_end_of_file;
826 *out_file_attributes = state->out_file_attributes;
827 *out_file_id_volatile = state->out_file_id_volatile;
828 *out_context_blobs = state->out_context_blobs;
830 talloc_steal(mem_ctx, state->out_context_blobs.blobs);
832 tevent_req_received(req);
833 return NT_STATUS_OK;
836 /*********************************************************
837 Code for dealing with deferred opens.
838 *********************************************************/
840 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
841 struct timeval *p_request_time,
842 void **pp_state)
844 struct smbd_smb2_create_state *state = NULL;
845 struct tevent_req *req = NULL;
847 if (!smb2req) {
848 return false;
850 if (!smb2req->async) {
851 return false;
853 req = smb2req->subreq;
854 if (!req) {
855 return false;
857 state = tevent_req_data(req, struct smbd_smb2_create_state);
858 if (!state) {
859 return false;
861 if (p_request_time) {
862 *p_request_time = state->request_time;
864 if (pp_state) {
865 *pp_state = (void *)state->private_data.data;
867 return true;
870 /*********************************************************
871 Re-process this call early - requested by message or
872 close.
873 *********************************************************/
875 static struct smbd_smb2_request *find_open_smb2req(uint64_t mid)
877 struct smbd_server_connection *sconn = smbd_server_conn;
878 struct smbd_smb2_request *smb2req;
880 for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) {
881 uint64_t message_id;
882 if (smb2req->subreq == NULL) {
883 /* This message has been processed. */
884 continue;
886 if (!tevent_req_is_in_progress(smb2req->subreq)) {
887 /* This message has been processed. */
888 continue;
890 message_id = get_mid_from_smb2req(smb2req);
891 if (message_id == mid) {
892 return smb2req;
895 return NULL;
898 bool open_was_deferred_smb2(uint64_t mid)
900 struct smbd_smb2_create_state *state = NULL;
901 struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
903 if (!smb2req) {
904 DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
905 (unsigned long long)mid));
906 return false;
908 if (!smb2req->subreq) {
909 return false;
911 if (!tevent_req_is_in_progress(smb2req->subreq)) {
912 return false;
914 state = tevent_req_data(smb2req->subreq,
915 struct smbd_smb2_create_state);
916 if (!state) {
917 return false;
919 /* It's not in progress if there's no timeout event. */
920 if (!state->te) {
921 return false;
924 DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
925 (unsigned long long)mid));
927 return true;
930 static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req,
931 uint64_t mid)
933 struct smbd_smb2_create_state *state = NULL;
935 if (!smb2req->subreq) {
936 return;
938 if (!tevent_req_is_in_progress(smb2req->subreq)) {
939 return;
941 state = tevent_req_data(smb2req->subreq,
942 struct smbd_smb2_create_state);
943 if (!state) {
944 return;
947 DEBUG(10,("remove_deferred_open_message_smb2_internal: "
948 "mid %llu\n",
949 (unsigned long long)mid ));
951 /* Ensure we don't have any outstanding timer event. */
952 TALLOC_FREE(state->te);
955 void remove_deferred_open_message_smb2(uint64_t mid)
957 struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
959 if (!smb2req) {
960 DEBUG(10,("remove_deferred_open_message_smb2: "
961 "can't find mid %llu\n",
962 (unsigned long long)mid ));
963 return;
965 remove_deferred_open_message_smb2_internal(smb2req, mid);
968 void schedule_deferred_open_message_smb2(uint64_t mid)
970 struct tevent_immediate *im = NULL;
971 struct smbd_smb2_create_state *state = NULL;
972 struct smbd_smb2_request *smb2req = find_open_smb2req(mid);
974 if (!smb2req) {
975 DEBUG(10,("schedule_deferred_open_message_smb2: "
976 "can't find mid %llu\n",
977 (unsigned long long)mid ));
978 return;
980 if (!smb2req->subreq) {
981 return;
983 if (!tevent_req_is_in_progress(smb2req->subreq)) {
984 return;
986 state = tevent_req_data(smb2req->subreq,
987 struct smbd_smb2_create_state);
988 if (!state) {
989 return;
991 /* Ensure we don't have any outstanding timer event. */
992 TALLOC_FREE(state->te);
995 * This is subtle. We must null out the callback
996 * before resheduling, else the first call to
997 * tevent_req_nterror() causes the _receive()
998 * function to be called, this causing tevent_req_post()
999 * to crash.
1001 tevent_req_set_callback(smb2req->subreq, NULL, NULL);
1003 im = tevent_create_immediate(smb2req);
1004 if (!im) {
1005 smbd_server_connection_terminate(smb2req->sconn,
1006 nt_errstr(NT_STATUS_NO_MEMORY));
1009 DEBUG(10,("schedule_deferred_open_message_smb2: "
1010 "re-processing mid %llu\n",
1011 (unsigned long long)mid ));
1013 tevent_schedule_immediate(im,
1014 smb2req->sconn->smb2.event_ctx,
1015 smbd_smb2_request_dispatch_immediate,
1016 smb2req);
1019 /*********************************************************
1020 Re-process this call.
1021 *********************************************************/
1023 static void smb2_deferred_open_timer(struct event_context *ev,
1024 struct timed_event *te,
1025 struct timeval _tval,
1026 void *private_data)
1028 NTSTATUS status;
1029 struct smbd_smb2_create_state *state = NULL;
1030 struct smbd_smb2_request *smb2req = talloc_get_type(private_data,
1031 struct smbd_smb2_request);
1033 DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n",
1034 smb2req->current_idx,
1035 tevent_req_default_print(smb2req->subreq, talloc_tos()) ));
1037 state = tevent_req_data(smb2req->subreq,
1038 struct smbd_smb2_create_state);
1039 if (!state) {
1040 return;
1043 * Null this out, don't talloc_free. It will
1044 * be talloc_free'd by the tevent library when
1045 * this returns.
1047 state->te = NULL;
1050 * This is subtle. We must null out the callback
1051 * before resheduling, else the first call to
1052 * tevent_req_nterror() causes the _receive()
1053 * function to be called, this causing tevent_req_post()
1054 * to crash.
1056 tevent_req_set_callback(smb2req->subreq, NULL, NULL);
1058 status = smbd_smb2_request_dispatch(smb2req);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 smbd_server_connection_terminate(smb2req->sconn,
1062 nt_errstr(status));
1066 static bool smbd_smb2_create_cancel(struct tevent_req *req)
1068 struct smbd_smb2_request *smb2req = NULL;
1069 struct smbd_smb2_create_state *state = tevent_req_data(req,
1070 struct smbd_smb2_create_state);
1071 uint64_t mid;
1073 if (!state) {
1074 return false;
1077 if (!state->smb2req) {
1078 return false;
1081 smb2req = state->smb2req;
1082 mid = get_mid_from_smb2req(smb2req);
1084 remove_deferred_open_entry(state->id, mid);
1085 remove_deferred_open_message_smb2_internal(smb2req, mid);
1086 smb2req->cancelled = true;
1088 tevent_req_done(req);
1089 return true;
1092 bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
1093 struct timeval request_time,
1094 struct timeval timeout,
1095 struct file_id id,
1096 char *private_data,
1097 size_t priv_len)
1099 struct tevent_req *req = NULL;
1100 struct smbd_smb2_create_state *state = NULL;
1101 struct timeval end_time;
1103 if (!smb2req) {
1104 return false;
1106 req = smb2req->subreq;
1107 if (!req) {
1108 return false;
1110 state = tevent_req_data(req, struct smbd_smb2_create_state);
1111 if (!state) {
1112 return false;
1114 state->id = id;
1115 state->request_time = request_time;
1116 state->private_data = data_blob_talloc(state, private_data,
1117 priv_len);
1118 if (!state->private_data.data) {
1119 return false;
1121 #if 0
1122 /* Boo - turns out this isn't what W2K8R2
1123 does. It actually sends the STATUS_PENDING
1124 message followed by the STATUS_SHARING_VIOLATION
1125 message. Surely this means that all open
1126 calls (even on directories) will potentially
1127 fail in a chain.... ? And I've seen directory
1128 opens as the start of a chain. JRA.
1131 * More subtlety. To match W2K8R2 don't
1132 * send a "gone async" message if it's simply
1133 * a STATUS_SHARING_VIOLATION (short) wait, not
1134 * an oplock break wait. We do this by prematurely
1135 * setting smb2req->async flag.
1137 if (timeout.tv_sec < 2) {
1138 DEBUG(10,("push_deferred_open_message_smb2: "
1139 "short timer wait (usec = %u). "
1140 "Don't send async message.\n",
1141 (unsigned int)timeout.tv_usec ));
1142 smb2req->async = true;
1144 #endif
1146 /* Re-schedule us to retry on timer expiry. */
1147 end_time = timeval_sum(&request_time, &timeout);
1149 DEBUG(10,("push_deferred_open_message_smb2: "
1150 "timeout at %s\n",
1151 timeval_string(talloc_tos(),
1152 &end_time,
1153 true) ));
1155 state->te = event_add_timed(smb2req->sconn->smb2.event_ctx,
1156 state,
1157 end_time,
1158 smb2_deferred_open_timer,
1159 smb2req);
1160 if (!state->te) {
1161 return false;
1164 /* allow this request to be canceled */
1165 tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);
1167 return true;