diff options
Diffstat (limited to 'source4/libcli/smb2')
-rw-r--r-- | source4/libcli/smb2/cancel.c | 6 | ||||
-rw-r--r-- | source4/libcli/smb2/connect.c | 10 | ||||
-rw-r--r-- | source4/libcli/smb2/create.c | 52 | ||||
-rw-r--r-- | source4/libcli/smb2/getinfo.c | 45 | ||||
-rw-r--r-- | source4/libcli/smb2/logoff.c | 2 | ||||
-rw-r--r-- | source4/libcli/smb2/negprot.c | 54 | ||||
-rw-r--r-- | source4/libcli/smb2/notify.c | 2 | ||||
-rw-r--r-- | source4/libcli/smb2/request.c | 101 | ||||
-rw-r--r-- | source4/libcli/smb2/session.c | 24 | ||||
-rw-r--r-- | source4/libcli/smb2/setinfo.c | 6 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2.h | 73 | ||||
-rw-r--r-- | source4/libcli/smb2/smb2_calls.h | 61 | ||||
-rw-r--r-- | source4/libcli/smb2/tcon.c | 18 | ||||
-rw-r--r-- | source4/libcli/smb2/transport.c | 4 |
14 files changed, 323 insertions, 135 deletions
diff --git a/source4/libcli/smb2/cancel.c b/source4/libcli/smb2/cancel.c index 096919f177..80127feea5 100644 --- a/source4/libcli/smb2/cancel.c +++ b/source4/libcli/smb2/cancel.c @@ -52,11 +52,11 @@ NTSTATUS smb2_cancel(struct smb2_request *r) c->seqnum = 0; SIVAL(c->out.hdr, SMB2_HDR_FLAGS, 0x00000002); - SSVAL(c->out.hdr, SMB2_HDR_UNKNOWN1, 0x0030); + SSVAL(c->out.hdr, SMB2_HDR_CREDIT, 0x0030); SIVAL(c->out.hdr, SMB2_HDR_PID, r->cancel.pending_id); - SBVAL(c->out.hdr, SMB2_HDR_SEQNUM, c->seqnum); + SBVAL(c->out.hdr, SMB2_HDR_MESSAGE_ID, c->seqnum); if (r->session) { - SBVAL(c->out.hdr, SMB2_HDR_UID, r->session->uid); + SBVAL(c->out.hdr, SMB2_HDR_SESSION_ID, r->session->uid); } SSVAL(c->out.body, 0x02, 0); diff --git a/source4/libcli/smb2/connect.c b/source4/libcli/smb2/connect.c index 4518203183..85ddafc031 100644 --- a/source4/libcli/smb2/connect.c +++ b/source4/libcli/smb2/connect.c @@ -73,7 +73,7 @@ static void continue_session(struct composite_context *creq) state->tree = smb2_tree_init(state->session, state, true); if (composite_nomem(state->tree, c)) return; - state->tcon.in.unknown1 = 0x09; + state->tcon.in.reserved = 0; state->tcon.in.path = talloc_asprintf(state, "\\\\%s\\%s", state->host, state->share); if (composite_nomem(state->tcon.in.path, c)) return; @@ -120,6 +120,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]; c->status = smbcli_sock_connect_recv(creq, state, &sock); if (!composite_is_ok(c)) return; @@ -128,7 +129,12 @@ static void continue_socket(struct composite_context *creq) if (composite_nomem(transport, c)) return; ZERO_STRUCT(state->negprot); - state->negprot.in.unknown1 = 0x0001; + state->negprot.in.dialect_count = 1; + 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; + state->negprot.in.dialects = dialects; req = smb2_negprot_send(transport, &state->negprot); if (composite_nomem(req, c)) return; diff --git a/source4/libcli/smb2/create.c b/source4/libcli/smb2/create.c index ba11c22e87..cca83a040c 100644 --- a/source4/libcli/smb2/create.c +++ b/source4/libcli/smb2/create.c @@ -24,34 +24,33 @@ #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" -#define CREATE_TAG_EXTA 0x41747845 /* "ExtA" */ -#define CREATE_TAG_MXAC 0x6341784D /* "MxAc" */ - /* add a blob to a smb2_create attribute blob */ NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, - uint32_t tag, + const char *tag, DATA_BLOB add, bool last) { uint32_t ofs = blob->length; - uint8_t pad = smb2_padding_size(add.length, 8); - if (!data_blob_realloc(mem_ctx, blob, blob->length + 0x18 + add.length + pad)) + 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)) return NT_STATUS_NO_MEMORY; if (last) { SIVAL(blob->data, ofs+0x00, 0); } else { - SIVAL(blob->data, ofs+0x00, 0x18 + add.length + pad); + SIVAL(blob->data, ofs+0x00, 0x14 + tag_length + add.length + pad); } SSVAL(blob->data, ofs+0x04, 0x10); /* offset of tag */ - SIVAL(blob->data, ofs+0x06, 0x04); /* tag length */ - SSVAL(blob->data, ofs+0x0A, 0x18); /* offset of data */ + 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); - SIVAL(blob->data, ofs+0x10, tag); - SIVAL(blob->data, ofs+0x14, 0); /* pad? */ - memcpy(blob->data+ofs+0x18, add.data, add.length); - memset(blob->data+ofs+0x18+add.length, 0, pad); + 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); return NT_STATUS_OK; } @@ -68,16 +67,15 @@ struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0); if (req == NULL) return NULL; - SSVAL(req->out.body, 0x02, io->in.oplock_flags); - SIVAL(req->out.body, 0x04, io->in.impersonation); - SIVAL(req->out.body, 0x08, io->in.unknown3[0]); - SIVAL(req->out.body, 0x0C, io->in.unknown3[1]); - SIVAL(req->out.body, 0x10, io->in.unknown3[2]); - SIVAL(req->out.body, 0x14, io->in.unknown3[3]); - SIVAL(req->out.body, 0x18, io->in.access_mask); - SIVAL(req->out.body, 0x1C, io->in.file_attr); + SCVAL(req->out.body, 0x02, io->in.security_flags); + SCVAL(req->out.body, 0x03, io->in.oplock_level); + SIVAL(req->out.body, 0x04, io->in.impersonation_level); + SBVAL(req->out.body, 0x08, io->in.create_flags); + SBVAL(req->out.body, 0x10, io->in.reserved); + SIVAL(req->out.body, 0x18, io->in.desired_access); + SIVAL(req->out.body, 0x1C, io->in.file_attributes); SIVAL(req->out.body, 0x20, io->in.share_access); - SIVAL(req->out.body, 0x24, io->in.open_disposition); + SIVAL(req->out.body, 0x24, io->in.create_disposition); SIVAL(req->out.body, 0x28, io->in.create_options); status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname); @@ -90,7 +88,7 @@ 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, CREATE_TAG_EXTA, b, false); + status = smb2_create_blob_add(req, &blob, SMB2_CREATE_TAG_EXTA, b, false); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); return NULL; @@ -100,7 +98,8 @@ 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, CREATE_TAG_MXAC, data_blob(NULL, 0), true); + status = smb2_create_blob_add(req, &blob, SMB2_CREATE_TAG_MXAC, + data_blob(NULL, 0), true); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); @@ -132,7 +131,8 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct SMB2_CHECK_PACKET_RECV(req, 0x58, true); - io->out.oplock_flags = SVAL(req->in.body, 0x02); + io->out.oplock_level = CVAL(req->in.body, 0x02); + io->out.reserved = CVAL(req->in.body, 0x03); io->out.create_action = IVAL(req->in.body, 0x04); io->out.create_time = smbcli_pull_nttime(req->in.body, 0x08); io->out.access_time = smbcli_pull_nttime(req->in.body, 0x10); @@ -141,7 +141,7 @@ NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct io->out.alloc_size = BVAL(req->in.body, 0x28); io->out.size = BVAL(req->in.body, 0x30); io->out.file_attr = IVAL(req->in.body, 0x38); - io->out._pad = IVAL(req->in.body, 0x3C); + io->out.reserved2 = IVAL(req->in.body, 0x3C); smb2_pull_handle(req->in.body+0x40, &io->out.file.handle); status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &io->out.blob); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/libcli/smb2/getinfo.c b/source4/libcli/smb2/getinfo.c index 0665dd441c..e9f47140f5 100644 --- a/source4/libcli/smb2/getinfo.c +++ b/source4/libcli/smb2/getinfo.c @@ -30,21 +30,27 @@ struct smb2_request *smb2_getinfo_send(struct smb2_tree *tree, struct smb2_getinfo *io) { struct smb2_request *req; + NTSTATUS status; - req = smb2_request_init_tree(tree, SMB2_OP_GETINFO, 0x28, false, 0); + req = smb2_request_init_tree(tree, SMB2_OP_GETINFO, 0x28, true, + io->in.blob.length); if (req == NULL) return NULL; - /* this seems to be a bug, they use 0x29 but only send 0x28 bytes */ - SSVAL(req->out.body, 0x00, 0x29); - - SSVAL(req->out.body, 0x02, io->in.level); - SIVAL(req->out.body, 0x04, io->in.max_response_size); - SIVAL(req->out.body, 0x08, io->in.unknown1); - SIVAL(req->out.body, 0x0C, io->in.unknown2); - SIVAL(req->out.body, 0x10, io->in.flags); - SIVAL(req->out.body, 0x14, io->in.flags2); + SCVAL(req->out.body, 0x02, io->in.info_type); + SCVAL(req->out.body, 0x03, io->in.info_class); + SIVAL(req->out.body, 0x04, io->in.output_buffer_length); + SIVAL(req->out.body, 0x0C, io->in.reserved); + SIVAL(req->out.body, 0x08, io->in.input_buffer_length); + SIVAL(req->out.body, 0x10, io->in.additional_information); + SIVAL(req->out.body, 0x14, io->in.getinfo_flags); smb2_push_handle(req->out.body+0x18, &io->in.file.handle); + /* this blob is used for quota queries */ + status = smb2_push_o32s32_blob(&req->out, 0x08, io->in.blob); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(req); + return NULL; + } smb2_transport_send(req); return req; @@ -116,15 +122,17 @@ struct smb2_request *smb2_getinfo_file_send(struct smb2_tree *tree, union smb_fi } ZERO_STRUCT(b); - b.in.max_response_size = 0x10000; - b.in.file.handle = io->generic.in.file.handle; - b.in.level = smb2_level; + b.in.info_type = smb2_level & 0xFF; + b.in.info_class = smb2_level >> 8; + b.in.output_buffer_length = 0x10000; + b.in.input_buffer_length = 0; + b.in.file.handle = io->generic.in.file.handle; if (io->generic.level == RAW_FILEINFO_SEC_DESC) { - b.in.flags = io->query_secdesc.in.secinfo_flags; + b.in.additional_information = io->query_secdesc.in.secinfo_flags; } if (io->generic.level == RAW_FILEINFO_SMB2_ALL_EAS) { - b.in.flags2 = io->all_eas.in.continue_flags; + b.in.getinfo_flags = io->all_eas.in.continue_flags; } return smb2_getinfo_send(tree, &b); @@ -172,9 +180,10 @@ struct smb2_request *smb2_getinfo_fs_send(struct smb2_tree *tree, union smb_fsin } ZERO_STRUCT(b); - b.in.max_response_size = 0x10000; - b.in.file.handle = io->generic.handle; - b.in.level = smb2_level; + b.in.output_buffer_length = 0x10000; + b.in.file.handle = io->generic.handle; + b.in.info_type = smb2_level & 0xFF; + b.in.info_class = smb2_level >> 8; return smb2_getinfo_send(tree, &b); } diff --git a/source4/libcli/smb2/logoff.c b/source4/libcli/smb2/logoff.c index 321a4db1a6..b38a08ca43 100644 --- a/source4/libcli/smb2/logoff.c +++ b/source4/libcli/smb2/logoff.c @@ -33,7 +33,7 @@ struct smb2_request *smb2_logoff_send(struct smb2_session *session) req = smb2_request_init(session->transport, SMB2_OP_LOGOFF, 0x04, false, 0); if (req == NULL) return NULL; - SBVAL(req->out.hdr, SMB2_HDR_UID, session->uid); + SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, session->uid); SSVAL(req->out.body, 0x02, 0); diff --git a/source4/libcli/smb2/negprot.c b/source4/libcli/smb2/negprot.c index 38fe0e7e53..6b879e2add 100644 --- a/source4/libcli/smb2/negprot.c +++ b/source4/libcli/smb2/negprot.c @@ -31,16 +31,28 @@ struct smb2_request *smb2_negprot_send(struct smb2_transport *transport, struct smb2_negprot *io) { struct smb2_request *req; - - req = smb2_request_init(transport, SMB2_OP_NEGPROT, 0x26, false, 0); + uint16_t size = 0x24 + io->in.dialect_count*2; + enum ndr_err_code ndr_err; + int i; + + req = smb2_request_init(transport, SMB2_OP_NEGPROT, size, false, 0); if (req == NULL) return NULL; - /* this seems to be a bug, they use 0x24 but the length is 0x26 */ - SSVAL(req->out.body, 0x00, 0x24); - SSVAL(req->out.body, 0x02, io->in.unknown1); - memcpy(req->out.body+0x04, io->in.unknown2, 32); - SSVAL(req->out.body, 0x24, io->in.unknown3); + SSVAL(req->out.body, 0x00, 0x24); + SSVAL(req->out.body, 0x02, io->in.dialect_count); + SSVAL(req->out.body, 0x04, io->in.security_mode); + SSVAL(req->out.body, 0x06, io->in.reserved); + SIVAL(req->out.body, 0x08, io->in.capabilities); + ndr_err = smbcli_push_guid(req->out.body, 0x0C, &io->in.client_guid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(req); + return NULL; + } + smbcli_push_nttime(req->out.body, 0x1C, io->in.start_time); + for (i=0;i<io->in.dialect_count;i++) { + SSVAL(req->out.body, 0x24 + i*2, io->in.dialects[i]); + } smb2_transport_send(req); @@ -54,6 +66,7 @@ NTSTATUS smb2_negprot_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_negprot *io) { NTSTATUS status; + enum ndr_err_code ndr_err; if (!smb2_request_receive(req) || smb2_request_is_error(req)) { @@ -62,24 +75,27 @@ NTSTATUS smb2_negprot_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, SMB2_CHECK_PACKET_RECV(req, 0x40, true); - io->out._pad = SVAL(req->in.body, 0x02); - io->out.unknown2 = IVAL(req->in.body, 0x04); - memcpy(io->out.sessid, req->in.body + 0x08, 16); - io->out.unknown3 = IVAL(req->in.body, 0x18); - io->out.unknown4 = SVAL(req->in.body, 0x1C); - io->out.unknown5 = IVAL(req->in.body, 0x1E); - io->out.unknown6 = IVAL(req->in.body, 0x22); - io->out.unknown7 = SVAL(req->in.body, 0x26); - io->out.current_time = smbcli_pull_nttime(req->in.body, 0x28); - io->out.boot_time = smbcli_pull_nttime(req->in.body, 0x30); + io->out.security_mode = SVAL(req->in.body, 0x02); + io->out.dialect_revision = SVAL(req->in.body, 0x04); + io->out.reserved = SVAL(req->in.body, 0x06); + ndr_err = smbcli_pull_guid(req->in.body, 0x08, &io->in.client_guid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + smb2_request_destroy(req); + return NT_STATUS_INTERNAL_ERROR; + } + io->out.capabilities = IVAL(req->in.body, 0x18); + io->out.max_transact_size = IVAL(req->in.body, 0x1C); + io->out.max_read_size = IVAL(req->in.body, 0x20); + io->out.max_write_size = IVAL(req->in.body, 0x24); + io->out.system_time = smbcli_pull_nttime(req->in.body, 0x28); + io->out.server_start_time = smbcli_pull_nttime(req->in.body, 0x30); + io->out.reserved2 = IVAL(req->in.body, 0x3C); status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x38, &io->out.secblob); if (!NT_STATUS_IS_OK(status)) { smb2_request_destroy(req); return status; } - - io->out.unknown9 = IVAL(req->in.body, 0x3C); return smb2_request_destroy(req); } diff --git a/source4/libcli/smb2/notify.c b/source4/libcli/smb2/notify.c index a3bea41eb0..e7c38a27f9 100644 --- a/source4/libcli/smb2/notify.c +++ b/source4/libcli/smb2/notify.c @@ -35,7 +35,7 @@ struct smb2_request *smb2_notify_send(struct smb2_tree *tree, struct smb2_notify req = smb2_request_init_tree(tree, SMB2_OP_NOTIFY, 0x20, false, 0); if (req == NULL) return NULL; - SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0030); + SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0x0030); SSVAL(req->out.body, 0x02, io->in.recursive); SIVAL(req->out.body, 0x04, io->in.buffer_size); diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index 73c74dcfeb..2471fcaa4d 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -28,6 +28,21 @@ #include "libcli/smb2/smb2_calls.h" #include "param/param.h" +/* fill in the bufinfo */ +void smb2_setup_bufinfo(struct smb2_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2; + req->in.bufinfo.align_base = req->in.buffer; + if (req->in.dynamic) { + req->in.bufinfo.data = req->in.dynamic; + req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed; + } else { + req->in.bufinfo.data = NULL; + req->in.bufinfo.data_size = 0; + } +} + /* initialise a smb2 request */ @@ -83,17 +98,17 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_ SIVAL(req->out.hdr, 0, SMB2_MAGIC); SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0); + SSVAL(req->out.hdr, SMB2_HDR_EPOCH, 0); SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0); SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode); - SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0); + SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0); SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0); - SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0); - SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum); + SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0); + SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, req->seqnum); SIVAL(req->out.hdr, SMB2_HDR_PID, 0); SIVAL(req->out.hdr, SMB2_HDR_TID, 0); - SBVAL(req->out.hdr, SMB2_HDR_UID, 0); - memset(req->out.hdr+SMB2_HDR_SIG, 0, 16); + SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0); + memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16); /* set the length of the fixed body part and +1 if there's a dynamic part also */ SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0)); @@ -122,7 +137,7 @@ struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opc body_dynamic_size); if (req == NULL) return NULL; - SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid); + SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, tree->session->uid); SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid); req->session = tree->session; req->tree = tree; @@ -191,6 +206,10 @@ bool smb2_request_is_ok(struct smb2_request *req) */ bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size) { + if (size == 0) { + /* zero bytes is never out of range */ + return false; + } /* be careful with wraparound! */ if (ptr < buf->body || ptr >= buf->body + buf->body_size || @@ -255,7 +274,7 @@ NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ } ofs = SVAL(ptr, 0); size = SVAL(ptr, 2); - if (ofs == 0 || size == 0) { + if (ofs == 0) { *blob = data_blob(NULL, 0); return NT_STATUS_OK; } @@ -295,7 +314,10 @@ NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, return NT_STATUS_BUFFER_TOO_SMALL; } - if (blob.length == 0) { + if (blob.data == NULL) { + if (blob.length != 0) { + return NT_STATUS_INTERNAL_ERROR; + } SSVAL(ptr, 0, 0); SSVAL(ptr, 2, 0); return NT_STATUS_OK; @@ -348,7 +370,10 @@ NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, return NT_STATUS_BUFFER_TOO_SMALL; } - if (blob.length == 0) { + if (blob.data == NULL) { + if (blob.length != 0) { + return NT_STATUS_INTERNAL_ERROR; + } SSVAL(ptr, 0, 0); SIVAL(ptr, 2, 0); return NT_STATUS_OK; @@ -401,7 +426,10 @@ NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, return NT_STATUS_BUFFER_TOO_SMALL; } - if (blob.length == 0) { + if (blob.data == NULL) { + if (blob.length != 0) { + return NT_STATUS_INTERNAL_ERROR; + } SIVAL(ptr, 0, 0); SIVAL(ptr, 4, 0); return NT_STATUS_OK; @@ -454,7 +482,10 @@ NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, return NT_STATUS_BUFFER_TOO_SMALL; } - if (blob.length == 0) { + if (blob.data == NULL) { + if (blob.length != 0) { + return NT_STATUS_INTERNAL_ERROR; + } SIVAL(ptr, 0, 0); SIVAL(ptr, 4, 0); return NT_STATUS_OK; @@ -497,7 +528,7 @@ NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ } ofs = SVAL(ptr, 0); size = IVAL(ptr, 2); - if (ofs == 0 || size == 0) { + if (ofs == 0) { *blob = data_blob(NULL, 0); return NT_STATUS_OK; } @@ -521,7 +552,34 @@ NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ } ofs = IVAL(ptr, 0); size = IVAL(ptr, 4); - if (ofs == 0 || size == 0) { + if (ofs == 0) { + *blob = data_blob(NULL, 0); + return NT_STATUS_OK; + } + if (smb2_oob(buf, buf->hdr + ofs, size)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size); + NT_STATUS_HAVE_NO_MEMORY(blob->data); + return NT_STATUS_OK; +} + +/* + pull a uint16_t ofs/ uint32_t length/blob triple from a data blob + the ptr points to the start of the offset/length pair + + In this varient the uint16_t is padded by an extra 2 bytes, making + the size aligned on 4 byte boundary +*/ +NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob) +{ + uint32_t ofs, size; + if (smb2_oob(buf, ptr, 8)) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + ofs = SVAL(ptr, 0); + size = IVAL(ptr, 4); + if (ofs == 0) { *blob = data_blob(NULL, 0); return NT_STATUS_OK; } @@ -545,7 +603,7 @@ NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ } size = IVAL(ptr, 0); ofs = IVAL(ptr, 4); - if (ofs == 0 || size == 0) { + if (ofs == 0) { *blob = data_blob(NULL, 0); return NT_STATUS_OK; } @@ -572,6 +630,11 @@ NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *me status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob); NT_STATUS_NOT_OK_RETURN(status); + if (blob.data == NULL) { + *str = NULL; + return NT_STATUS_OK; + } + if (blob.length == 0) { char *s; s = talloc_strdup(mem_ctx, ""); @@ -601,10 +664,16 @@ NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf, NTSTATUS status; ssize_t size; - if (strcmp("", str) == 0) { + if (str == NULL) { return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0)); } + if (*str == 0) { + blob.data = str; + blob.length = 0; + return smb2_push_o16s16_blob(buf, ofs, blob); + } + size = convert_string_talloc(buf->buffer, lp_iconv_convenience(global_loadparm), CH_UNIX, CH_UTF16, str, strlen(str), (void **)&blob.data); if (size == -1) { diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c index a784ea65d8..18fe3486a4 100644 --- a/source4/libcli/smb2/session.c +++ b/source4/libcli/smb2/session.c @@ -74,10 +74,12 @@ struct smb2_request *smb2_session_setup_send(struct smb2_session *session, 0x18, true, io->in.secblob.length); if (req == NULL) return NULL; - SBVAL(req->out.hdr, SMB2_HDR_UID, session->uid); - SSVAL(req->out.body, 0x02, io->in._pad); /* pad */ - SIVAL(req->out.body, 0x04, io->in.unknown2); - SIVAL(req->out.body, 0x08, io->in.unknown3); + SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, session->uid); + SCVAL(req->out.body, 0x02, io->in.vc_number); + SCVAL(req->out.body, 0x03, io->in.security_mode); + SIVAL(req->out.body, 0x04, io->in.capabilities); + SIVAL(req->out.body, 0x08, io->in.channel); + SBVAL(req->out.body, 0x10, io->in.previous_sessionid); req->session = session; @@ -86,7 +88,6 @@ struct smb2_request *smb2_session_setup_send(struct smb2_session *session, talloc_free(req); return NULL; } - SBVAL(req->out.body, 0x10, io->in.unknown4); smb2_transport_send(req); @@ -110,8 +111,8 @@ NTSTATUS smb2_session_setup_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, SMB2_CHECK_PACKET_RECV(req, 0x08, true); - io->out._pad = SVAL(req->in.body, 0x02); - io->out.uid = BVAL(req->in.hdr, SMB2_HDR_UID); + io->out.session_flags = SVAL(req->in.body, 0x02); + io->out.uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID); status = smb2_pull_o16s16_blob(&req->in, mem_ctx, req->in.body+0x04, &io->out.secblob); if (!NT_STATUS_IS_OK(status)) { @@ -206,10 +207,11 @@ struct composite_context *smb2_session_setup_spnego_send(struct smb2_session *se c->private_data = state; ZERO_STRUCT(state->io); - state->io.in._pad = 0x0000; - state->io.in.unknown2 = 0x0000000F; - state->io.in.unknown3 = 0x00000000; - state->io.in.unknown4 = 0; /* uint64_t */ + state->io.in.vc_number = 0; + state->io.in.security_mode = 0; + state->io.in.capabilities = 0; + state->io.in.channel = 0; + state->io.in.previous_sessionid = 0; c->status = gensec_set_credentials(session->gensec, credentials); if (!composite_is_ok(c)) return c; diff --git a/source4/libcli/smb2/setinfo.c b/source4/libcli/smb2/setinfo.c index d942568a2d..a6e22d9a68 100644 --- a/source4/libcli/smb2/setinfo.c +++ b/source4/libcli/smb2/setinfo.c @@ -92,6 +92,12 @@ struct smb2_request *smb2_setinfo_file_send(struct smb2_tree *tree, union smb_se ZERO_STRUCT(b); b.in.level = smb2_level; b.in.file.handle = io->generic.in.file.handle; + + /* change levels so the parsers know it is SMB2 */ + if (io->generic.level == RAW_SFILEINFO_RENAME_INFORMATION) { + io->generic.level = RAW_SFILEINFO_RENAME_INFORMATION_SMB2; + } + if (!smb_raw_setfileinfo_passthru(tree, io->generic.level, io, &b.in.blob)) { return NULL; } diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index 33876c6f7c..726df64090 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "libcli/raw/request.h" + struct smb2_options { uint32_t timeout; }; @@ -102,6 +104,9 @@ struct smb2_request_buffer { * this will be moved when some dynamic data is pushed */ uint8_t *dynamic; + + /* this is used to range check and align strings and buffers */ + struct request_bufinfo bufinfo; }; @@ -156,19 +161,20 @@ struct smb2_request { #define SMB2_MIN_SIZE 0x42 -/* offsets into header elements */ +/* offsets into header elements for a sync SMB2 request */ +#define SMB2_HDR_PROTOCOL_ID 0x00 #define SMB2_HDR_LENGTH 0x04 -#define SMB2_HDR_PAD1 0x06 +#define SMB2_HDR_EPOCH 0x06 #define SMB2_HDR_STATUS 0x08 #define SMB2_HDR_OPCODE 0x0c -#define SMB2_HDR_UNKNOWN1 0x0e +#define SMB2_HDR_CREDIT 0x0e #define SMB2_HDR_FLAGS 0x10 -#define SMB2_HDR_CHAIN_OFFSET 0x14 -#define SMB2_HDR_SEQNUM 0x18 +#define SMB2_HDR_NEXT_COMMAND 0x14 +#define SMB2_HDR_MESSAGE_ID 0x18 #define SMB2_HDR_PID 0x20 #define SMB2_HDR_TID 0x24 -#define SMB2_HDR_UID 0x28 /* 64 bit */ -#define SMB2_HDR_SIG 0x30 /* guess ... */ +#define SMB2_HDR_SESSION_ID 0x28 +#define SMB2_HDR_SIGNATURE 0x30 /* 16 bytes */ #define SMB2_HDR_BODY 0x40 /* SMB2 opcodes */ @@ -194,6 +200,59 @@ struct smb2_request { #define SMB2_MAGIC 0x424D53FE /* 0xFE 'S' 'M' 'B' */ +/* the dialect we support */ +#define SMB2_DIALECT_REVISION 0x202 + +/* SMB2 negotiate security_mode */ +#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01 +#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02 + +/* SMB2 capabilities - only 1 so far. I'm sure more will be added */ +#define SMB2_CAP_DFS 0x0 +/* so we can spot new caps as added */ +#define SMB2_CAP_ALL SMB2_CAP_DFS + +/* SMB2 share flags */ +#define SMB2_SHAREFLAG_MANUAL_CACHING 0x0000 +#define SMB2_SHAREFLAG_AUTO_CACHING 0x0010 +#define SMB2_SHAREFLAG_VDO_CACHING 0x0020 +#define SMB2_SHAREFLAG_NO_CACHING 0x0030 +#define SMB2_SHAREFLAG_DFS 0x0001 +#define SMB2_SHAREFLAG_DFS_ROOT 0x0002 +#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x0100 +#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x0200 +#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x0400 +#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x0800 +#define SMB2_SHAREFLAG_ALL 0x0F33 + +/* SMB2 create security flags */ +#define SMB2_SECURITY_DYNAMIC_TRACKING 0x01 +#define SMB2_SECURITY_EFFECTIVE_ONLY 0x02 + +/* SMB2 requested oplock levels */ +#define SMB2_OPLOCK_LEVEL_NONE 0x00 +#define SMB2_OPLOCK_LEVEL_II 0x01 +#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08 +#define SMB2_OPLOCK_LEVEL_BATCH 0x09 + +/* SMB2 impersonation levels */ +#define SMB2_IMPERSONATION_ANONYMOUS 0x00 +#define SMB2_IMPERSONATION_IDENTIFICATION 0x01 +#define SMB2_IMPERSONATION_IMPERSONATION 0x02 +#define SMB2_IMPERSONATION_DELEGATE 0x03 + +/* SMB2 create tags */ +#define SMB2_CREATE_TAG_EXTA "ExtA" +#define SMB2_CREATE_TAG_MXAC "MxAc" +#define SMB2_CREATE_TAG_SECD "SecD" +#define SMB2_CREATE_TAG_DHNQ "DHnQ" +#define SMB2_CREATE_TAG_DHNC "DHnC" +#define SMB2_CREATE_TAG_ALSI "AlSi" +#define SMB2_CREATE_TAG_TWRP "TWrp" +#define SMB2_CREATE_TAG_QFID "QFid" + + + /* check that a body has the expected size */ diff --git a/source4/libcli/smb2/smb2_calls.h b/source4/libcli/smb2/smb2_calls.h index 6a551da4ae..f66236af30 100644 --- a/source4/libcli/smb2/smb2_calls.h +++ b/source4/libcli/smb2/smb2_calls.h @@ -23,30 +23,31 @@ struct smb2_negprot { struct { - /* static body buffer 38 (0x26) bytes */ - /* uint16_t buffer_code; 0x24 (why?) */ - uint16_t unknown1; /* 0x0001 */ - uint8_t unknown2[32]; /* all zero */ - uint16_t unknown3; /* 0x00000 */ + uint16_t dialect_count; /* size of dialects array */ + uint16_t security_mode; /* 0==signing disabled + 1==signing enabled */ + uint16_t reserved; + uint32_t capabilities; + struct GUID client_guid; + NTTIME start_time; + uint16_t *dialects; } in; struct { /* static body buffer 64 (0x40) bytes */ /* uint16_t buffer_code; 0x41 = 0x40 + 1 */ - uint16_t _pad; - uint32_t unknown2; /* 0x06 */ - uint8_t sessid[16]; - uint32_t unknown3; /* 0x0d */ - uint16_t unknown4; /* 0x00 */ - uint32_t unknown5; /* 0x01 */ - uint32_t unknown6; /* 0x01 */ - uint16_t unknown7; /* 0x01 */ - NTTIME current_time; - NTTIME boot_time; + uint16_t security_mode; /* SMB2_NEGOTIATE_SIGNING_* */ + uint16_t dialect_revision; + uint16_t reserved; + struct GUID server_guid; + uint32_t capabilities; + uint32_t max_transact_size; + uint32_t max_read_size; + uint32_t max_write_size; + NTTIME system_time; + NTTIME server_start_time; /* uint16_t secblob_ofs */ /* uint16_t secblob_size */ - uint32_t unknown9; /* 0x204d4c20 */ - - /* dynamic body buffer */ + uint32_t reserved2; DATA_BLOB secblob; } out; }; @@ -55,6 +56,13 @@ struct smb2_negprot { #define SMB2_GETINFO_FILE 0x01 #define SMB2_GETINFO_FS 0x02 #define SMB2_GETINFO_SECURITY 0x03 +#define SMB2_GETINFO_QUOTA 0x04 + +#define SMB2_GETINFO_ADD_OWNER_SECURITY 0x01 +#define SMB2_GETINFO_ADD_GROUP_SECURITY 0x02 +#define SMB2_GETINFO_ADD_DACL_SECURITY 0x04 +#define SMB2_GETINFO_ADD_SACL_SECURITY 0x08 +#define SMB2_GETINFO_ADD_LABEL_SECURITY 0x10 /* NOTE! the getinfo fs and file levels exactly match up with the 'passthru' SMB levels, which are levels >= 1000. The SMB2 client @@ -63,14 +71,17 @@ struct smb2_negprot { struct smb2_getinfo { struct { /* static body buffer 40 (0x28) bytes */ - /* uint16_t buffer_code; 0x29 = 0x28 + 1 (why???) */ - uint16_t level; - uint32_t max_response_size; - uint32_t unknown1; - uint32_t unknown2; - uint32_t flags; /* level specific */ - uint32_t flags2; /* used by all_eas level */ + /* uint16_t buffer_code; 0x29 = 0x28 + 1 */ + uint8_t info_type; + uint8_t info_class; + uint32_t output_buffer_length; + /* uint32_t input_buffer_offset; */ + uint32_t reserved; + uint32_t input_buffer_length; + uint32_t additional_information; /* SMB2_GETINFO_ADD_* */ + uint32_t getinfo_flags; /* level specific */ union smb_handle file; + DATA_BLOB blob; } in; struct { diff --git a/source4/libcli/smb2/tcon.c b/source4/libcli/smb2/tcon.c index ad1ba4c92d..db35669d41 100644 --- a/source4/libcli/smb2/tcon.c +++ b/source4/libcli/smb2/tcon.c @@ -56,9 +56,9 @@ struct smb2_request *smb2_tree_connect_send(struct smb2_tree *tree, 0x08, true, 0); if (req == NULL) return NULL; - SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid); + SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, tree->session->uid); - SSVAL(req->out.body, 0x02, io->in.unknown1); + SSVAL(req->out.body, 0x02, io->in.reserved); status = smb2_push_o16s16_string(&req->out, 0x04, io->in.path); if (!NT_STATUS_IS_OK(status)) { talloc_free(req); @@ -85,10 +85,18 @@ NTSTATUS smb2_tree_connect_recv(struct smb2_request *req, struct smb2_tree_conne io->out.tid = IVAL(req->in.hdr, SMB2_HDR_TID); - io->out.unknown1 = SVAL(req->in.body, 0x02); - io->out.unknown2 = IVAL(req->in.body, 0x04); - io->out.unknown3 = IVAL(req->in.body, 0x08); + io->out.share_type = CVAL(req->in.body, 0x02); + io->out.reserved = CVAL(req->in.body, 0x03); + io->out.flags = IVAL(req->in.body, 0x04); + io->out.capabilities= IVAL(req->in.body, 0x08); io->out.access_mask = IVAL(req->in.body, 0x0C); + + if (io->out.capabilities & ~SMB2_CAP_ALL) { + DEBUG(0,("Unknown capabilities mask 0x%x\n", io->out.capabilities)); + } + if (io->out.flags & ~SMB2_SHAREFLAG_ALL) { + DEBUG(0,("Unknown tcon shareflag 0x%x\n", io->out.flags)); + } return smb2_request_destroy(req); } diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index 83e9436a58..1d601fdbfe 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -167,7 +167,7 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) } flags = IVAL(hdr, SMB2_HDR_FLAGS); - seqnum = BVAL(hdr, SMB2_HDR_SEQNUM); + seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); /* match the incoming request against the list of pending requests */ for (req=transport->pending_recv; req; req=req->next) { @@ -216,6 +216,8 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) } } + smb2_setup_bufinfo(req); + DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", (long long)req->seqnum)); dump_data(5, req->in.body, req->in.body_size); |