diff options
-rw-r--r-- | source4/libcli/smb2/negprot.c | 1 | ||||
-rw-r--r-- | source4/libcli/smb2/request.c | 56 | ||||
-rw-r--r-- | source4/libcli/smb2/session.c | 28 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2.h | 4 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2_calls.h | 7 | ||||
-rw-r--r-- | source4/libcli/smb2/transport.c | 8 | ||||
-rw-r--r-- | source4/torture/smb2/connect.c | 40 |
7 files changed, 114 insertions, 30 deletions
diff --git a/source4/libcli/smb2/negprot.c b/source4/libcli/smb2/negprot.c index ffddf8a2f0..5cd4810909 100644 --- a/source4/libcli/smb2/negprot.c +++ b/source4/libcli/smb2/negprot.c @@ -33,7 +33,6 @@ struct smb2_request *smb2_negprot_send(struct smb2_transport *transport, { struct smb2_request *req; - req = smb2_request_init(transport, SMB2_OP_NEGPROT, 0x26); if (req == NULL) return NULL; diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index e71fc84471..93f8043d0c 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -130,7 +130,7 @@ BOOL smb2_request_is_error(struct smb2_request *req) /* check if a range in the reply body is out of bounds */ -BOOL smb2_oob(struct smb2_request *req, const uint8_t *ptr, uint_t size) +BOOL smb2_oob_in(struct smb2_request *req, const uint8_t *ptr, uint_t size) { /* be careful with wraparound! */ if (ptr < req->in.body || @@ -143,13 +143,65 @@ BOOL smb2_oob(struct smb2_request *req, const uint8_t *ptr, uint_t size) } /* + check if a range in the outgoing body is out of bounds +*/ +BOOL smb2_oob_out(struct smb2_request *req, const uint8_t *ptr, uint_t size) +{ + /* be careful with wraparound! */ + if (ptr < req->out.body || + ptr >= req->out.body + req->out.body_size || + size > req->out.body_size || + ptr + size > req->out.body + req->out.body_size) { + return True; + } + return False; +} + +/* pull a data blob from the body of a reply */ DATA_BLOB smb2_pull_blob(struct smb2_request *req, uint8_t *ptr, uint_t size) { - if (smb2_oob(req, ptr, size)) { + if (smb2_oob_in(req, ptr, size)) { return data_blob(NULL, 0); } return data_blob_talloc(req, ptr, size); } +/* + pull a ofs/length/blob triple into a data blob + the ptr points to the start of the offset/length pair +*/ +NTSTATUS smb2_pull_ofs_blob(struct smb2_request *req, uint8_t *ptr, DATA_BLOB *blob) +{ + uint16_t ofs, size; + if (smb2_oob_in(req, ptr, 4)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + ofs = SVAL(ptr, 0); + size = SVAL(ptr, 2); + if (smb2_oob_in(req, req->in.hdr + ofs, size)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + *blob = data_blob_talloc(req, req->in.hdr+ofs, size); + NT_STATUS_HAVE_NO_MEMORY(blob->data); + return NT_STATUS_OK; +} + +/* + push a ofs/length/blob triple into a data blob + the ptr points to the start of the offset/length pair + + NOTE: assumes blob goes immediately after the offset/length pair. Needs + to be generalised +*/ +NTSTATUS smb2_push_ofs_blob(struct smb2_request *req, uint8_t *ptr, DATA_BLOB blob) +{ + if (smb2_oob_out(req, ptr, 4+blob.length)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + SSVAL(ptr, 0, 4 + (ptr - req->out.hdr)); + SSVAL(ptr, 2, blob.length); + memcpy(ptr+4, blob.data, blob.length); + return NT_STATUS_OK; +} diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c index 2f9a979fea..031360fcb9 100644 --- a/source4/libcli/smb2/session.c +++ b/source4/libcli/smb2/session.c @@ -62,17 +62,22 @@ struct smb2_request *smb2_session_setup_send(struct smb2_session *session, struct smb2_session_setup *io) { struct smb2_request *req; + NTSTATUS status; req = smb2_request_init(session->transport, SMB2_OP_SESSSETUP, 0x10 + io->in.secblob.length); if (req == NULL) return NULL; + SBVAL(req->out.hdr, SMB2_HDR_UID, session->uid); SIVAL(req->out.body, 0x00, io->in.unknown1); SIVAL(req->out.body, 0x04, io->in.unknown2); SIVAL(req->out.body, 0x08, io->in.unknown3); - SSVAL(req->out.body, 0x0C, io->in.unknown4); - SSVAL(req->out.body, 0x0E, io->in.secblob.length); - memcpy(req->out.body+0x10, io->in.secblob.data, io->in.secblob.length); + + status = smb2_push_ofs_blob(req, req->out.body+0x0C, io->in.secblob); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } smb2_transport_send(req); @@ -86,10 +91,11 @@ struct smb2_request *smb2_session_setup_send(struct smb2_session *session, NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_session_setup *io) { - uint16_t blobsize; + NTSTATUS status; if (!smb2_request_receive(req) || - smb2_request_is_error(req)) { + (smb2_request_is_error(req) && + !NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED))) { return smb2_request_destroy(req); } @@ -97,10 +103,14 @@ NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, return NT_STATUS_BUFFER_TOO_SMALL; } - io->out.unknown1 = IVAL(req->in.body, 0x00); - io->out.unknown2 = SVAL(req->in.body, 0x04); - blobsize = SVAL(req->in.body, 0x06); - io->out.secblob = smb2_pull_blob(req, req->in.body+0x08, blobsize); + io->out.unknown1 = IVAL(req->in.body, 0x00); + io->out.uid = BVAL(req->in.hdr, SMB2_HDR_UID); + + status = smb2_pull_ofs_blob(req, req->in.body+0x04, &io->out.secblob); + if (!NT_STATUS_IS_OK(status)) { + smb2_request_destroy(req); + return status; + } talloc_steal(mem_ctx, io->out.secblob.data); return smb2_request_destroy(req); diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index 2262040b51..8ed51b2351 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -57,6 +57,7 @@ struct smb2_transport { struct smb2_session { struct smb2_transport *transport; struct gensec_security *gensec; + uint64_t uid; }; struct smb2_request_buffer { @@ -141,8 +142,7 @@ struct smb2_request { #define SMB2_HDR_SEQNUM 0x18 #define SMB2_HDR_PID 0x20 #define SMB2_HDR_TID 0x24 -#define SMB2_HDR_UID 0x28 -#define SMB2_HDR_UID2 0x2c /* whats this? */ +#define SMB2_HDR_UID 0x28 /* 64 bit */ #define SMB2_HDR_SIG 0x30 /* guess ... */ #define SMB2_HDR_BODY 0x40 diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h index ef0abc3e45..3ee8f90bc9 100644 --- a/source4/libcli/smb2/smb2_calls.h +++ b/source4/libcli/smb2/smb2_calls.h @@ -50,14 +50,13 @@ struct smb2_session_setup { uint32_t unknown1; /* 0x11 */ uint32_t unknown2; /* 0xF */ uint32_t unknown3; /* 0x00 */ - uint16_t unknown4; /* 0x50 */ - /* uint16_t secblob size here */ + /* uint16_t secblob ofs/size here */ DATA_BLOB secblob; } in; struct { uint32_t unknown1; /* 0x09 */ - uint16_t unknown2; /* 0x48 */ - /* uint16_t secblob size here */ + /* uint16_t secblob ofs/size here */ DATA_BLOB secblob; + uint64_t uid; /* returned in header */ } out; }; diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index dd05eed1dd..97408b2ae3 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -183,7 +183,8 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) req->in.ptr = req->in.body; req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS)); - dump_data(0, req->in.body, req->in.body_size); + DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", req->seqnum)); + dump_data(2, req->in.body, req->in.body_size); /* if this request has an async handler then call that to notify that the reply has been received. This might destroy @@ -200,7 +201,7 @@ error: DLIST_REMOVE(transport->pending_recv, req); req->state = SMB2_REQUEST_ERROR; } - dump_data(0, blob.data, blob.length); + dump_data(2, blob.data, blob.length); data_blob_free(&blob); return NT_STATUS_UNSUCCESSFUL; } @@ -247,6 +248,9 @@ void smb2_transport_send(struct smb2_request *req) _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE); + DEBUG(2, ("SMB2 send seqnum=0x%llx\n", req->seqnum)); + dump_data(2, req->out.body, req->out.body_size); + /* check if the transport is dead */ if (req->transport->socket->sock == NULL) { req->state = SMB2_REQUEST_ERROR; diff --git a/source4/torture/smb2/connect.c b/source4/torture/smb2/connect.c index 43029dd04d..49b9582d4d 100644 --- a/source4/torture/smb2/connect.c +++ b/source4/torture/smb2/connect.c @@ -76,6 +76,8 @@ static struct smb2_transport *torture_smb2_negprot(TALLOC_CTX *mem_ctx, const ch printf("current_time = %s\n", nt_time_string(mem_ctx, io.out.current_time)); printf("boot_time = %s\n", nt_time_string(mem_ctx, io.out.boot_time)); + transport->negotiate.secblob = io.out.secblob; + return transport; } @@ -89,12 +91,12 @@ static struct smb2_session *torture_smb2_session(struct smb2_transport *transpor struct smb2_session_setup io; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(transport); + DATA_BLOB secblob; ZERO_STRUCT(io); io.in.unknown1 = 0x11; io.in.unknown2 = 0xF; io.in.unknown3 = 0x00; - io.in.unknown4 = 0x50; session = smb2_session_init(transport, transport, True); @@ -126,21 +128,39 @@ static struct smb2_session *torture_smb2_session(struct smb2_transport *transpor return NULL; } - status = gensec_update(session->gensec, tmp_ctx, - session->transport->negotiate.secblob, - &io.in.secblob); - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && - !NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed initial gensec_update : %s\n", nt_errstr(status))); - return NULL; - } + secblob = session->transport->negotiate.secblob; + + do { + NTSTATUS status1; + + status1 = gensec_update(session->gensec, tmp_ctx, secblob, &io.in.secblob); + if (!NT_STATUS_EQUAL(status1, NT_STATUS_MORE_PROCESSING_REQUIRED) && + !NT_STATUS_IS_OK(status1)) { + DEBUG(1, ("Failed initial gensec_update : %s\n", + nt_errstr(status1))); + status = status1; + break; + } + + status = smb2_session_setup(session, tmp_ctx, &io); + secblob = io.out.secblob; + + session->uid = io.out.uid; + + if (NT_STATUS_IS_OK(status) && + NT_STATUS_EQUAL(status1, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + status = gensec_update(session->gensec, tmp_ctx, secblob, + &io.in.secblob); + } + } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); - status = smb2_session_setup(session, tmp_ctx, &io); if (!NT_STATUS_IS_OK(status)) { printf("session setup failed - %s\n", nt_errstr(status)); return NULL; } + printf("Session setup gave UID 0x%llx\n", session->uid); + return session; } |