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