summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/smb_server/smb2/fileio.c5
-rw-r--r--source4/smb_server/smb2/receive.c103
-rw-r--r--source4/smb_server/smb2/smb2_server.h11
-rw-r--r--source4/smb_server/smb_server.h17
4 files changed, 125 insertions, 11 deletions
diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c
index 948c53d9e6..66e3f61ee2 100644
--- a/source4/smb_server/smb2/fileio.c
+++ b/source4/smb_server/smb2/fileio.c
@@ -286,11 +286,6 @@ void smb2srv_ioctl_recv(struct smb2srv_request *req)
SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_ioctl(req->ntvfs, io));
}
-void smb2srv_cancel_recv(struct smb2srv_request *req)
-{
- smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED);
-}
-
static void smb2srv_notify_send(struct ntvfs_request *ntvfs)
{
struct smb2srv_request *req;
diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c
index 0f8eb101cf..3d6daa51b6 100644
--- a/source4/smb_server/smb2/receive.c
+++ b/source4/smb_server/smb2/receive.c
@@ -28,7 +28,21 @@
#include "smb_server/smb2/smb2_server.h"
#include "smbd/service_stream.h"
#include "lib/stream/packet.h"
+#include "ntvfs/ntvfs.h"
+static int smb2srv_request_destructor(struct smb2srv_request *req)
+{
+ DLIST_REMOVE(req->smb_conn->requests2.list, req);
+ if (req->pending_id) {
+ idr_remove(req->smb_conn->requests2.idtree_req, req->pending_id);
+ }
+ return 0;
+}
+
+static int smb2srv_request_deny_destructor(struct smb2srv_request *req)
+{
+ return -1;
+}
static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
{
@@ -39,12 +53,24 @@ static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *sm
req->smb_conn = smb_conn;
+ talloc_set_destructor(req, smb2srv_request_destructor);
+
return req;
}
NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
BOOL body_dynamic_present, uint32_t body_dynamic_size)
{
+ uint32_t flags = 0x00000001;
+ uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
+ uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
+
+ if (req->pending_id) {
+ flags |= 0x00000002;
+ pid = req->pending_id;
+ tid = 0;
+ }
+
if (body_dynamic_present) {
if (body_dynamic_size == 0) {
body_dynamic_size = 1;
@@ -71,11 +97,11 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si
SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0x0001);
- SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0x00000001);
+ SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
- SIVAL(req->out.hdr, SMB2_HDR_PID, IVAL(req->in.hdr, SMB2_HDR_PID));
- SIVAL(req->out.hdr, SMB2_HDR_TID, IVAL(req->in.hdr, SMB2_HDR_TID));
+ SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
+ SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
@@ -216,8 +242,6 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
smb2srv_ioctl_recv(req);
return NT_STATUS_OK;
case SMB2_OP_CANCEL:
- if (!req->session) goto nosession;
- if (!req->tcon) goto notcon;
smb2srv_cancel_recv(req);
return NT_STATUS_OK;
case SMB2_OP_KEEPALIVE:
@@ -329,6 +353,72 @@ NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob)
return smb2srv_reply(req);
}
+static NTSTATUS smb2srv_init_pending(struct smbsrv_connection *smb_conn)
+{
+ smb_conn->requests2.idtree_req = idr_init(smb_conn);
+ NT_STATUS_HAVE_NO_MEMORY(smb_conn->requests2.idtree_req);
+ smb_conn->requests2.idtree_limit = 0x00FFFFFF & (UINT32_MAX - 1);
+ smb_conn->requests2.list = NULL;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req)
+{
+ int id;
+
+ if (req->pending_id) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req,
+ 1, req->smb_conn->requests2.idtree_limit);
+ if (id == -1) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
+ req->pending_id = id;
+
+ talloc_set_destructor(req, smb2srv_request_deny_destructor);
+ smb2srv_send_error(req, STATUS_PENDING);
+ talloc_set_destructor(req, smb2srv_request_destructor);
+
+ return NT_STATUS_OK;
+}
+
+void smb2srv_cancel_recv(struct smb2srv_request *req)
+{
+ uint32_t pending_id;
+ uint32_t flags;
+ void *p;
+ struct smb2srv_request *r;
+
+ if (!req->session) goto done;
+
+ flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
+ pending_id = IVAL(req->in.hdr, SMB2_HDR_PID);
+
+ if (!(flags & 0x00000002)) {
+ /* TODO: what to do here? */
+ goto done;
+ }
+
+ p = idr_find(req->smb_conn->requests2.idtree_req, pending_id);
+ if (!p) goto done;
+
+ r = talloc_get_type(p, struct smb2srv_request);
+ if (!r) goto done;
+
+ if (!r->ntvfs) goto done;
+
+ ntvfs_cancel(r->ntvfs);
+
+done:
+ /* we never generate a reply for a SMB2 Cancel */
+ talloc_free(req);
+}
+
/*
* init the SMB2 protocol related stuff
*/
@@ -351,6 +441,9 @@ NTSTATUS smbsrv_init_smb2_connection(struct smbsrv_connection *smb_conn)
status = smbsrv_init_sessions(smb_conn, UINT64_MAX);
NT_STATUS_NOT_OK_RETURN(status);
+ status = smb2srv_init_pending(smb_conn);
+ NT_STATUS_NOT_OK_RETURN(status);
+
return NT_STATUS_OK;
}
diff --git a/source4/smb_server/smb2/smb2_server.h b/source4/smb_server/smb2/smb2_server.h
index 838abdf4d6..b58bf5511a 100644
--- a/source4/smb_server/smb2/smb2_server.h
+++ b/source4/smb_server/smb2/smb2_server.h
@@ -53,6 +53,9 @@ struct smb2srv_request {
/* for matching request and reply */
uint64_t seqnum;
+ /* the id that can be used to cancel the request */
+ uint32_t pending_id;
+
struct smb2_request_buffer in;
struct smb2_request_buffer out;
};
@@ -127,7 +130,13 @@ struct smbsrv_request;
*/
#define SMB2SRV_CALL_NTVFS_BACKEND(cmd) do { \
req->ntvfs->async_states->status = cmd; \
- if (!(req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
+ if (req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
+ NTSTATUS _status; \
+ _status = smb2srv_queue_pending(req); \
+ if (!NT_STATUS_IS_OK(_status)) { \
+ ntvfs_cancel(req->ntvfs); \
+ } \
+ } else { \
req->ntvfs->async_states->send_fn(req->ntvfs); \
} \
} while (0)
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index c546de7e1c..9acf181c54 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -324,9 +324,26 @@ struct smbsrv_connection {
/*
* the server_context holds a linked list of pending requests,
* this is used for finding the request structures on ntcancel requests
+ * For SMB only
*/
struct smbsrv_request *requests;
+ /*
+ * the server_context holds a linked list of pending requests,
+ * and an idtree for finding the request structures on SMB2 Cancel
+ * For SMB2 only
+ */
+ struct {
+ /* an id tree used to allocate ids */
+ struct idr_context *idtree_req;
+
+ /* this is the limit of pending requests values for this connection */
+ uint32_t idtree_limit;
+
+ /* list of open tree connects */
+ struct smb2srv_request *list;
+ } requests2;
+
struct smb_signing_context signing;
struct stream_connection *connection;