s3:smb2_create: make use of smbd_smb2_generate_outbody()
[amitay/samba.git] / source3 / smbd / smb2_create.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6    Copyright (C) Jeremy Allison 2010
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
23 #include "printing.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "../libcli/smb/smb_common.h"
27 #include "../librpc/gen_ndr/ndr_security.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "messages.h"
30
31 int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
32 {
33         switch(in_oplock_level) {
34         case SMB2_OPLOCK_LEVEL_NONE:
35                 return NO_OPLOCK;
36         case SMB2_OPLOCK_LEVEL_II:
37                 return LEVEL_II_OPLOCK;
38         case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
39                 return EXCLUSIVE_OPLOCK;
40         case SMB2_OPLOCK_LEVEL_BATCH:
41                 return BATCH_OPLOCK;
42         case SMB2_OPLOCK_LEVEL_LEASE:
43                 DEBUG(2,("map_smb2_oplock_levels_to_samba: "
44                         "LEASE_OPLOCK_REQUESTED\n"));
45                 return NO_OPLOCK;
46         default:
47                 DEBUG(2,("map_smb2_oplock_levels_to_samba: "
48                         "unknown level %u\n",
49                         (unsigned int)in_oplock_level));
50                 return NO_OPLOCK;
51         }
52 }
53
54 static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
55 {
56         if (BATCH_OPLOCK_TYPE(oplock_type)) {
57                 return SMB2_OPLOCK_LEVEL_BATCH;
58         } else if (EXCLUSIVE_OPLOCK_TYPE(oplock_type)) {
59                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
60         } else if (oplock_type == LEVEL_II_OPLOCK) {
61                 return SMB2_OPLOCK_LEVEL_II;
62         } else {
63                 return SMB2_OPLOCK_LEVEL_NONE;
64         }
65 }
66
67 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
68                         struct tevent_context *ev,
69                         struct smbd_smb2_request *smb2req,
70                         uint8_t in_oplock_level,
71                         uint32_t in_impersonation_level,
72                         uint32_t in_desired_access,
73                         uint32_t in_file_attributes,
74                         uint32_t in_share_access,
75                         uint32_t in_create_disposition,
76                         uint32_t in_create_options,
77                         const char *in_name,
78                         struct smb2_create_blobs in_context_blobs);
79 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
80                         TALLOC_CTX *mem_ctx,
81                         uint8_t *out_oplock_level,
82                         uint32_t *out_create_action,
83                         NTTIME *out_creation_time,
84                         NTTIME *out_last_access_time,
85                         NTTIME *out_last_write_time,
86                         NTTIME *out_change_time,
87                         uint64_t *out_allocation_size,
88                         uint64_t *out_end_of_file,
89                         uint32_t *out_file_attributes,
90                         uint64_t *out_file_id_persistent,
91                         uint64_t *out_file_id_volatile,
92                         struct smb2_create_blobs *out_context_blobs);
93
94 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq);
95 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
96 {
97         const uint8_t *inbody;
98         const struct iovec *indyniov;
99         uint8_t in_oplock_level;
100         uint32_t in_impersonation_level;
101         uint32_t in_desired_access;
102         uint32_t in_file_attributes;
103         uint32_t in_share_access;
104         uint32_t in_create_disposition;
105         uint32_t in_create_options;
106         uint16_t in_name_offset;
107         uint16_t in_name_length;
108         DATA_BLOB in_name_buffer;
109         char *in_name_string;
110         size_t in_name_string_size;
111         uint32_t name_offset = 0;
112         uint32_t name_available_length = 0;
113         uint32_t in_context_offset;
114         uint32_t in_context_length;
115         DATA_BLOB in_context_buffer;
116         struct smb2_create_blobs in_context_blobs;
117         uint32_t context_offset = 0;
118         uint32_t context_available_length = 0;
119         uint32_t dyn_offset;
120         NTSTATUS status;
121         bool ok;
122         struct tevent_req *tsubreq;
123
124         status = smbd_smb2_request_verify_sizes(smb2req, 0x39);
125         if (!NT_STATUS_IS_OK(status)) {
126                 return smbd_smb2_request_error(smb2req, status);
127         }
128         inbody = SMBD_SMB2_IN_BODY_PTR(smb2req);
129
130         in_oplock_level         = CVAL(inbody, 0x03);
131         in_impersonation_level  = IVAL(inbody, 0x04);
132         in_desired_access       = IVAL(inbody, 0x18);
133         in_file_attributes      = IVAL(inbody, 0x1C);
134         in_share_access         = IVAL(inbody, 0x20);
135         in_create_disposition   = IVAL(inbody, 0x24);
136         in_create_options       = IVAL(inbody, 0x28);
137         in_name_offset          = SVAL(inbody, 0x2C);
138         in_name_length          = SVAL(inbody, 0x2E);
139         in_context_offset       = IVAL(inbody, 0x30);
140         in_context_length       = IVAL(inbody, 0x34);
141
142         /*
143          * First check if the dynamic name and context buffers
144          * are correctly specified.
145          *
146          * Note: That we don't check if the name and context buffers
147          *       overlap
148          */
149
150         dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(smb2req);
151
152         if (in_name_offset == 0 && in_name_length == 0) {
153                 /* This is ok */
154                 name_offset = 0;
155         } else if (in_name_offset < dyn_offset) {
156                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
157         } else {
158                 name_offset = in_name_offset - dyn_offset;
159         }
160
161         indyniov = SMBD_SMB2_IN_DYN_IOV(smb2req);
162
163         if (name_offset > indyniov->iov_len) {
164                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
165         }
166
167         name_available_length = indyniov->iov_len - name_offset;
168
169         if (in_name_length > name_available_length) {
170                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
171         }
172
173         in_name_buffer.data = (uint8_t *)indyniov->iov_base + name_offset;
174         in_name_buffer.length = in_name_length;
175
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;
183         }
184
185         if (context_offset > indyniov->iov_len) {
186                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
187         }
188
189         context_available_length = indyniov->iov_len - context_offset;
190
191         if (in_context_length > context_available_length) {
192                 return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
193         }
194
195         in_context_buffer.data = (uint8_t *)indyniov->iov_base +
196                 context_offset;
197         in_context_buffer.length = in_context_length;
198
199         /*
200          * Now interpret the name and context buffers
201          */
202
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);
208         if (!ok) {
209                 return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
210         }
211
212         if (in_name_buffer.length == 0) {
213                 in_name_string_size = 0;
214         }
215
216         if (strlen(in_name_string) != in_name_string_size) {
217                 return smbd_smb2_request_error(smb2req, NT_STATUS_OBJECT_NAME_INVALID);
218         }
219
220         ZERO_STRUCT(in_context_blobs);
221         status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
222         if (!NT_STATUS_IS_OK(status)) {
223                 return smbd_smb2_request_error(smb2req, status);
224         }
225
226         tsubreq = smbd_smb2_create_send(smb2req,
227                                        smb2req->sconn->ev_ctx,
228                                        smb2req,
229                                        in_oplock_level,
230                                        in_impersonation_level,
231                                        in_desired_access,
232                                        in_file_attributes,
233                                        in_share_access,
234                                        in_create_disposition,
235                                        in_create_options,
236                                        in_name_string,
237                                        in_context_blobs);
238         if (tsubreq == NULL) {
239                 smb2req->subreq = NULL;
240                 return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
241         }
242         tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);
243
244         /*
245          * For now we keep the logic that we do not send STATUS_PENDING
246          * for sharing violations, so we just wait 2 seconds.
247          *
248          * TODO: we need more tests for this.
249          */
250         return smbd_smb2_request_pending_queue(smb2req, tsubreq, 2000000);
251 }
252
253 static uint64_t get_mid_from_smb2req(struct smbd_smb2_request *smb2req)
254 {
255         uint8_t *reqhdr = SMBD_SMB2_OUT_HDR_PTR(smb2req);
256         return BVAL(reqhdr, SMB2_HDR_MESSAGE_ID);
257 }
258
259 static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
260 {
261         struct smbd_smb2_request *smb2req = tevent_req_callback_data(tsubreq,
262                                         struct smbd_smb2_request);
263         DATA_BLOB outbody;
264         DATA_BLOB outdyn;
265         uint8_t out_oplock_level = 0;
266         uint32_t out_create_action = 0;
267         NTTIME out_creation_time = 0;
268         NTTIME out_last_access_time = 0;
269         NTTIME out_last_write_time = 0;
270         NTTIME out_change_time = 0;
271         uint64_t out_allocation_size = 0;
272         uint64_t out_end_of_file = 0;
273         uint32_t out_file_attributes = 0;
274         uint64_t out_file_id_persistent = 0;
275         uint64_t out_file_id_volatile = 0;
276         struct smb2_create_blobs out_context_blobs;
277         DATA_BLOB out_context_buffer;
278         uint16_t out_context_buffer_offset = 0;
279         NTSTATUS status;
280         NTSTATUS error; /* transport error */
281
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_persistent,
294                                        &out_file_id_volatile,
295                                        &out_context_blobs);
296         if (!NT_STATUS_IS_OK(status)) {
297                 error = smbd_smb2_request_error(smb2req, status);
298                 if (!NT_STATUS_IS_OK(error)) {
299                         smbd_server_connection_terminate(smb2req->sconn,
300                                                          nt_errstr(error));
301                         return;
302                 }
303                 return;
304         }
305
306         status = smb2_create_blob_push(smb2req, &out_context_buffer, out_context_blobs);
307         if (!NT_STATUS_IS_OK(status)) {
308                 error = smbd_smb2_request_error(smb2req, status);
309                 if (!NT_STATUS_IS_OK(error)) {
310                         smbd_server_connection_terminate(smb2req->sconn,
311                                                          nt_errstr(error));
312                         return;
313                 }
314                 return;
315         }
316
317         if (out_context_buffer.length > 0) {
318                 out_context_buffer_offset = SMB2_HDR_BODY + 0x58;
319         }
320
321         outbody = smbd_smb2_generate_outbody(smb2req, 0x58);
322         if (outbody.data == NULL) {
323                 error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
324                 if (!NT_STATUS_IS_OK(error)) {
325                         smbd_server_connection_terminate(smb2req->sconn,
326                                                          nt_errstr(error));
327                         return;
328                 }
329                 return;
330         }
331
332         SSVAL(outbody.data, 0x00, 0x58 + 1);    /* struct size */
333         SCVAL(outbody.data, 0x02,
334               out_oplock_level);                /* oplock level */
335         SCVAL(outbody.data, 0x03, 0);           /* reserved */
336         SIVAL(outbody.data, 0x04,
337               out_create_action);               /* create action */
338         SBVAL(outbody.data, 0x08,
339               out_creation_time);               /* creation time */
340         SBVAL(outbody.data, 0x10,
341               out_last_access_time);            /* last access time */
342         SBVAL(outbody.data, 0x18,
343               out_last_write_time);             /* last write time */
344         SBVAL(outbody.data, 0x20,
345               out_change_time);                 /* change time */
346         SBVAL(outbody.data, 0x28,
347               out_allocation_size);             /* allocation size */
348         SBVAL(outbody.data, 0x30,
349               out_end_of_file);                 /* end of file */
350         SIVAL(outbody.data, 0x38,
351               out_file_attributes);             /* file attributes */
352         SIVAL(outbody.data, 0x3C, 0);           /* reserved */
353         SBVAL(outbody.data, 0x40,
354               out_file_id_persistent);          /* 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 */
361
362         outdyn = out_context_buffer;
363
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;
369         }
370 }
371
372 struct smbd_smb2_create_state {
373         struct smbd_smb2_request *smb2req;
374         struct smb_request *smb1req;
375         bool open_was_deferred;
376         struct tevent_timer *te;
377         struct tevent_immediate *im;
378         struct timeval request_time;
379         struct file_id id;
380         DATA_BLOB private_data;
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_persistent;
391         uint64_t out_file_id_volatile;
392         struct smb2_create_blobs out_context_blobs;
393 };
394
395 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
396                         struct tevent_context *ev,
397                         struct smbd_smb2_request *smb2req,
398                         uint8_t in_oplock_level,
399                         uint32_t in_impersonation_level,
400                         uint32_t in_desired_access,
401                         uint32_t in_file_attributes,
402                         uint32_t in_share_access,
403                         uint32_t in_create_disposition,
404                         uint32_t in_create_options,
405                         const char *in_name,
406                         struct smb2_create_blobs in_context_blobs)
407 {
408         struct tevent_req *req = NULL;
409         struct smbd_smb2_create_state *state = NULL;
410         NTSTATUS status;
411         struct smb_request *smb1req = NULL;
412         files_struct *result = NULL;
413         int info;
414         struct smb2_create_blobs out_context_blobs;
415         int requested_oplock_level;
416         struct smb2_create_blob *dhnc = NULL;
417         struct smb2_create_blob *dh2c = NULL;
418         struct smb2_create_blob *dhnq = NULL;
419         struct smb2_create_blob *dh2q = NULL;
420         struct smbXsrv_open *op = NULL;
421
422         ZERO_STRUCT(out_context_blobs);
423
424         if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
425                 requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
426         } else {
427                 requested_oplock_level = in_oplock_level;
428         }
429
430
431         if (smb2req->subreq == NULL) {
432                 /* New create call. */
433                 req = tevent_req_create(mem_ctx, &state,
434                                 struct smbd_smb2_create_state);
435                 if (req == NULL) {
436                         return NULL;
437                 }
438                 state->smb2req = smb2req;
439
440                 smb1req = smbd_smb2_fake_smb_request(smb2req);
441                 if (tevent_req_nomem(smb1req, req)) {
442                         return tevent_req_post(req, ev);
443                 }
444                 state->smb1req = smb1req;
445                 smb2req->subreq = req;
446                 DEBUG(10,("smbd_smb2_create: name[%s]\n",
447                         in_name));
448         } else {
449                 /* Re-entrant create call. */
450                 req = smb2req->subreq;
451                 state = tevent_req_data(req,
452                                 struct smbd_smb2_create_state);
453                 smb1req = state->smb1req;
454                 DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
455                         in_name ));
456         }
457
458         dhnq = smb2_create_blob_find(&in_context_blobs,
459                                      SMB2_CREATE_TAG_DHNQ);
460         dhnc = smb2_create_blob_find(&in_context_blobs,
461                                      SMB2_CREATE_TAG_DHNC);
462         dh2q = smb2_create_blob_find(&in_context_blobs,
463                                      SMB2_CREATE_TAG_DH2Q);
464         dh2c = smb2_create_blob_find(&in_context_blobs,
465                                      SMB2_CREATE_TAG_DH2C);
466
467         if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
468             (dh2q && dh2c))
469         {
470                 /* not both are allowed at the same time */
471                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
472                 return tevent_req_post(req, ev);
473         }
474
475         if (dhnc) {
476                 uint32_t num_blobs_allowed;
477
478                 if (dhnc->data.length != 16) {
479                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
480                         return tevent_req_post(req, ev);
481                 }
482
483                 /*
484                  * According to MS-SMB2: 3.3.5.9.7, "Handling the
485                  * SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context",
486                  * we should ignore an additional dhnq blob, but fail
487                  * the request (with status OBJECT_NAME_NOT_FOUND) if
488                  * any other extra create blob has been provided.
489                  *
490                  * (Note that the cases of an additional dh2q or dh2c blob
491                  *  which require a different error code, have been treated
492                  *  above.)
493                  *
494                  * TODO:
495                  * This is only true for the oplock case:
496                  * For leases, lease request is required additionally.
497                  */
498
499                 if (dhnq) {
500                         num_blobs_allowed = 2;
501                 } else {
502                         num_blobs_allowed = 1;
503                 }
504
505                 if (in_context_blobs.num_blobs != num_blobs_allowed) {
506                         tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
507                         return tevent_req_post(req, ev);
508                 }
509         }
510
511         if (dh2c) {
512                 uint32_t num_blobs_allowed;
513
514                 if (dh2c->data.length != 36) {
515                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
516                         return tevent_req_post(req, ev);
517                 }
518
519                 /*
520                  * According to MS-SMB2: 3.3.5.9.12, "Handling the
521                  * SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context",
522                  * we should fail the request with status
523                  * OBJECT_NAME_NOT_FOUND if any other create blob has been
524                  * provided.
525                  *
526                  * (Note that the cases of an additional dhnq, dhnc or dh2q
527                  *  blob which require a different error code, have been
528                  *  treated above.)
529                  *
530                  * TODO:
531                  * This is only true for the oplock case:
532                  * For leases, lease request is required additionally!
533                  */
534
535                 num_blobs_allowed = 1;
536
537                 if (in_context_blobs.num_blobs != num_blobs_allowed) {
538                         tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
539                         return tevent_req_post(req, ev);
540                 }
541         }
542
543         if (IS_IPC(smb1req->conn)) {
544                 const char *pipe_name = in_name;
545
546                 if (dhnc || dh2c) {
547                         /* durable handles are not supported on IPC$ */
548                         tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
549                         return tevent_req_post(req, ev);
550                 }
551
552                 if (!lp_nt_pipe_support()) {
553                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
554                         return tevent_req_post(req, ev);
555                 }
556
557                 status = open_np_file(smb1req, pipe_name, &result);
558                 if (!NT_STATUS_IS_OK(status)) {
559                         tevent_req_nterror(req, status);
560                         return tevent_req_post(req, ev);
561                 }
562                 info = FILE_WAS_OPENED;
563         } else if (CAN_PRINT(smb1req->conn)) {
564                 if (dhnc || dh2c) {
565                         /* durable handles are not supported on printers */
566                         tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
567                         return tevent_req_post(req, ev);
568                 }
569
570                 status = file_new(smb1req, smb1req->conn, &result);
571                 if(!NT_STATUS_IS_OK(status)) {
572                         tevent_req_nterror(req, status);
573                         return tevent_req_post(req, ev);
574                 }
575
576                 status = print_spool_open(result, in_name,
577                                           smb1req->vuid);
578                 if (!NT_STATUS_IS_OK(status)) {
579                         file_free(smb1req, result);
580                         tevent_req_nterror(req, status);
581                         return tevent_req_post(req, ev);
582                 }
583                 info = FILE_WAS_CREATED;
584         } else {
585                 char *fname;
586                 struct smb2_create_blob *exta = NULL;
587                 struct ea_list *ea_list = NULL;
588                 struct smb2_create_blob *mxac = NULL;
589                 NTTIME max_access_time = 0;
590                 struct smb2_create_blob *secd = NULL;
591                 struct security_descriptor *sec_desc = NULL;
592                 struct smb2_create_blob *alsi = NULL;
593                 uint64_t allocation_size = 0;
594                 struct smb2_create_blob *twrp = NULL;
595                 struct smb2_create_blob *qfid = NULL;
596                 struct GUID _create_guid = GUID_zero();
597                 struct GUID *create_guid = NULL;
598                 bool update_open = false;
599                 bool durable_requested = false;
600                 uint32_t durable_timeout_msec = 0;
601                 bool do_durable_reconnect = false;
602                 uint64_t persistent_id = 0;
603
604                 exta = smb2_create_blob_find(&in_context_blobs,
605                                              SMB2_CREATE_TAG_EXTA);
606                 mxac = smb2_create_blob_find(&in_context_blobs,
607                                              SMB2_CREATE_TAG_MXAC);
608                 secd = smb2_create_blob_find(&in_context_blobs,
609                                              SMB2_CREATE_TAG_SECD);
610                 alsi = smb2_create_blob_find(&in_context_blobs,
611                                              SMB2_CREATE_TAG_ALSI);
612                 twrp = smb2_create_blob_find(&in_context_blobs,
613                                              SMB2_CREATE_TAG_TWRP);
614                 qfid = smb2_create_blob_find(&in_context_blobs,
615                                              SMB2_CREATE_TAG_QFID);
616
617                 fname = talloc_strdup(state, in_name);
618                 if (tevent_req_nomem(fname, req)) {
619                         return tevent_req_post(req, ev);
620                 }
621
622                 if (exta) {
623                         ea_list = read_nttrans_ea_list(mem_ctx,
624                                 (const char *)exta->data.data, exta->data.length);
625                         if (!ea_list) {
626                                 DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
627                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
628                                 return tevent_req_post(req, ev);
629                         }
630
631                         if (ea_list_has_invalid_name(ea_list)) {
632                                 tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
633                                 return tevent_req_post(req, ev);
634                         }
635                 }
636
637                 if (mxac) {
638                         if (mxac->data.length == 0) {
639                                 max_access_time = 0;
640                         } else if (mxac->data.length == 8) {
641                                 max_access_time = BVAL(mxac->data.data, 0);
642                         } else {
643                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
644                                 return tevent_req_post(req, ev);
645                         }
646                 }
647
648                 if (secd) {
649                         enum ndr_err_code ndr_err;
650
651                         sec_desc = talloc_zero(state, struct security_descriptor);
652                         if (tevent_req_nomem(sec_desc, req)) {
653                                 return tevent_req_post(req, ev);
654                         }
655
656                         ndr_err = ndr_pull_struct_blob(&secd->data,
657                                 sec_desc, sec_desc,
658                                 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
659                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
660                                 DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
661                                          ndr_errstr(ndr_err)));
662                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
663                                 return tevent_req_post(req, ev);
664                         }
665                 }
666
667                 if (dhnq) {
668                         if (dhnq->data.length != 16) {
669                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
670                                 return tevent_req_post(req, ev);
671                         }
672
673                         if (dh2q) {
674                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
675                                 return tevent_req_post(req, ev);
676                         }
677
678                         /*
679                          * durable handle request is processed below.
680                          */
681                         durable_requested = true;
682                         /*
683                          * Set the timeout to 16 mins.
684                          *
685                          * TODO: test this against Windows 2012
686                          *       as the default for durable v2 is 1 min.
687                          */
688                         durable_timeout_msec = (16*60*1000);
689                 }
690
691                 if (dh2q) {
692                         const uint8_t *p = dh2q->data.data;
693                         uint32_t durable_v2_timeout = 0;
694                         DATA_BLOB create_guid_blob;
695
696                         if (dh2q->data.length != 32) {
697                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
698                                 return tevent_req_post(req, ev);
699                         }
700
701                         if (dhnq) {
702                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
703                                 return tevent_req_post(req, ev);
704                         }
705
706                         durable_v2_timeout = IVAL(p, 0);
707                         create_guid_blob = data_blob_const(p + 16, 16);
708
709                         status = GUID_from_ndr_blob(&create_guid_blob,
710                                                     &_create_guid);
711                         if (tevent_req_nterror(req, status)) {
712                                 return tevent_req_post(req, ev);
713                         }
714                         create_guid = &_create_guid;
715                         /*
716                          * we need to store the create_guid later
717                          */
718                         update_open = true;
719
720                         /*
721                          * durable handle v2 request processed below
722                          */
723                         durable_requested = true;
724                         durable_timeout_msec = durable_v2_timeout;
725                         if (durable_timeout_msec == 0) {
726                                 /*
727                                  * Set the timeout to 1 min as default.
728                                  *
729                                  * This matches Windows 2012.
730                                  */
731                                 durable_timeout_msec = (60*1000);
732                         }
733                 }
734
735                 if (dhnc) {
736                         persistent_id = BVAL(dhnc->data.data, 0);
737
738                         do_durable_reconnect = true;
739                 }
740
741                 if (dh2c) {
742                         const uint8_t *p = dh2c->data.data;
743                         DATA_BLOB create_guid_blob;
744
745                         persistent_id = BVAL(p, 0);
746                         create_guid_blob = data_blob_const(p + 16, 16);
747
748                         status = GUID_from_ndr_blob(&create_guid_blob,
749                                                     &_create_guid);
750                         if (tevent_req_nterror(req, status)) {
751                                 return tevent_req_post(req, ev);
752                         }
753                         create_guid = &_create_guid;
754
755                         do_durable_reconnect = true;
756                 }
757
758                 if (alsi) {
759                         if (alsi->data.length != 8) {
760                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
761                                 return tevent_req_post(req, ev);
762                         }
763                         allocation_size = BVAL(alsi->data.data, 0);
764                 }
765
766                 if (twrp) {
767                         NTTIME nttime;
768                         time_t t;
769                         struct tm *tm;
770
771                         if (twrp->data.length != 8) {
772                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
773                                 return tevent_req_post(req, ev);
774                         }
775
776                         nttime = BVAL(twrp->data.data, 0);
777                         t = nt_time_to_unix(nttime);
778                         tm = gmtime(&t);
779
780                         TALLOC_FREE(fname);
781                         fname = talloc_asprintf(state,
782                                         "@GMT-%04u.%02u.%02u-%02u.%02u.%02u\\%s",
783                                         tm->tm_year + 1900,
784                                         tm->tm_mon + 1,
785                                         tm->tm_mday,
786                                         tm->tm_hour,
787                                         tm->tm_min,
788                                         tm->tm_sec,
789                                         in_name);
790                         if (tevent_req_nomem(fname, req)) {
791                                 return tevent_req_post(req, ev);
792                         }
793                 }
794
795                 if (qfid) {
796                         if (qfid->data.length != 0) {
797                                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
798                                 return tevent_req_post(req, ev);
799                         }
800                 }
801
802                 /* these are ignored for SMB2 */
803                 in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
804                 in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
805
806                 in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
807
808                 DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
809
810                 /*
811                  * For the backend file open procedure, there are
812                  * two possible modes: durable_reconnect or not.
813                  */
814                 if (do_durable_reconnect) {
815                         DATA_BLOB new_cookie = data_blob_null;
816                         NTTIME now = timeval_to_nttime(&smb2req->request_time);
817
818                         status = smb2srv_open_recreate(smb2req->sconn->conn,
819                                                 smb1req->conn->session_info,
820                                                 persistent_id, create_guid,
821                                                 now, &op);
822                         if (!NT_STATUS_IS_OK(status)) {
823                                 DEBUG(3, ("smbd_smb2_create_send: "
824                                           "smb2srv_open_recreate failed: %s\n",
825                                           nt_errstr(status)));
826                                 tevent_req_nterror(req, status);
827                                 return tevent_req_post(req, ev);
828                         }
829
830                         DEBUG(10, ("smb2_create_send: %s to recreate the "
831                                    "smb2srv_open struct for a durable handle.\n",
832                                    op->global->durable ? "succeded" : "failed"));
833
834                         if (!op->global->durable) {
835                                 talloc_free(op);
836                                 tevent_req_nterror(req,
837                                         NT_STATUS_OBJECT_NAME_NOT_FOUND);
838                                 return tevent_req_post(req, ev);
839                         }
840
841                         status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
842                                                 smb1req,
843                                                 op, /* smbXsrv_open input */
844                                                 op->global->backend_cookie,
845                                                 op, /* TALLOC_CTX */
846                                                 &result, &new_cookie);
847                         if (!NT_STATUS_IS_OK(status)) {
848                                 NTSTATUS return_status;
849
850                                 return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
851
852                                 DEBUG(3, ("smbd_smb2_create_send: "
853                                           "durable_reconnect failed: %s => %s\n",
854                                           nt_errstr(status),
855                                           nt_errstr(return_status)));
856
857                                 tevent_req_nterror(req, return_status);
858                                 return tevent_req_post(req, ev);
859                         }
860
861                         data_blob_free(&op->global->backend_cookie);
862                         op->global->backend_cookie = new_cookie;
863
864                         op->status = NT_STATUS_OK;
865                         op->global->disconnect_time = 0;
866
867                         /* save the timout for later update */
868                         durable_timeout_msec = op->global->durable_timeout_msec;
869
870                         update_open = true;
871
872                         info = FILE_WAS_OPENED;
873                 } else {
874                         struct smb_filename *smb_fname = NULL;
875
876                         /*
877                          * For a DFS path the function parse_dfs_path()
878                          * will do the path processing.
879                          */
880
881                         if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
882                                 /* convert '\\' into '/' */
883                                 status = check_path_syntax(fname);
884                                 if (!NT_STATUS_IS_OK(status)) {
885                                         tevent_req_nterror(req, status);
886                                         return tevent_req_post(req, ev);
887                                 }
888                         }
889
890                         status = filename_convert(req,
891                                                   smb1req->conn,
892                                                   smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
893                                                   fname,
894                                                   UCF_PREP_CREATEFILE,
895                                                   NULL, /* ppath_contains_wcards */
896                                                   &smb_fname);
897                         if (!NT_STATUS_IS_OK(status)) {
898                                 tevent_req_nterror(req, status);
899                                 return tevent_req_post(req, ev);
900                         }
901
902                         status = SMB_VFS_CREATE_FILE(smb1req->conn,
903                                                      smb1req,
904                                                      0, /* root_dir_fid */
905                                                      smb_fname,
906                                                      in_desired_access,
907                                                      in_share_access,
908                                                      in_create_disposition,
909                                                      in_create_options,
910                                                      in_file_attributes,
911                                                      map_smb2_oplock_levels_to_samba(requested_oplock_level),
912                                                      allocation_size,
913                                                      0, /* private_flags */
914                                                      sec_desc,
915                                                      ea_list,
916                                                      &result,
917                                                      &info);
918                         if (!NT_STATUS_IS_OK(status)) {
919                                 if (open_was_deferred(smb1req->sconn, smb1req->mid)) {
920                                         return req;
921                                 }
922                                 tevent_req_nterror(req, status);
923                                 return tevent_req_post(req, ev);
924                         }
925                         op = result->op;
926                 }
927
928                 /*
929                  * here we have op == result->op
930                  */
931
932                 DEBUG(10, ("smbd_smb2_create_send: "
933                            "response construction phase\n"));
934
935                 if (mxac) {
936                         NTTIME last_write_time;
937
938                         unix_timespec_to_nt_time(&last_write_time,
939                                                  result->fsp_name->st.st_ex_mtime);
940                         if (last_write_time != max_access_time) {
941                                 uint8_t p[8];
942                                 uint32_t max_access_granted;
943                                 DATA_BLOB blob = data_blob_const(p, sizeof(p));
944
945                                 status = smbd_calculate_access_mask(smb1req->conn,
946                                                         result->fsp_name,
947                                                         false,
948                                                         SEC_FLAG_MAXIMUM_ALLOWED,
949                                                         &max_access_granted);
950
951                                 SIVAL(p, 0, NT_STATUS_V(status));
952                                 SIVAL(p, 4, max_access_granted);
953
954                                 status = smb2_create_blob_add(state,
955                                                         &out_context_blobs,
956                                                         SMB2_CREATE_TAG_MXAC,
957                                                         blob);
958                                 if (!NT_STATUS_IS_OK(status)) {
959                                         tevent_req_nterror(req, status);
960                                         return tevent_req_post(req, ev);
961                                 }
962                         }
963                 }
964
965                 if (durable_requested &&
966                     BATCH_OPLOCK_TYPE(result->oplock_type))
967                 {
968                         status = SMB_VFS_DURABLE_COOKIE(result,
969                                                 op,
970                                                 &op->global->backend_cookie);
971                         if (!NT_STATUS_IS_OK(status)) {
972                                 op->global->backend_cookie = data_blob_null;
973                         }
974                 }
975                 if (op->global->backend_cookie.length > 0) {
976                         update_open = true;
977
978                         op->global->durable = true;
979                         op->global->durable_timeout_msec = durable_timeout_msec;
980                 }
981
982                 if (update_open) {
983                         op->global->create_guid = _create_guid;
984
985                         status = smbXsrv_open_update(op);
986                         DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
987                                    "returned %s\n",
988                                    nt_errstr(status)));
989                         if (!NT_STATUS_IS_OK(status)) {
990                                 tevent_req_nterror(req, status);
991                                 return tevent_req_post(req, ev);
992                         }
993                 }
994
995                 if (dhnq && op->global->durable) {
996                         uint8_t p[8] = { 0, };
997                         DATA_BLOB blob = data_blob_const(p, sizeof(p));
998
999                         status = smb2_create_blob_add(state,
1000                                                       &out_context_blobs,
1001                                                       SMB2_CREATE_TAG_DHNQ,
1002                                                       blob);
1003                         if (!NT_STATUS_IS_OK(status)) {
1004                                 tevent_req_nterror(req, status);
1005                                 return tevent_req_post(req, ev);
1006                         }
1007                 }
1008
1009                 if (dh2q && op->global->durable) {
1010                         uint8_t p[8] = { 0, };
1011                         DATA_BLOB blob = data_blob_const(p, sizeof(p));
1012                         uint32_t durable_v2_response_flags = 0;
1013
1014                         SIVAL(p, 0, op->global->durable_timeout_msec);
1015                         SIVAL(p, 4, durable_v2_response_flags);
1016
1017                         status = smb2_create_blob_add(state, &out_context_blobs,
1018                                                       SMB2_CREATE_TAG_DH2Q,
1019                                                       blob);
1020                         if (!NT_STATUS_IS_OK(status)) {
1021                                 tevent_req_nterror(req, status);
1022                                 return tevent_req_post(req, ev);
1023                         }
1024                 }
1025
1026                 if (qfid) {
1027                         uint8_t p[32];
1028                         uint64_t file_index = get_FileIndex(result->conn,
1029                                                         &result->fsp_name->st);
1030                         DATA_BLOB blob = data_blob_const(p, sizeof(p));
1031
1032                         ZERO_STRUCT(p);
1033
1034                         /* From conversations with Microsoft engineers at
1035                            the MS plugfest. The first 8 bytes are the "volume index"
1036                            == inode, the second 8 bytes are the "volume id",
1037                            == dev. This will be updated in the SMB2 doc. */
1038                         SBVAL(p, 0, file_index);
1039                         SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
1040
1041                         status = smb2_create_blob_add(state, &out_context_blobs,
1042                                                       SMB2_CREATE_TAG_QFID,
1043                                                       blob);
1044                         if (!NT_STATUS_IS_OK(status)) {
1045                                 tevent_req_nterror(req, status);
1046                                 return tevent_req_post(req, ev);
1047                         }
1048                 }
1049         }
1050
1051         smb2req->compat_chain_fsp = smb1req->chain_fsp;
1052
1053         if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
1054                 state->out_oplock_level = in_oplock_level;
1055         } else {
1056                 state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type);
1057         }
1058
1059         if ((in_create_disposition == FILE_SUPERSEDE)
1060             && (info == FILE_WAS_OVERWRITTEN)) {
1061                 state->out_create_action = FILE_WAS_SUPERSEDED;
1062         } else {
1063                 state->out_create_action = info;
1064         }
1065         state->out_file_attributes = dos_mode(result->conn,
1066                                            result->fsp_name);
1067
1068         unix_timespec_to_nt_time(&state->out_creation_time,
1069                         get_create_timespec(smb1req->conn, result,
1070                                         result->fsp_name));
1071         unix_timespec_to_nt_time(&state->out_last_access_time,
1072                         result->fsp_name->st.st_ex_atime);
1073         unix_timespec_to_nt_time(&state->out_last_write_time,
1074                         result->fsp_name->st.st_ex_mtime);
1075         unix_timespec_to_nt_time(&state->out_change_time,
1076                         get_change_timespec(smb1req->conn, result,
1077                                         result->fsp_name));
1078         state->out_allocation_size =
1079                         SMB_VFS_GET_ALLOC_SIZE(smb1req->conn, result,
1080                                                &(result->fsp_name->st));
1081         state->out_end_of_file = result->fsp_name->st.st_ex_size;
1082         if (state->out_file_attributes == 0) {
1083                 state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
1084         }
1085         state->out_file_id_persistent = result->op->global->open_persistent_id;
1086         state->out_file_id_volatile = result->op->global->open_volatile_id;
1087         state->out_context_blobs = out_context_blobs;
1088
1089         DEBUG(10,("smbd_smb2_create_send: %s - %s\n",
1090                   fsp_str_dbg(result), fsp_fnum_dbg(result)));
1091
1092         tevent_req_done(req);
1093         return tevent_req_post(req, ev);
1094 }
1095
1096 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
1097                         TALLOC_CTX *mem_ctx,
1098                         uint8_t *out_oplock_level,
1099                         uint32_t *out_create_action,
1100                         NTTIME *out_creation_time,
1101                         NTTIME *out_last_access_time,
1102                         NTTIME *out_last_write_time,
1103                         NTTIME *out_change_time,
1104                         uint64_t *out_allocation_size,
1105                         uint64_t *out_end_of_file,
1106                         uint32_t *out_file_attributes,
1107                         uint64_t *out_file_id_persistent,
1108                         uint64_t *out_file_id_volatile,
1109                         struct smb2_create_blobs *out_context_blobs)
1110 {
1111         NTSTATUS status;
1112         struct smbd_smb2_create_state *state = tevent_req_data(req,
1113                                                struct smbd_smb2_create_state);
1114
1115         if (tevent_req_is_nterror(req, &status)) {
1116                 tevent_req_received(req);
1117                 return status;
1118         }
1119
1120         *out_oplock_level       = state->out_oplock_level;
1121         *out_create_action      = state->out_create_action;
1122         *out_creation_time      = state->out_creation_time;
1123         *out_last_access_time   = state->out_last_access_time;
1124         *out_last_write_time    = state->out_last_write_time;
1125         *out_change_time        = state->out_change_time;
1126         *out_allocation_size    = state->out_allocation_size;
1127         *out_end_of_file        = state->out_end_of_file;
1128         *out_file_attributes    = state->out_file_attributes;
1129         *out_file_id_persistent = state->out_file_id_persistent;
1130         *out_file_id_volatile   = state->out_file_id_volatile;
1131         *out_context_blobs      = state->out_context_blobs;
1132
1133         talloc_steal(mem_ctx, state->out_context_blobs.blobs);
1134
1135         tevent_req_received(req);
1136         return NT_STATUS_OK;
1137 }
1138
1139 /*********************************************************
1140  Code for dealing with deferred opens.
1141 *********************************************************/
1142
1143 bool get_deferred_open_message_state_smb2(struct smbd_smb2_request *smb2req,
1144                         struct timeval *p_request_time,
1145                         void **pp_state)
1146 {
1147         struct smbd_smb2_create_state *state = NULL;
1148         struct tevent_req *req = NULL;
1149
1150         if (!smb2req) {
1151                 return false;
1152         }
1153         req = smb2req->subreq;
1154         if (!req) {
1155                 return false;
1156         }
1157         state = tevent_req_data(req, struct smbd_smb2_create_state);
1158         if (!state) {
1159                 return false;
1160         }
1161         if (!state->open_was_deferred) {
1162                 return false;
1163         }
1164         if (p_request_time) {
1165                 *p_request_time = state->request_time;
1166         }
1167         if (pp_state) {
1168                 *pp_state = (void *)state->private_data.data;
1169         }
1170         return true;
1171 }
1172
1173 /*********************************************************
1174  Re-process this call early - requested by message or
1175  close.
1176 *********************************************************/
1177
1178 static struct smbd_smb2_request *find_open_smb2req(
1179         struct smbd_server_connection *sconn, uint64_t mid)
1180 {
1181         struct smbd_smb2_request *smb2req;
1182
1183         for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) {
1184                 uint64_t message_id;
1185                 if (smb2req->subreq == NULL) {
1186                         /* This message has been processed. */
1187                         continue;
1188                 }
1189                 if (!tevent_req_is_in_progress(smb2req->subreq)) {
1190                         /* This message has been processed. */
1191                         continue;
1192                 }
1193                 message_id = get_mid_from_smb2req(smb2req);
1194                 if (message_id == mid) {
1195                         return smb2req;
1196                 }
1197         }
1198         return NULL;
1199 }
1200
1201 bool open_was_deferred_smb2(struct smbd_server_connection *sconn, uint64_t mid)
1202 {
1203         struct smbd_smb2_create_state *state = NULL;
1204         struct smbd_smb2_request *smb2req;
1205
1206         smb2req = find_open_smb2req(sconn, mid);
1207
1208         if (!smb2req) {
1209                 DEBUG(10,("open_was_deferred_smb2: mid %llu smb2req == NULL\n",
1210                         (unsigned long long)mid));
1211                 return false;
1212         }
1213         if (!smb2req->subreq) {
1214                 return false;
1215         }
1216         if (!tevent_req_is_in_progress(smb2req->subreq)) {
1217                 return false;
1218         }
1219         state = tevent_req_data(smb2req->subreq,
1220                         struct smbd_smb2_create_state);
1221         if (!state) {
1222                 return false;
1223         }
1224         /* It's not in progress if there's no timeout event. */
1225         if (!state->open_was_deferred) {
1226                 return false;
1227         }
1228
1229         DEBUG(10,("open_was_deferred_smb2: mid = %llu\n",
1230                         (unsigned long long)mid));
1231
1232         return true;
1233 }
1234
1235 static void remove_deferred_open_message_smb2_internal(struct smbd_smb2_request *smb2req,
1236                                                         uint64_t mid)
1237 {
1238         struct smbd_smb2_create_state *state = NULL;
1239
1240         if (!smb2req->subreq) {
1241                 return;
1242         }
1243         if (!tevent_req_is_in_progress(smb2req->subreq)) {
1244                 return;
1245         }
1246         state = tevent_req_data(smb2req->subreq,
1247                         struct smbd_smb2_create_state);
1248         if (!state) {
1249                 return;
1250         }
1251
1252         DEBUG(10,("remove_deferred_open_message_smb2_internal: "
1253                 "mid %llu\n",
1254                 (unsigned long long)mid ));
1255
1256         state->open_was_deferred = false;
1257         /* Ensure we don't have any outstanding timer event. */
1258         TALLOC_FREE(state->te);
1259         /* Ensure we don't have any outstanding immediate event. */
1260         TALLOC_FREE(state->im);
1261 }
1262
1263 void remove_deferred_open_message_smb2(
1264         struct smbd_server_connection *sconn, uint64_t mid)
1265 {
1266         struct smbd_smb2_request *smb2req;
1267
1268         smb2req = find_open_smb2req(sconn, mid);
1269
1270         if (!smb2req) {
1271                 DEBUG(10,("remove_deferred_open_message_smb2: "
1272                         "can't find mid %llu\n",
1273                         (unsigned long long)mid ));
1274                 return;
1275         }
1276         remove_deferred_open_message_smb2_internal(smb2req, mid);
1277 }
1278
1279 static void smbd_smb2_create_request_dispatch_immediate(struct tevent_context *ctx,
1280                                         struct tevent_immediate *im,
1281                                         void *private_data)
1282 {
1283         struct smbd_smb2_request *smb2req = talloc_get_type_abort(private_data,
1284                                         struct smbd_smb2_request);
1285         struct smbd_server_connection *sconn = smb2req->sconn;
1286         uint64_t mid = get_mid_from_smb2req(smb2req);
1287         NTSTATUS status;
1288
1289         DEBUG(10,("smbd_smb2_create_request_dispatch_immediate: "
1290                 "re-dispatching mid %llu\n",
1291                 (unsigned long long)mid ));
1292
1293         status = smbd_smb2_request_dispatch(smb2req);
1294         if (!NT_STATUS_IS_OK(status)) {
1295                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1296                 return;
1297         }
1298 }
1299
1300 bool schedule_deferred_open_message_smb2(
1301         struct smbd_server_connection *sconn, uint64_t mid)
1302 {
1303         struct smbd_smb2_create_state *state = NULL;
1304         struct smbd_smb2_request *smb2req;
1305
1306         smb2req = find_open_smb2req(sconn, mid);
1307
1308         if (!smb2req) {
1309                 DEBUG(10,("schedule_deferred_open_message_smb2: "
1310                         "can't find mid %llu\n",
1311                         (unsigned long long)mid ));
1312                 return false;
1313         }
1314         if (!smb2req->subreq) {
1315                 return false;
1316         }
1317         if (!tevent_req_is_in_progress(smb2req->subreq)) {
1318                 return false;
1319         }
1320         state = tevent_req_data(smb2req->subreq,
1321                         struct smbd_smb2_create_state);
1322         if (!state) {
1323                 return false;
1324         }
1325
1326         /* Ensure we don't have any outstanding timer event. */
1327         TALLOC_FREE(state->te);
1328         /* Ensure we don't have any outstanding immediate event. */
1329         TALLOC_FREE(state->im);
1330
1331         /*
1332          * This is subtle. We must null out the callback
1333          * before rescheduling, else the first call to
1334          * tevent_req_nterror() causes the _receive()
1335          * function to be called, this causing tevent_req_post()
1336          * to crash.
1337          */
1338         tevent_req_set_callback(smb2req->subreq, NULL, NULL);
1339
1340         state->im = tevent_create_immediate(smb2req);
1341         if (!state->im) {
1342                 smbd_server_connection_terminate(smb2req->sconn,
1343                         nt_errstr(NT_STATUS_NO_MEMORY));
1344                 return false;
1345         }
1346
1347         DEBUG(10,("schedule_deferred_open_message_smb2: "
1348                 "re-processing mid %llu\n",
1349                 (unsigned long long)mid ));
1350
1351         tevent_schedule_immediate(state->im,
1352                         smb2req->sconn->ev_ctx,
1353                         smbd_smb2_create_request_dispatch_immediate,
1354                         smb2req);
1355
1356         return true;
1357 }
1358
1359 static bool smbd_smb2_create_cancel(struct tevent_req *req)
1360 {
1361         struct smbd_smb2_request *smb2req = NULL;
1362         struct smbd_smb2_create_state *state = tevent_req_data(req,
1363                                 struct smbd_smb2_create_state);
1364         uint64_t mid;
1365
1366         if (!state) {
1367                 return false;
1368         }
1369
1370         if (!state->smb2req) {
1371                 return false;
1372         }
1373
1374         smb2req = state->smb2req;
1375         mid = get_mid_from_smb2req(smb2req);
1376
1377         if (is_deferred_open_async(state->private_data.data)) {
1378                 /* Can't cancel an async create. */
1379                 return false;
1380         }
1381
1382         remove_deferred_open_message_smb2_internal(smb2req, mid);
1383
1384         tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
1385         tevent_req_nterror(req, NT_STATUS_CANCELLED);
1386         return true;
1387 }
1388
1389 bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
1390                                 struct timeval request_time,
1391                                 struct timeval timeout,
1392                                 struct file_id id,
1393                                 char *private_data,
1394                                 size_t priv_len)
1395 {
1396         struct tevent_req *req = NULL;
1397         struct smbd_smb2_create_state *state = NULL;
1398         struct timeval end_time;
1399
1400         if (!smb2req) {
1401                 return false;
1402         }
1403         req = smb2req->subreq;
1404         if (!req) {
1405                 return false;
1406         }
1407         state = tevent_req_data(req, struct smbd_smb2_create_state);
1408         if (!state) {
1409                 return false;
1410         }
1411         state->id = id;
1412         state->request_time = request_time;
1413         state->private_data = data_blob_talloc(state, private_data,
1414                                                 priv_len);
1415         if (!state->private_data.data) {
1416                 return false;
1417         }
1418
1419         /* Re-schedule us to retry on timer expiry. */
1420         end_time = timeval_sum(&request_time, &timeout);
1421
1422         DEBUG(10,("push_deferred_open_message_smb2: "
1423                 "timeout at %s\n",
1424                 timeval_string(talloc_tos(),
1425                                 &end_time,
1426                                 true) ));
1427
1428         state->open_was_deferred = true;
1429
1430         /* allow this request to be canceled */
1431         tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);
1432
1433         return true;
1434 }