smbd:smb2_create: fix return code for durable handle create blob combinations
[mat/samba.git] / source3 / smbd / smb2_create.c
index c239ccb1432b2c07841feeefdf5bcd01888d93ca..79ba14674b9fe8141f1f36e9ca5941cc4618919f 100644 (file)
@@ -421,6 +421,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
        int requested_oplock_level;
        struct smb2_create_blob *dhnc = NULL;
        struct smb2_create_blob *dh2c = NULL;
+       struct smb2_create_blob *dhnq = NULL;
+       struct smb2_create_blob *dh2q = NULL;
        struct smbXsrv_open *op = NULL;
 
        ZERO_STRUCT(out_context_blobs);
@@ -459,8 +461,22 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        in_name ));
        }
 
+       dhnq = smb2_create_blob_find(&in_context_blobs,
+                                    SMB2_CREATE_TAG_DHNQ);
        dhnc = smb2_create_blob_find(&in_context_blobs,
                                     SMB2_CREATE_TAG_DHNC);
+       dh2q = smb2_create_blob_find(&in_context_blobs,
+                                    SMB2_CREATE_TAG_DH2Q);
+       dh2c = smb2_create_blob_find(&in_context_blobs,
+                                    SMB2_CREATE_TAG_DH2C);
+
+       if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
+           (dh2q && dh2c))
+       {
+               /* not both are allowed at the same time */
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return tevent_req_post(req, ev);
+       }
 
        if (dhnc) {
                if (dhnc->data.length != 16) {
@@ -470,14 +486,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                if (in_context_blobs.num_blobs != 1) {
                        /*
                         * DHNC should be the only one.
+                        * TODO: This is only true for the oplock case!
+                        * For leases, lease request is required additionally!
                         */
                        tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
                        return tevent_req_post(req, ev);
                }
        }
 
-       dh2c = smb2_create_blob_find(&in_context_blobs,
-                                    SMB2_CREATE_TAG_DH2C);
        if (dh2c) {
                if (dh2c->data.length != 36) {
                        tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -486,6 +502,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                if (in_context_blobs.num_blobs != 1) {
                        /*
                         * DH2C should be the only one.
+                        * TODO: This is only true for the oplock case!
+                        * For leases, lease request is required additionally!
                         */
                        tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
                        return tevent_req_post(req, ev);
@@ -541,17 +559,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                NTTIME max_access_time = 0;
                struct smb2_create_blob *secd = NULL;
                struct security_descriptor *sec_desc = NULL;
-               struct smb2_create_blob *dhnq = NULL;
                struct smb2_create_blob *alsi = NULL;
                uint64_t allocation_size = 0;
                struct smb2_create_blob *twrp = NULL;
                struct smb2_create_blob *qfid = NULL;
-               struct GUID create_guid = GUID_zero();
+               struct GUID _create_guid = GUID_zero();
+               struct GUID *create_guid = NULL;
                bool update_open = false;
                bool durable_requested = false;
                uint32_t durable_timeout_msec = 0;
                bool do_durable_reconnect = false;
-               struct smb2_create_blob *dh2q = NULL;
+               uint64_t persistent_id = 0;
 
                exta = smb2_create_blob_find(&in_context_blobs,
                                             SMB2_CREATE_TAG_EXTA);
@@ -559,16 +577,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                             SMB2_CREATE_TAG_MXAC);
                secd = smb2_create_blob_find(&in_context_blobs,
                                             SMB2_CREATE_TAG_SECD);
-               dhnq = smb2_create_blob_find(&in_context_blobs,
-                                            SMB2_CREATE_TAG_DHNQ);
                alsi = smb2_create_blob_find(&in_context_blobs,
                                             SMB2_CREATE_TAG_ALSI);
                twrp = smb2_create_blob_find(&in_context_blobs,
                                             SMB2_CREATE_TAG_TWRP);
                qfid = smb2_create_blob_find(&in_context_blobs,
                                             SMB2_CREATE_TAG_QFID);
-               dh2q = smb2_create_blob_find(&in_context_blobs,
-                                            SMB2_CREATE_TAG_DH2Q);
 
                fname = talloc_strdup(state, in_name);
                if (tevent_req_nomem(fname, req)) {
@@ -583,6 +597,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
                                return tevent_req_post(req, ev);
                        }
+
+                       if (ea_list_has_invalid_name(ea_list)) {
+                               tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
+                               return tevent_req_post(req, ev);
+                       }
                }
 
                if (mxac) {
@@ -658,10 +677,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        create_guid_blob = data_blob_const(p + 16, 16);
 
                        status = GUID_from_ndr_blob(&create_guid_blob,
-                                                   &create_guid);
+                                                   &_create_guid);
                        if (tevent_req_nterror(req, status)) {
                                return tevent_req_post(req, ev);
                        }
+                       create_guid = &_create_guid;
                        /*
                         * we need to store the create_guid later
                         */
@@ -683,74 +703,24 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                }
 
                if (dhnc) {
-                       NTTIME now = timeval_to_nttime(&smb2req->request_time);
-                       uint64_t persistent_id;
-
                        persistent_id = BVAL(dhnc->data.data, 0);
 
-                       status = smb2srv_open_recreate(smb2req->sconn->conn,
-                                               smb1req->conn->session_info,
-                                               persistent_id, create_guid,
-                                               now, &op);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(3, ("smbd_smb2_create_send: "
-                                         "smb2srv_open_recreate v1 failed: %s\n",
-                                         nt_errstr(status)));
-                               tevent_req_nterror(req, status);
-                               return tevent_req_post(req, ev);
-                       }
-
-                       DEBUG(10, ("smb2_create_send: DHNC: %s recreate the "
-                                  "smb2srv_open struct for a durable handle.\n",
-                                  op->global->durable ? "did" : "could not"));
-
-                       if (!op->global->durable) {
-                               talloc_free(op);
-                               tevent_req_nterror(req,
-                                       NT_STATUS_OBJECT_NAME_NOT_FOUND);
-                               return tevent_req_post(req, ev);
-                       }
-
                        do_durable_reconnect = true;
                }
 
                if (dh2c) {
                        const uint8_t *p = dh2c->data.data;
-                       NTTIME now = timeval_to_nttime(&smb2req->request_time);
-                       uint64_t persistent_id;
                        DATA_BLOB create_guid_blob;
 
                        persistent_id = BVAL(p, 0);
                        create_guid_blob = data_blob_const(p + 16, 16);
 
                        status = GUID_from_ndr_blob(&create_guid_blob,
-                                                   &create_guid);
+                                                   &_create_guid);
                        if (tevent_req_nterror(req, status)) {
                                return tevent_req_post(req, ev);
                        }
-
-                       status = smb2srv_open_recreate(smb2req->sconn->conn,
-                                                      smb1req->conn->session_info,
-                                                      persistent_id, create_guid,
-                                                      now, &op);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(3, ("smbd_smb2_create_send: "
-                                         "smb2srv_open_recreate v2 failed: %s\n",
-                                         nt_errstr(status)));
-                               tevent_req_nterror(req, status);
-                               return tevent_req_post(req, ev);
-                       }
-
-                       DEBUG(10, ("smb2_create_send: DH2C: %s recreate the "
-                                  "smb2srv_open struct for a durable handle.\n",
-                                  op->global->durable ? "did" : "could not"));
-
-                       if (!op->global->durable) {
-                               talloc_free(op);
-                               tevent_req_nterror(req,
-                                       NT_STATUS_OBJECT_NAME_NOT_FOUND);
-                               return tevent_req_post(req, ev);
-                       }
+                       create_guid = &_create_guid;
 
                        do_durable_reconnect = true;
                }
@@ -813,12 +783,37 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                 */
                if (do_durable_reconnect) {
                        DATA_BLOB new_cookie = data_blob_null;
+                       NTTIME now = timeval_to_nttime(&smb2req->request_time);
+
+                       status = smb2srv_open_recreate(smb2req->sconn->conn,
+                                               smb1req->conn->session_info,
+                                               persistent_id, create_guid,
+                                               now, &op);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(3, ("smbd_smb2_create_send: "
+                                         "smb2srv_open_recreate failed: %s\n",
+                                         nt_errstr(status)));
+                               tevent_req_nterror(req, status);
+                               return tevent_req_post(req, ev);
+                       }
+
+                       DEBUG(10, ("smb2_create_send: %s to recreate the "
+                                  "smb2srv_open struct for a durable handle.\n",
+                                  op->global->durable ? "succeded" : "failed"));
+
+                       if (!op->global->durable) {
+                               talloc_free(op);
+                               tevent_req_nterror(req,
+                                       NT_STATUS_OBJECT_NAME_NOT_FOUND);
+                               return tevent_req_post(req, ev);
+                       }
 
                        status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
                                                smb1req,
-                                               op,
+                                               op, /* smbXsrv_open input */
                                                op->global->backend_cookie,
-                                               op, &result, &new_cookie);
+                                               op, /* TALLOC_CTX */
+                                               &result, &new_cookie);
                        if (!NT_STATUS_IS_OK(status)) {
                                NTSTATUS return_status;
 
@@ -839,11 +834,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        op->status = NT_STATUS_OK;
                        op->global->disconnect_time = 0;
 
-                       status = smbXsrv_open_update(op);
-                       if (!NT_STATUS_IS_OK(status)) {
-                               tevent_req_nterror(req, status);
-                               return tevent_req_post(req, ev);
-                       }
+                       /* save the timout for later update */
+                       durable_timeout_msec = op->global->durable_timeout_msec;
+
+                       update_open = true;
 
                        info = FILE_WAS_OPENED;
                } else {
@@ -867,7 +861,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                                  smb1req->conn,
                                                  smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
                                                  fname,
-                                                 0,    /* unix_convert flags */
+                                                 (in_create_disposition == FILE_CREATE) ?
+                                                 UCF_CREATING_FILE : 0,
                                                  NULL, /* ppath_contains_wcards */
                                                  &smb_fname);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -956,7 +951,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                }
 
                if (update_open) {
-                       op->global->create_guid = create_guid;
+                       op->global->create_guid = _create_guid;
 
                        status = smbXsrv_open_update(op);
                        DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
@@ -1339,55 +1334,6 @@ bool schedule_deferred_open_message_smb2(
        return true;
 }
 
-/*********************************************************
- Re-process this call.
-*********************************************************/
-
-static void smb2_deferred_open_timer(struct tevent_context *ev,
-                                       struct tevent_timer *te,
-                                       struct timeval _tval,
-                                       void *private_data)
-{
-       NTSTATUS status;
-       struct smbd_smb2_create_state *state = NULL;
-       struct smbd_smb2_request *smb2req = talloc_get_type(private_data,
-                                               struct smbd_smb2_request);
-
-       DEBUG(10,("smb2_deferred_open_timer: [idx=%d], %s\n",
-               smb2req->current_idx,
-               tevent_req_default_print(smb2req->subreq, talloc_tos()) ));
-
-       state = tevent_req_data(smb2req->subreq,
-                       struct smbd_smb2_create_state);
-       if (!state) {
-               return;
-       }
-       /*
-        * Null this out, don't talloc_free. It will
-        * be talloc_free'd by the tevent library when
-        * this returns.
-        */
-       state->te = NULL;
-       /* Ensure we don't have any outstanding immediate event. */
-       TALLOC_FREE(state->im);
-
-       /*
-        * This is subtle. We must null out the callback
-        * before rescheduling, else the first call to
-        * tevent_req_nterror() causes the _receive()
-        * function to be called, this causing tevent_req_post()
-        * to crash.
-        */
-       tevent_req_set_callback(smb2req->subreq, NULL, NULL);
-
-       status = smbd_smb2_request_dispatch(smb2req);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               smbd_server_connection_terminate(smb2req->sconn,
-                               nt_errstr(status));
-       }
-}
-
 static bool smbd_smb2_create_cancel(struct tevent_req *req)
 {
        struct smbd_smb2_request *smb2req = NULL;
@@ -1411,8 +1357,6 @@ static bool smbd_smb2_create_cancel(struct tevent_req *req)
                return false;
        }
 
-       remove_deferred_open_entry(state->id, mid,
-                                  messaging_server_id(smb2req->sconn->msg_ctx));
        remove_deferred_open_message_smb2_internal(smb2req, mid);
 
        tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
@@ -1460,14 +1404,6 @@ bool push_deferred_open_message_smb2(struct smbd_smb2_request *smb2req,
                                true) ));
 
        state->open_was_deferred = true;
-       state->te = tevent_add_timer(smb2req->sconn->ev_ctx,
-                               state,
-                               end_time,
-                               smb2_deferred_open_timer,
-                               smb2req);
-        if (!state->te) {
-               return false;
-       }
 
        /* allow this request to be canceled */
        tevent_req_set_cancel_fn(req, smbd_smb2_create_cancel);