diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/smbd/globals.h | 2 | ||||
-rw-r--r-- | source3/smbd/smb2_negprot.c | 127 | ||||
-rw-r--r-- | source3/smbd/smb2_server.c | 2 |
4 files changed, 132 insertions, 1 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 17558c97f9..53b7a3252a 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -748,7 +748,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \ smbd/dmapi.o smbd/signing.o \ smbd/file_access.o \ smbd/dnsregister.o smbd/globals.o \ - smbd/smb2_server.o \ + smbd/smb2_server.o smbd/smb2_negprot.o \ $(MANGLE_OBJ) @VFS_STATIC@ SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \ diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 3001189867..22e4837bf3 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -216,6 +216,8 @@ NTSTATUS smbd_smb2_request_error(struct smbd_smb2_request *req, NTSTATUS smbd_smb2_request_done(struct smbd_smb2_request *req, DATA_BLOB body, DATA_BLOB *dyn); +NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req); + struct smbd_smb2_request { TALLOC_CTX *mem_pool; diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c new file mode 100644 index 0000000000..d82d04885d --- /dev/null +++ b/source3/smbd/smb2_negprot.c @@ -0,0 +1,127 @@ +/* + Unix SMB/CIFS implementation. + Core SMB2 server + + Copyright (C) Stefan Metzmacher 2009 + + 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 "smbd/globals.h" +#include "../source4/libcli/smb2/smb2_constants.h" + +extern enum protocol_types Protocol; + +NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) +{ + const uint8_t *inbody; + const uint8_t *indyn = NULL; + int i = req->current_idx; + DATA_BLOB outbody; + DATA_BLOB outdyn; + DATA_BLOB negprot_spnego_blob; + uint16_t security_offset; + DATA_BLOB security_buffer; + size_t expected_body_size = 0x24; + size_t body_size; + size_t expected_dyn_size = 0; + size_t c; + uint16_t dialect_count; + uint16_t dialect; + +/* TODO: drop the connection with INVALI_PARAMETER */ + + if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) { + return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + } + + inbody = (const uint8_t *)req->in.vector[i+1].iov_base; + + body_size = SVAL(inbody, 0x00); + if (body_size != expected_body_size) { + return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + } + + dialect_count = SVAL(inbody, 0x02); + if (dialect_count == 0) { + return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + } + + expected_dyn_size = dialect_count * 2; + if (req->in.vector[i+2].iov_len < expected_dyn_size) { + return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + } + indyn = (const uint8_t *)req->in.vector[i+2].iov_base; + + for (c=0; c < dialect_count; c++) { + dialect = SVAL(indyn, c*2); + if (dialect == 0x0202) { + break; + } + } + + if (dialect != 0x0202) { + return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER); + } + + Protocol = PROTOCOL_SMB2; + + if (get_remote_arch() != RA_SAMBA) { + set_remote_arch(RA_VISTA); + } + + /* negprot_spnego() returns a the server guid in the first 16 bytes */ + negprot_spnego_blob = negprot_spnego(); + if (negprot_spnego_blob.data == NULL) { + return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); + } + talloc_steal(req, negprot_spnego_blob.data); + + if (negprot_spnego_blob.length < 16) { + return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR); + } + + security_offset = SMB2_HDR_BODY + 0x40; + security_buffer = data_blob_const(negprot_spnego_blob.data + 16, + negprot_spnego_blob.length - 16); + + outbody = data_blob_talloc(req->out.vector, NULL, 0x40); + if (outbody.data == NULL) { + return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); + } + + SSVAL(outbody.data, 0x00, 0x40 + 1); /* struct size */ +/*TODO: indicate signing enabled */ + SSVAL(outbody.data, 0x02, 0); /* security mode */ + SSVAL(outbody.data, 0x04, dialect); /* dialect revision */ + SSVAL(outbody.data, 0x06, 0); /* reserved */ + memcpy(outbody.data + 0x08, + negprot_spnego_blob.data, 16); /* server guid */ + SIVAL(outbody.data, 0x18, 0); /* capabilities */ + SIVAL(outbody.data, 0x1C, 0x00010000); /* max transact size */ + SIVAL(outbody.data, 0x20, 0x00010000); /* max read size */ + SIVAL(outbody.data, 0x24, 0x00010000); /* max write size */ + SBVAL(outbody.data, 0x28, 0); /* system time */ + SBVAL(outbody.data, 0x30, 0); /* server start time */ + SSVAL(outbody.data, 0x38, + security_offset); /* security buffer offset */ + SSVAL(outbody.data, 0x3A, + security_buffer.length); /* security buffer length */ + SIVAL(outbody.data, 0x3C, 0); /* reserved */ + + outdyn = security_buffer; + + return smbd_smb2_request_done(req, outbody, &outdyn); +} diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index c63c8da43c..f4e5dfabc5 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -290,6 +290,8 @@ static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode)); switch (opcode) { case SMB2_OP_NEGPROT: + return smbd_smb2_request_process_negprot(req); + case SMB2_OP_SESSSETUP: case SMB2_OP_LOGOFF: case SMB2_OP_TCON: |