} transport;
struct {
+ bool force_unacked_timeout;
uint64_t unacked_bytes;
uint32_t rto_usecs;
struct tevent_req *checker_subreq;
}
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;
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.
}
}
+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,
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);
*_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;
}
} 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