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