1
0
mirror of https://github.com/samba-team/samba.git synced 2025-10-23 11:33:16 +03:00

r17084: implement SMB2 Cancel in the server,

that makes it possible for clients to cancel
async requests, like NOTIFY...

metze
(This used to be commit eaccd3c435)
This commit is contained in:
Stefan Metzmacher
2006-07-17 09:44:13 +00:00
committed by Gerald (Jerry) Carter
parent a5bafffd66
commit 8075ce63fd
4 changed files with 125 additions and 11 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;