diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2008-04-25 10:04:20 +0100 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2008-04-25 10:04:20 +0100 |
commit | cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31 (patch) | |
tree | d0b116699dee35372ed335834989e1c885e8f94a /source4/libcli/smb2 | |
parent | d1432d617e6ed04c33ca214d7f3b0099bdf53065 (diff) | |
parent | 240d959005f5fd80a38b3734b39dd5d6e425a566 (diff) | |
download | samba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.tar.gz samba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.tar.bz2 samba-cc9c4aaa8d02c4c31c9e9a4bb53e5941683fcc31.zip |
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-gmake3
Conflicts:
source/Makefile
source/auth/config.mk
source/auth/gensec/config.mk
source/build/m4/public.m4
source/build/make/python.mk
source/build/make/rules.mk
source/build/smb_build/header.pm
source/build/smb_build/main.pl
source/build/smb_build/makefile.pm
source/dsdb/config.mk
source/dsdb/samdb/ldb_modules/config.mk
source/kdc/config.mk
source/lib/events/config.mk
source/lib/events/events.c
source/lib/ldb/config.mk
source/lib/nss_wrapper/config.mk
source/lib/policy/config.mk
source/lib/util/config.mk
source/libcli/smb2/config.mk
source/libnet/config.mk
source/librpc/config.mk
source/nbt_server/config.mk
source/ntptr/ntptr_base.c
source/ntvfs/posix/config.mk
source/ntvfs/sysdep/config.mk
source/param/config.mk
source/rpc_server/config.mk
source/rpc_server/service_rpc.c
source/scripting/ejs/config.mk
source/scripting/python/config.mk
source/smb_server/config.mk
source/smbd/server.c
source/torture/config.mk
source/torture/smb2/config.mk
source/wrepl_server/config.mk
(This used to be commit 13bbd420681519894a4036729c43273912c9b402)
Diffstat (limited to 'source4/libcli/smb2')
-rw-r--r-- | source4/libcli/smb2/break.c | 74 | ||||
-rw-r--r-- | source4/libcli/smb2/config.mk | 2 | ||||
-rw-r--r-- | source4/libcli/smb2/connect.c | 7 | ||||
-rw-r--r-- | source4/libcli/smb2/create.c | 94 | ||||
-rw-r--r-- | source4/libcli/smb2/read.c | 13 | ||||
-rw-r--r-- | source4/libcli/smb2/request.c | 8 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2.h | 11 | ||||
-rw-r--r-- | source4/libcli/smb2/transport.c | 43 |
8 files changed, 217 insertions, 35 deletions
diff --git a/source4/libcli/smb2/break.c b/source4/libcli/smb2/break.c new file mode 100644 index 0000000000..fe0cceb829 --- /dev/null +++ b/source4/libcli/smb2/break.c @@ -0,0 +1,74 @@ +/* + Unix SMB/CIFS implementation. + + SMB2 client oplock break handling + + Copyright (C) Stefan Metzmacher 2008 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" + +/* + send a break request +*/ +struct smb2_request *smb2_break_send(struct smb2_tree *tree, struct smb2_break *io) +{ + struct smb2_request *req; + + req = smb2_request_init_tree(tree, SMB2_OP_BREAK, 0x18, false, 0); + if (req == NULL) return NULL; + + SCVAL(req->out.body, 0x02, io->in.oplock_level); + SCVAL(req->out.body, 0x03, io->in.reserved); + SIVAL(req->out.body, 0x04, io->in.reserved2); + smb2_push_handle(req->out.body+0x08, &io->in.file.handle); + + smb2_transport_send(req); + + return req; +} + + +/* + recv a break reply +*/ +NTSTATUS smb2_break_recv(struct smb2_request *req, struct smb2_break *io) +{ + if (!smb2_request_receive(req) || + !smb2_request_is_ok(req)) { + return smb2_request_destroy(req); + } + + SMB2_CHECK_PACKET_RECV(req, 0x18, false); + + io->out.oplock_level = CVAL(req->in.body, 0x02); + io->out.reserved = CVAL(req->in.body, 0x03); + io->out.reserved2 = IVAL(req->in.body, 0x04); + smb2_pull_handle(req->in.body+0x08, &io->out.file.handle); + + return smb2_request_destroy(req); +} + +/* + sync flush request +*/ +NTSTATUS smb2_break(struct smb2_tree *tree, struct smb2_break *io) +{ + struct smb2_request *req = smb2_break_send(tree, io); + return smb2_break_recv(req, io); +} diff --git a/source4/libcli/smb2/config.mk b/source4/libcli/smb2/config.mk index e95997db54..18f6245a3e 100644 --- a/source4/libcli/smb2/config.mk +++ b/source4/libcli/smb2/config.mk @@ -6,5 +6,5 @@ LIBCLI_SMB2_OBJ_FILES = $(addprefix libcli/smb2/, \ transport.o request.o negprot.o session.o tcon.o \ create.o close.o connect.o getinfo.o write.o read.o \ setinfo.o find.o ioctl.o logoff.o tdis.o flush.o \ - lock.o notify.o cancel.o keepalive.o) + lock.o notify.o cancel.o keepalive.o break.o) diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index d68b85ad54..59d4e6ea2d 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -121,7 +121,7 @@ static void continue_socket(struct composite_context *creq) struct smbcli_socket *sock; struct smb2_transport *transport; struct smb2_request *req; - uint16_t dialects[1]; + uint16_t dialects[2]; c->status = smbcli_sock_connect_recv(creq, state, &sock); if (!composite_is_ok(c)) return; @@ -130,11 +130,12 @@ static void continue_socket(struct composite_context *creq) if (composite_nomem(transport, c)) return; ZERO_STRUCT(state->negprot); - state->negprot.in.dialect_count = 1; + state->negprot.in.dialect_count = 2; state->negprot.in.security_mode = 0; state->negprot.in.capabilities = 0; unix_to_nt_time(&state->negprot.in.start_time, time(NULL)); - dialects[0] = SMB2_DIALECT_REVISION; + dialects[0] = 0; + dialects[1] = SMB2_DIALECT_REVISION; state->negprot.in.dialects = dialects; req = smb2_negprot_send(transport, &state->negprot); diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index 999c10ab08..6ac32a494f 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -28,30 +28,59 @@ /* add a blob to a smb2_create attribute blob */ -NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, - const char *tag, - DATA_BLOB add, bool last) +static NTSTATUS smb2_create_blob_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer, + const struct smb2_create_blob *blob, + bool last) { - uint32_t ofs = blob->length; - size_t tag_length = strlen(tag); - uint8_t pad = smb2_padding_size(add.length+tag_length, 8); - if (!data_blob_realloc(mem_ctx, blob, - blob->length + 0x14 + tag_length + add.length + pad)) + uint32_t ofs = buffer->length; + size_t tag_length = strlen(blob->tag); + uint8_t pad = smb2_padding_size(blob->data.length+tag_length, 4); + + if (!data_blob_realloc(mem_ctx, buffer, + buffer->length + 0x14 + tag_length + blob->data.length + pad)) return NT_STATUS_NO_MEMORY; - + if (last) { - SIVAL(blob->data, ofs+0x00, 0); + SIVAL(buffer->data, ofs+0x00, 0); } else { - SIVAL(blob->data, ofs+0x00, 0x14 + tag_length + add.length + pad); + SIVAL(buffer->data, ofs+0x00, 0x14 + tag_length + blob->data.length + pad); } - SSVAL(blob->data, ofs+0x04, 0x10); /* offset of tag */ - SIVAL(blob->data, ofs+0x06, tag_length); /* tag length */ - SSVAL(blob->data, ofs+0x0A, 0x14 + tag_length); /* offset of data */ - SIVAL(blob->data, ofs+0x0C, add.length); - memcpy(blob->data+ofs+0x10, tag, tag_length); - SIVAL(blob->data, ofs+0x10+tag_length, 0); /* pad? */ - memcpy(blob->data+ofs+0x14+tag_length, add.data, add.length); - memset(blob->data+ofs+0x14+tag_length+add.length, 0, pad); + SSVAL(buffer->data, ofs+0x04, 0x10); /* offset of tag */ + SIVAL(buffer->data, ofs+0x06, tag_length); /* tag length */ + SSVAL(buffer->data, ofs+0x0A, 0x14 + tag_length); /* offset of data */ + SIVAL(buffer->data, ofs+0x0C, blob->data.length); + memcpy(buffer->data+ofs+0x10, blob->tag, tag_length); + SIVAL(buffer->data, ofs+0x10+tag_length, 0); /* pad? */ + memcpy(buffer->data+ofs+0x14+tag_length, blob->data.data, blob->data.length); + memset(buffer->data+ofs+0x14+tag_length+blob->data.length, 0, pad); + + return NT_STATUS_OK; +} + +NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b, + const char *tag, DATA_BLOB data) +{ + struct smb2_create_blob *array; + + array = talloc_realloc(mem_ctx, b->blobs, + struct smb2_create_blob, + b->num_blobs + 1); + NT_STATUS_HAVE_NO_MEMORY(array); + b->blobs = array; + + b->blobs[b->num_blobs].tag = talloc_strdup(b->blobs, tag); + NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].tag); + + if (data.data) { + b->blobs[b->num_blobs].data = data_blob_talloc(b->blobs, + data.data, + data.length); + NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].data.data); + } else { + b->blobs[b->num_blobs].data = data_blob(NULL, 0); + } + + b->num_blobs += 1; return NT_STATUS_OK; } @@ -64,6 +93,7 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create struct smb2_request *req; NTSTATUS status; DATA_BLOB blob = data_blob(NULL, 0); + uint32_t i; req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0); if (req == NULL) return NULL; @@ -89,7 +119,8 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create DATA_BLOB b = data_blob_talloc(req, NULL, ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas)); ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas); - status = smb2_create_blob_add(req, &blob, SMB2_CREATE_TAG_EXTA, b, false); + status = smb2_create_blob_add(req, &io->in.blobs, + SMB2_CREATE_TAG_EXTA, b); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; @@ -99,13 +130,30 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create /* an empty MxAc tag seems to be used to ask the server to return the maximum access mask allowed on the file */ - status = smb2_create_blob_add(req, &blob, SMB2_CREATE_TAG_MXAC, - data_blob(NULL, 0), true); - + status = smb2_create_blob_add(req, &io->in.blobs, + SMB2_CREATE_TAG_MXAC, data_blob(NULL, 0)); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; } + + for (i=0; i < io->in.blobs.num_blobs; i++) { + bool last = false; + const struct smb2_create_blob *c; + + if ((i + 1) == io->in.blobs.num_blobs) { + last = true; + } + + c = &io->in.blobs.blobs[i]; + status = smb2_create_blob_push_one(req, &blob, + c, last); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } + } + status = smb2_push_o32s32_blob(&req->out, 0x30, blob); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); diff --git a/source4/libcli/smb2/read.c b/source4/libcli/smb2/read.c index b61f918481..9d40e32a4d 100644 --- a/source4/libcli/smb2/read.c +++ b/source4/libcli/smb2/read.c @@ -33,12 +33,16 @@ struct smb2_request *smb2_read_send(struct smb2_tree *tree, struct smb2_read *io req = smb2_request_init_tree(tree, SMB2_OP_READ, 0x30, true, 0); if (req == NULL) return NULL; - SSVAL(req->out.body, 0x02, 0); /* pad */ + SCVAL(req->out.body, 0x02, 0); /* pad */ + SCVAL(req->out.body, 0x03, 0); /* reserved */ SIVAL(req->out.body, 0x04, io->in.length); SBVAL(req->out.body, 0x08, io->in.offset); smb2_push_handle(req->out.body+0x10, &io->in.file.handle); - SBVAL(req->out.body, 0x20, io->in.unknown1); - SBVAL(req->out.body, 0x28, io->in.unknown2); + SIVAL(req->out.body, 0x20, io->in.min_count); + SIVAL(req->out.body, 0x24, io->in.channel); + SIVAL(req->out.body, 0x28, io->in.remaining); + SSVAL(req->out.body, 0x2C, io->in.channel_offset); + SSVAL(req->out.body, 0x2E, io->in.channel_length); smb2_transport_send(req); @@ -67,7 +71,8 @@ NTSTATUS smb2_read_recv(struct smb2_request *req, return status; } - io->out.unknown1 = BVAL(req->in.body, 0x08); + io->out.remaining = IVAL(req->in.body, 0x08); + io->out.reserved = IVAL(req->in.body, 0x0C); return smb2_request_destroy(req); } diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index 2471fcaa4d..f52b0ceef2 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -211,10 +211,10 @@ bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size) return false; } /* be careful with wraparound! */ - if (ptr < buf->body || - ptr >= buf->body + buf->body_size || + if ((uintptr_t)ptr < (uintptr_t)buf->body || + (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size || size > buf->body_size || - ptr + size > buf->body + buf->body_size) { + (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) { return true; } return false; @@ -669,7 +669,7 @@ NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf, } if (*str == 0) { - blob.data = str; + blob.data = discard_const(str); blob.length = 0; return smb2_push_o16s16_blob(buf, ofs, blob); } diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index 726df64090..ae66a6e0d3 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -21,6 +21,8 @@ #include "libcli/raw/request.h" +struct smb2_handle; + struct smb2_options { uint32_t timeout; }; @@ -58,6 +60,15 @@ struct smb2_transport { void *private; uint_t period; } idle; + + struct { + /* a oplock break request handler */ + bool (*handler)(struct smb2_transport *transport, + const struct smb2_handle *handle, + uint8_t level, void *private_data); + /* private data passed to the oplock handler */ + void *private_data; + } oplock; }; diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index af19fcb0a9..8eb60a06f1 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -140,6 +140,44 @@ void smb2_transport_dead(struct smb2_transport *transport, NTSTATUS status) } } +static bool smb2_handle_oplock_break(struct smb2_transport *transport, + const DATA_BLOB *blob) +{ + uint8_t *hdr; + uint16_t opcode; + uint64_t seqnum; + + hdr = blob->data+NBT_HDR_SIZE; + + if (blob->length < (SMB2_MIN_SIZE+0x18)) { + DEBUG(1,("Discarding smb2 oplock reply of size %u\n", + blob->length)); + return false; + } + + opcode = SVAL(hdr, SMB2_HDR_OPCODE); + seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); + + if ((opcode != SMB2_OP_BREAK) || + (seqnum != UINT64_MAX)) { + return false; + } + + if (transport->oplock.handler) { + uint8_t *body = hdr+SMB2_HDR_BODY; + struct smb2_handle h; + uint8_t level; + + level = CVAL(body, 0x02); + smb2_pull_handle(body+0x08, &h); + + transport->oplock.handler(transport, &h, level, + transport->oplock.private_data); + } + + return true; +} + /* we have a full request in our receive buffer - match it to a pending request and process @@ -167,6 +205,11 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) goto error; } + if (smb2_handle_oplock_break(transport, &blob)) { + talloc_free(buffer); + return NT_STATUS_OK; + } + flags = IVAL(hdr, SMB2_HDR_FLAGS); seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); |