diff options
Diffstat (limited to 'source3/smbd/smb2_lock.c')
-rw-r--r-- | source3/smbd/smb2_lock.c | 180 |
1 files changed, 169 insertions, 11 deletions
diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 3ffe053481..121b4eb24d 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -31,6 +31,7 @@ struct smbd_smb2_lock_element { static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, + uint32_t in_smbpid, uint64_t in_file_id_volatile, uint16_t in_lock_count, struct smbd_smb2_lock_element *in_locks); @@ -41,15 +42,17 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) { const uint8_t *inhdr; const uint8_t *inbody; - int i = req->current_idx; + const int i = req->current_idx; size_t expected_body_size = 0x30; size_t body_size; + uint32_t in_smbpid; uint16_t in_lock_count; uint64_t in_file_id_persistent; uint64_t in_file_id_volatile; struct smbd_smb2_lock_element *in_locks; struct tevent_req *subreq; const uint8_t *lock_buffer; + uint16_t l; inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { @@ -63,8 +66,10 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); } + in_smbpid = IVAL(inhdr, SMB2_HDR_PID); + in_lock_count = CVAL(inbody, 0x02); - /* 0x04 4 bytes reserved */ + /* 0x04 - 4 bytes reserved */ in_file_id_persistent = BVAL(inbody, 0x08); in_file_id_volatile = BVAL(inbody, 0x10); @@ -88,19 +93,21 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); } - i = 0; + l = 0; lock_buffer = inbody + 0x18; - in_locks[i].offset = BVAL(lock_buffer, 0x00); - in_locks[i].length = BVAL(lock_buffer, 0x08); - in_locks[i].flags = BVAL(lock_buffer, 0x10); + in_locks[l].offset = BVAL(lock_buffer, 0x00); + in_locks[l].length = BVAL(lock_buffer, 0x08); + in_locks[l].flags = IVAL(lock_buffer, 0x10); + /* 0x14 - 4 reserved bytes */ lock_buffer = (const uint8_t *)req->in.vector[i+2].iov_base; - for (i=1; i < in_lock_count; i++) { - in_locks[i].offset = BVAL(lock_buffer, 0x00); - in_locks[i].length = BVAL(lock_buffer, 0x08); - in_locks[i].flags = BVAL(lock_buffer, 0x10); + for (l=1; l < in_lock_count; l++) { + in_locks[l].offset = BVAL(lock_buffer, 0x00); + in_locks[l].length = BVAL(lock_buffer, 0x08); + in_locks[l].flags = IVAL(lock_buffer, 0x10); + /* 0x14 - 4 reserved bytes */ lock_buffer += 0x18; } @@ -108,6 +115,7 @@ NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req) subreq = smbd_smb2_lock_send(req, req->conn->smb2.event_ctx, req, + in_smbpid, in_file_id_volatile, in_lock_count, in_locks); @@ -172,6 +180,7 @@ struct smbd_smb2_lock_state { static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct smbd_smb2_request *smb2req, + uint32_t in_smbpid, uint64_t in_file_id_volatile, uint16_t in_lock_count, struct smbd_smb2_lock_element *in_locks) @@ -181,6 +190,12 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, struct smb_request *smbreq; connection_struct *conn = smb2req->tcon->compat_conn; files_struct *fsp; + int32_t timeout = -1; + bool isunlock = false; + uint16_t i; + struct smbd_lock_element *locks; + NTSTATUS status; + bool async = false; req = tevent_req_create(mem_ctx, &state, struct smbd_smb2_lock_state); @@ -211,7 +226,150 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED); + locks = talloc_array(state, struct smbd_lock_element, in_lock_count); + if (locks == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); + } + + switch (in_locks[0].flags) { + case SMB2_LOCK_FLAG_SHARED: + case SMB2_LOCK_FLAG_EXCLUSIVE: + if (in_lock_count > 1) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + timeout = -1; + break; + + case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + timeout = 0; + break; + + case SMB2_LOCK_FLAG_UNLOCK: + /* only the first lock gives the UNLOCK bit - see + MS-SMB2 3.3.5.14 */ + isunlock = true; + timeout = 0; + break; + + default: + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + for (i=0; i<in_lock_count; i++) { + uint64_t max_count; + bool invalid = false; + + switch (in_locks[i].flags) { + case SMB2_LOCK_FLAG_SHARED: + case SMB2_LOCK_FLAG_EXCLUSIVE: + if (i > 0) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + if (isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: + if (isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + case SMB2_LOCK_FLAG_UNLOCK: + if (!isunlock) { + tevent_req_nterror(req, + NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + break; + + default: + if (isunlock) { + /* + * is the first element was a UNLOCK + * we need to deferr the error response + * to the backend, because we need to process + * all unlock elements before + */ + invalid = true; + break; + } + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); + } + + locks[i].smbpid = in_smbpid; + locks[i].offset = in_locks[i].offset; + locks[i].count = in_locks[i].length; + + if (in_locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE) { + locks[i].brltype = WRITE_LOCK; + } else if (in_locks[i].flags & SMB2_LOCK_FLAG_SHARED) { + locks[i].brltype = READ_LOCK; + } else if (invalid) { + /* + * this is an invalid UNLOCK element + * and the backend needs to test for + * brltype != UNLOCK_LOCK and return + * NT_STATUS_INVALID_PARAMER + */ + locks[i].brltype = READ_LOCK; + } else { + locks[i].brltype = UNLOCK_LOCK; + } + + max_count = UINT64_MAX - locks[i].offset; + if (locks[i].count > max_count) { + tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_RANGE); + return tevent_req_post(req, ev); + } + } + + if (isunlock) { + status = smbd_do_locking(smbreq, fsp, + 0, + timeout, + in_lock_count, + locks, + 0, + NULL, + &async); + } else { + status = smbd_do_locking(smbreq, fsp, + 0, + timeout, + 0, + NULL, + in_lock_count, + locks, + &async); + } + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { + status = NT_STATUS_LOCK_NOT_GRANTED; + } + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } + + if (async) { + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return tevent_req_post(req, ev); + } + + tevent_req_done(req); return tevent_req_post(req, ev); } |