mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
smbd:smb2: implement create replay
Signed-off-by: Michael Adam <obnox@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
parent
03a3aa9815
commit
2fd54b5332
@ -202,16 +202,6 @@
|
||||
^samba3.smb2.setinfo.setinfo
|
||||
^samba3.smb2.session.*reauth5 # some special anonymous checks?
|
||||
^samba3.smb2.compound.interim2 # wrong return code (STATUS_CANCELLED)
|
||||
^samba3.smb2.replay.replay-commands
|
||||
^samba3.smb2.replay.replay-regular
|
||||
^samba3.smb2.replay.replay-dhv2-oplock1
|
||||
^samba3.smb2.replay.replay-dhv2-oplock2
|
||||
^samba3.smb2.replay.replay-dhv2-oplock3
|
||||
^samba3.smb2.replay.replay-dhv2-oplock-lease
|
||||
^samba3.smb2.replay.replay-dhv2-lease1
|
||||
^samba3.smb2.replay.replay-dhv2-lease2
|
||||
^samba3.smb2.replay.replay-dhv2-lease3
|
||||
^samba3.smb2.replay.replay-dhv2-lease-oplock
|
||||
^samba3.smb2.replay.replay3
|
||||
^samba3.smb2.replay.replay4
|
||||
^samba3.smb2.lock.*replay
|
||||
|
@ -475,6 +475,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
struct smb2_create_blob *dh2q = NULL;
|
||||
struct smb2_create_blob *rqls = NULL;
|
||||
struct smbXsrv_open *op = NULL;
|
||||
bool replay_operation = false;
|
||||
|
||||
if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
|
||||
requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
|
||||
@ -779,6 +780,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
const uint8_t *p = dh2q->data.data;
|
||||
uint32_t durable_v2_timeout = 0;
|
||||
DATA_BLOB create_guid_blob;
|
||||
const uint8_t *hdr;
|
||||
uint32_t flags;
|
||||
|
||||
if (dh2q->data.length != 32) {
|
||||
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
||||
@ -823,6 +826,38 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
*/
|
||||
durable_timeout_msec = (60*1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for replay operation.
|
||||
* Only consider it when we have dh2q.
|
||||
* If we do not have a replay operation, verify that
|
||||
* the create_guid is not cached for replay.
|
||||
*/
|
||||
hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
|
||||
flags = IVAL(hdr, SMB2_HDR_FLAGS);
|
||||
replay_operation =
|
||||
!!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION);
|
||||
|
||||
status = smb2srv_open_lookup_replay_cache(
|
||||
smb2req->xconn, create_guid,
|
||||
0 /* now */, &op);
|
||||
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
replay_operation = false;
|
||||
} else if (tevent_req_nterror(req, status)) {
|
||||
DBG_WARNING("smb2srv_open_lookup_replay_cache "
|
||||
"failed: %s\n", nt_errstr(status));
|
||||
return tevent_req_post(req, ev);
|
||||
} else if (!replay_operation) {
|
||||
/*
|
||||
* If a create without replay operation flag
|
||||
* is sent but with a create_guid that is
|
||||
* currently in the replay cache -- fail.
|
||||
*/
|
||||
status = NT_STATUS_DUPLICATE_OBJECTID;
|
||||
(void)tevent_req_nterror(req, status);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
}
|
||||
|
||||
if (dhnc) {
|
||||
@ -918,6 +953,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
DEBUG(10, ("v2 lease key only for SMB3\n"));
|
||||
lease_ptr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replay with a lease is only allowed if the
|
||||
* established open carries a lease with the
|
||||
* same lease key.
|
||||
*/
|
||||
if (replay_operation) {
|
||||
struct smb2_lease *op_ls =
|
||||
&op->compat->lease->lease;
|
||||
int op_oplock = op->compat->oplock_type;
|
||||
|
||||
if (map_samba_oplock_levels_to_smb2(op_oplock)
|
||||
!= SMB2_OPLOCK_LEVEL_LEASE)
|
||||
{
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
(void)tevent_req_nterror(req, status);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
if (!smb2_lease_key_equal(&lease.lease_key,
|
||||
&op_ls->lease_key))
|
||||
{
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
(void)tevent_req_nterror(req, status);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* these are ignored for SMB2 */
|
||||
@ -930,9 +991,16 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
|
||||
/*
|
||||
* For the backend file open procedure, there are
|
||||
* two possible modes: durable_reconnect or not.
|
||||
* three possible modes: replay operation (in which case
|
||||
* there is nothing else to do), durable_reconnect or
|
||||
* new open.
|
||||
*/
|
||||
if (do_durable_reconnect) {
|
||||
if (replay_operation) {
|
||||
result = op->compat;
|
||||
result->op = op;
|
||||
update_open = false;
|
||||
info = op->create_action;
|
||||
} else if (do_durable_reconnect) {
|
||||
DATA_BLOB new_cookie = data_blob_null;
|
||||
NTTIME now = timeval_to_nttime(&smb2req->request_time);
|
||||
|
||||
@ -1142,7 +1210,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (durable_requested &&
|
||||
if (!replay_operation && durable_requested &&
|
||||
(fsp_lease_type(result) & SMB2_LEASE_HANDLE))
|
||||
{
|
||||
status = SMB_VFS_DURABLE_COOKIE(result,
|
||||
@ -1152,7 +1220,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
op->global->backend_cookie = data_blob_null;
|
||||
}
|
||||
}
|
||||
if (op->global->backend_cookie.length > 0) {
|
||||
if (!replay_operation && op->global->backend_cookie.length > 0)
|
||||
{
|
||||
update_open = true;
|
||||
|
||||
op->global->durable = true;
|
||||
@ -1189,7 +1258,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (dh2q && op->global->durable) {
|
||||
if (dh2q && op->global->durable &&
|
||||
/*
|
||||
* For replay operations, we return the dh2q blob
|
||||
* in the case of oplocks not based on the state of
|
||||
* the open, but on whether it could have been granted
|
||||
* for the request data. In the case of leases instead,
|
||||
* the state of the open is used...
|
||||
*/
|
||||
(!replay_operation ||
|
||||
in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
|
||||
in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
|
||||
{
|
||||
uint8_t p[8] = { 0, };
|
||||
DATA_BLOB blob = data_blob_const(p, sizeof(p));
|
||||
uint32_t durable_v2_response_flags = 0;
|
||||
@ -1261,7 +1341,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
|
||||
smb2req->compat_chain_fsp = smb1req->chain_fsp;
|
||||
|
||||
if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
|
||||
if (replay_operation) {
|
||||
state->out_oplock_level = in_oplock_level;
|
||||
} else if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
|
||||
state->out_oplock_level = in_oplock_level;
|
||||
} else {
|
||||
state->out_oplock_level = map_samba_oplock_levels_to_smb2(result->oplock_type);
|
||||
@ -1273,6 +1355,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
|
||||
} else {
|
||||
state->out_create_action = info;
|
||||
}
|
||||
result->op->create_action = state->out_create_action;
|
||||
state->out_file_attributes = dos_mode(result->conn,
|
||||
result->fsp_name);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user