mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
s3:smbd: implement FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT
This will be used by smbtorture in order to simulate channel failures without relying on iptables. 'smbd:FSCTL_SMBTORTURE = yes' is required in order to active this. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Günther Deschner <gd@samba.org>
This commit is contained in:
parent
88b0da1062
commit
bd1285d40d
@ -375,6 +375,7 @@ struct smbXsrv_connection {
|
||||
} transport;
|
||||
|
||||
struct {
|
||||
bool force_unacked_timeout;
|
||||
uint64_t unacked_bytes;
|
||||
uint32_t rto_usecs;
|
||||
struct tevent_req *checker_subreq;
|
||||
|
@ -41,9 +41,13 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
|
||||
}
|
||||
|
||||
smbreq->request_time = req->request_time;
|
||||
smbreq->vuid = req->session->global->session_wire_id;
|
||||
smbreq->tid = req->tcon->compat->cnum;
|
||||
smbreq->conn = req->tcon->compat;
|
||||
if (req->session != NULL) {
|
||||
smbreq->vuid = req->session->global->session_wire_id;
|
||||
}
|
||||
if (req->tcon != NULL) {
|
||||
smbreq->tid = req->tcon->compat->cnum;
|
||||
smbreq->conn = req->tcon->compat;
|
||||
}
|
||||
smbreq->sconn = req->sconn;
|
||||
smbreq->xconn = req->xconn;
|
||||
smbreq->session = req->session;
|
||||
|
@ -194,6 +194,7 @@ NTSTATUS smbd_smb2_request_process_ioctl(struct smbd_smb2_request *req)
|
||||
case FSCTL_VALIDATE_NEGOTIATE_INFO_224:
|
||||
case FSCTL_VALIDATE_NEGOTIATE_INFO:
|
||||
case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
|
||||
case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
|
||||
/*
|
||||
* Some SMB2 specific CtlCodes like FSCTL_DFS_GET_REFERRALS or
|
||||
* FSCTL_PIPE_WAIT does not take a file handle.
|
||||
@ -366,6 +367,45 @@ static void smbd_smb2_request_ioctl_done(struct tevent_req *subreq)
|
||||
}
|
||||
}
|
||||
|
||||
static struct tevent_req *smb2_ioctl_smbtorture(uint32_t ctl_code,
|
||||
struct tevent_context *ev,
|
||||
struct tevent_req *req,
|
||||
struct smbd_smb2_ioctl_state *state)
|
||||
{
|
||||
NTSTATUS status;
|
||||
bool ok;
|
||||
|
||||
ok = lp_parm_bool(-1, "smbd", "FSCTL_SMBTORTURE", false);
|
||||
if (!ok) {
|
||||
goto not_supported;
|
||||
}
|
||||
|
||||
switch (ctl_code) {
|
||||
case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
|
||||
if (state->in_input.length != 0) {
|
||||
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->smb2req->xconn->ack.force_unacked_timeout = true;
|
||||
tevent_req_done(req);
|
||||
return tevent_req_post(req, ev);
|
||||
|
||||
default:
|
||||
goto not_supported;
|
||||
}
|
||||
|
||||
not_supported:
|
||||
if (IS_IPC(state->smbreq->conn)) {
|
||||
status = NT_STATUS_FS_DRIVER_REQUIRED;
|
||||
} else {
|
||||
status = NT_STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
tevent_req_nterror(req, status);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct smbd_smb2_request *smb2req,
|
||||
@ -415,6 +455,9 @@ static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx,
|
||||
case FSCTL_NETWORK_FILESYSTEM:
|
||||
return smb2_ioctl_network_fs(in_ctl_code, ev, req, state);
|
||||
break;
|
||||
case FSCTL_SMBTORTURE:
|
||||
return smb2_ioctl_smbtorture(in_ctl_code, ev, req, state);
|
||||
break;
|
||||
default:
|
||||
if (IS_IPC(smbreq->conn)) {
|
||||
tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED);
|
||||
|
@ -1201,6 +1201,17 @@ static NTSTATUS smbXsrv_connection_get_acked_bytes(struct smbXsrv_connection *xc
|
||||
|
||||
*_acked_bytes = 0;
|
||||
|
||||
if (xconn->ack.force_unacked_timeout) {
|
||||
/*
|
||||
* Smbtorture tries to test channel failures...
|
||||
* Just pretend nothing was acked...
|
||||
*/
|
||||
DBG_INFO("Simulating channel failure: "
|
||||
"xconn->ack.unacked_bytes[%llu]\n",
|
||||
(unsigned long long)xconn->ack.unacked_bytes);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef __IOCTL_SEND_QUEUE_SIZE_OPCODE
|
||||
{
|
||||
int value = 0;
|
||||
@ -3045,6 +3056,42 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
|
||||
}
|
||||
} else if (opcode == SMB2_OP_CANCEL) {
|
||||
/* Cancel requests are allowed to skip the signing */
|
||||
} else if (opcode == SMB2_OP_IOCTL) {
|
||||
/*
|
||||
* Some special IOCTL calls don't require
|
||||
* file, tcon nor session.
|
||||
*
|
||||
* They typically don't do any real action
|
||||
* on behalf of the client.
|
||||
*
|
||||
* They are mainly used to alter the behavior
|
||||
* of the connection for testing. So we can
|
||||
* run as root and skip all file, tcon and session
|
||||
* checks below.
|
||||
*/
|
||||
static const struct smbd_smb2_dispatch_table _root_ioctl_call = {
|
||||
_OP(SMB2_OP_IOCTL),
|
||||
.as_root = true,
|
||||
};
|
||||
const uint8_t *body = SMBD_SMB2_IN_BODY_PTR(req);
|
||||
size_t body_size = SMBD_SMB2_IN_BODY_LEN(req);
|
||||
uint32_t in_ctl_code;
|
||||
size_t needed = 4;
|
||||
|
||||
if (needed > body_size) {
|
||||
return smbd_smb2_request_error(req,
|
||||
NT_STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
in_ctl_code = IVAL(body, 0x04);
|
||||
/*
|
||||
* Only add trusted IOCTL codes here!
|
||||
*/
|
||||
switch (in_ctl_code) {
|
||||
case FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT:
|
||||
call = &_root_ioctl_call;
|
||||
break;
|
||||
}
|
||||
} else if (signing_required) {
|
||||
/*
|
||||
* If signing is required we try to sign
|
||||
|
Loading…
x
Reference in New Issue
Block a user