1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

r17083: - implement SMB2 Cancel in the client

- the 0xffffffffffffffff seqnum is reserved for SMB2 Break (oplock breaks)
  so don't use it in a request. we should someday try to test this...

metze
(This used to be commit 730cdc4475)
This commit is contained in:
Stefan Metzmacher 2006-07-17 09:36:52 +00:00 committed by Gerald (Jerry) Carter
parent 152ea280f1
commit a5bafffd66
5 changed files with 105 additions and 5 deletions

View File

@ -0,0 +1,78 @@
/*
Unix SMB/CIFS implementation.
SMB2 client notify calls
Copyright (C) Stefan Metzmacher 2006
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
/*
send a cancel request
*/
NTSTATUS smb2_cancel(struct smb2_request *r)
{
NTSTATUS status;
struct smb2_request *c;
uint32_t old_timeout;
uint64_t old_seqnum;
/*
* if we don't get a pending id yet, we just
* mark the request for pending, so that we directly
* send the cancel after getting the pending id
*/
if (!r->cancel.can_cancel) {
r->cancel.do_cancel++;
return NT_STATUS_OK;
}
/* we don't want a seqmun for a SMB2 Cancel */
old_seqnum = r->transport->seqnum;
c = smb2_request_init(r->transport, SMB2_OP_CANCEL, 0x04, False, 0);
r->transport->seqnum = old_seqnum;
NT_STATUS_HAVE_NO_MEMORY(c);
c->seqnum = 0;
SIVAL(c->out.hdr, SMB2_HDR_FLAGS, 0x00000002);
SSVAL(c->out.hdr, SMB2_HDR_UNKNOWN1, 0x0030);
SIVAL(c->out.hdr, SMB2_HDR_PID, r->cancel.pending_id);
SBVAL(c->out.hdr, SMB2_HDR_SEQNUM, c->seqnum);
if (r->session) {
SBVAL(c->out.hdr, SMB2_HDR_UID, r->session->uid);
}
SSVAL(c->out.body, 0x02, 0);
old_timeout = c->transport->options.timeout;
c->transport->options.timeout = 0;
smb2_transport_send(c);
c->transport->options.timeout = old_timeout;
if (c->state == SMB2_REQUEST_ERROR) {
status = c->status;
} else {
status = NT_STATUS_OK;
}
talloc_free(c);
return status;
}

View File

@ -20,5 +20,6 @@ OBJ_FILES = \
flush.o \
lock.o \
notify.o \
cancel.o \
keepalive.o
PUBLIC_DEPENDENCIES = LIBCLI_RAW LIBPACKET gensec

View File

@ -35,6 +35,7 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
uint32_t body_dynamic_size)
{
struct smb2_request *req;
uint64_t seqnum;
if (body_dynamic_present) {
if (body_dynamic_size == 0) {
@ -47,17 +48,23 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
req = talloc(transport, struct smb2_request);
if (req == NULL) return NULL;
seqnum = transport->seqnum++;
if (seqnum == UINT64_MAX) {
seqnum = transport->seqnum++;
}
req->state = SMB2_REQUEST_INIT;
req->transport = transport;
req->session = NULL;
req->tree = NULL;
req->seqnum = transport->seqnum++;
req->seqnum = seqnum;
req->status = NT_STATUS_OK;
req->async.fn = NULL;
req->next = req->prev = NULL;
ZERO_STRUCT(req->cancel);
ZERO_STRUCT(req->in);
req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
req->out.allocated = req->out.size + body_dynamic_size;

View File

@ -128,6 +128,12 @@ struct smb2_request {
uint64_t seqnum;
struct {
BOOL do_cancel;
BOOL can_cancel;
uint32_t pending_id;
} cancel;
/* the NT status for this request. Set by packet receive code
or code detecting error. */
NTSTATUS status;

View File

@ -152,8 +152,10 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
int len;
struct smb2_request *req = NULL;
uint64_t seqnum;
uint32_t flags;
uint16_t buffer_code;
uint32_t dynamic_size;
uint32_t i;
buffer = blob.data;
len = blob.length;
@ -165,7 +167,8 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
goto error;
}
seqnum = BVAL(hdr, SMB2_HDR_SEQNUM);
flags = IVAL(hdr, SMB2_HDR_FLAGS);
seqnum = BVAL(hdr, SMB2_HDR_SEQNUM);
/* match the incoming request against the list of pending requests */
for (req=transport->pending_recv; req; req=req->next) {
@ -190,8 +193,13 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob)
req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
if (NT_STATUS_EQUAL(req->status, STATUS_PENDING)) {
/* the server has helpfully told us that this request is still being
processed. how useful :) */
if (flags & 0x00000002) {
req->cancel.can_cancel = True;
req->cancel.pending_id = IVAL(hdr, SMB2_HDR_PID);
for (i=0; i< req->cancel.do_cancel; i++) {
smb2_cancel(req);
}
}
talloc_free(buffer);
return NT_STATUS_OK;
}