s3:smbd: the SMB2-COMPOUND test shows that the related vs. unrelated flags isn't...
[nivanova/samba-autobuild/.git] / source3 / smbd / smb2_server.c
index fa91e29b5ed7c4f6bd81efd4f876aacb9ce69715..c889555a1cbaf5c37196c4ea0f8c6da8c657d84a 100644 (file)
@@ -237,6 +237,12 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
                                compound_related = true;
                        }
                } else if (idx > 4) {
+#if 0
+                       /*
+                        * It seems the this tests are wrong
+                        * see the SMB2-COMPOUND test
+                        */
+
                        /*
                         * all other requests should match the 2nd one
                         */
@@ -253,6 +259,7 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
                                        return NT_STATUS_OK;
                                }
                        }
+#endif
                }
        }
 
@@ -277,6 +284,7 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
 
        for (idx=1; idx < count; idx += 3) {
                const uint8_t *inhdr = NULL;
+               uint32_t in_flags;
                uint8_t *outhdr = NULL;
                uint8_t *outbody = NULL;
                uint32_t next_command_ofs = 0;
@@ -288,6 +296,7 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
                }
 
                inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
+               in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
 
                outhdr = talloc_array(vector, uint8_t,
                                      SMB2_HDR_BODY + 8);
@@ -316,7 +325,8 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
                      SVAL(inhdr, SMB2_HDR_OPCODE));
                /* Make up a number for now... JRA. FIXME ! FIXME !*/
                SSVAL(outhdr, SMB2_HDR_CREDIT,          20);
-               SIVAL(outhdr, SMB2_HDR_FLAGS,           SMB2_HDR_FLAG_REDIRECT);
+               SIVAL(outhdr, SMB2_HDR_FLAGS,
+                     IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
                SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,    next_command_ofs);
                SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
                      BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
@@ -396,14 +406,19 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
        }
 
-       /*
-        * This check is mostly for giving the correct error code
-        * for compounded requests.
-        *
-        * TODO: we may need to move this after the session and tcon checks.
-        */
-       if (!NT_STATUS_IS_OK(req->next_status)) {
-               return smbd_smb2_request_error(req, req->next_status);
+       if (flags & SMB2_HDR_FLAG_CHAINED) {
+               /*
+                * This check is mostly for giving the correct error code
+                * for compounded requests.
+                *
+                * TODO: we may need to move this after the session
+                *       and tcon checks.
+                */
+               if (!NT_STATUS_IS_OK(req->next_status)) {
+                       return smbd_smb2_request_error(req, req->next_status);
+               }
+       } else {
+               req->compat_chain_fsp = NULL;
        }
 
        switch (opcode) {
@@ -751,9 +766,54 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
                next_command_ofs += req->out.vector[i+2].iov_len;
        }
 
-       /* TODO: we need to add padding ... */
        if ((next_command_ofs % 8) != 0) {
-               return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
+               size_t pad_size = 8 - (next_command_ofs % 8);
+               if (req->out.vector[i+2].iov_len == 0) {
+                       /*
+                        * if the dyn buffer is empty
+                        * we can use it to add padding
+                        */
+                       uint8_t *pad;
+
+                       pad = talloc_zero_array(req->out.vector,
+                                               uint8_t, pad_size);
+                       if (pad == NULL) {
+                               return smbd_smb2_request_error(req,
+                                               NT_STATUS_NO_MEMORY);
+                       }
+
+                       req->out.vector[i+2].iov_base = (void *)pad;
+                       req->out.vector[i+2].iov_len = pad_size;
+               } else {
+                       /*
+                        * For now we copy the dynamic buffer
+                        * and add the padding to the new buffer
+                        */
+                       size_t old_size;
+                       uint8_t *old_dyn;
+                       size_t new_size;
+                       uint8_t *new_dyn;
+
+                       old_size = req->out.vector[i+2].iov_len;
+                       old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
+
+                       new_size = old_size + pad_size;
+                       new_dyn = talloc_array(req->out.vector,
+                                              uint8_t, new_size);
+                       if (new_dyn == NULL) {
+                               return smbd_smb2_request_error(req,
+                                               NT_STATUS_NO_MEMORY);
+                       }
+
+                       memcpy(new_dyn, old_dyn, old_size);
+                       memset(new_dyn + old_size, 0, pad_size);
+
+                       req->out.vector[i+2].iov_base = (void *)new_dyn;
+                       req->out.vector[i+2].iov_len = new_size;
+
+                       TALLOC_FREE(old_dyn);
+               }
+               next_command_ofs += pad_size;
        }
 
        SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);