From c4541904d4d0a9c81454a4b2fbc23b7402feeda4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 31 Mar 2015 16:15:59 -0700 Subject: [PATCH 1/2] s3: Refactor smbd_smb2_request_process_negprot Breakout smb2_protocol_dialect_match to support future work in fsctl_validate_neg_info. Back port of 6221937acac7017dee397d1c9846236d9fd5f613 written by Ira Cooper and signed off by Stefan Metzmacher Fixes bug #11187 - Mac OS X 10.10.x fails Validate Negotiate Request to 4.1.x https://bugzilla.samba.org/show_bug.cgi?id=11187 Signed-off-by: Jeremy Allison --- source3/smbd/globals.h | 3 ++ source3/smbd/smb2_negprot.c | 114 ++++++++++++++++---------------------------- 2 files changed, 43 insertions(+), 74 deletions(-) diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 1286ced..0942e46 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -258,6 +258,9 @@ NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req, NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req, size_t expected_body_size); +enum protocol_types smbd_smb2_protocol_dialect_match(const uint8_t *indyn, + const int dialect_count, + uint16_t *dialect); NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req); NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *req); NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req); diff --git a/source3/smbd/smb2_negprot.c b/source3/smbd/smb2_negprot.c index 963a557..0cf5c8d 100644 --- a/source3/smbd/smb2_negprot.c +++ b/source3/smbd/smb2_negprot.c @@ -82,6 +82,43 @@ void reply_smb20ff(struct smb_request *req, uint16_t choice) reply_smb20xx(req, SMB2_DIALECT_REVISION_2FF); } +enum protocol_types smbd_smb2_protocol_dialect_match(const uint8_t *indyn, + const int dialect_count, + uint16_t *dialect) +{ + struct { + enum protocol_types proto; + uint16_t dialect; + } pd[] = { + { PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300 }, + { PROTOCOL_SMB2_24, SMB2_DIALECT_REVISION_224 }, + { PROTOCOL_SMB2_22, SMB2_DIALECT_REVISION_222 }, + { PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210 }, + { PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202 }, + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(pd); i ++) { + size_t c = 0; + + if (lp_srv_maxprotocol() < pd[i].proto) { + continue; + } + if (lp_srv_minprotocol() > pd[i].proto) { + continue; + } + + for (c = 0; c < dialect_count; c++) { + *dialect = SVAL(indyn, c*2); + if (*dialect == pd[i].dialect) { + return pd[i].proto; + } + } + } + + return PROTOCOL_NONE; +} + NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) { NTSTATUS status; @@ -138,80 +175,9 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req) } indyn = SMBD_SMB2_IN_DYN_PTR(req); - for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { - if (lp_srv_maxprotocol() < PROTOCOL_SMB3_00) { - break; - } - if (lp_srv_minprotocol() > PROTOCOL_SMB3_00) { - break; - } - - dialect = SVAL(indyn, c*2); - if (dialect == SMB3_DIALECT_REVISION_300) { - protocol = PROTOCOL_SMB3_00; - break; - } - } - - for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { - if (lp_srv_maxprotocol() < PROTOCOL_SMB2_24) { - break; - } - if (lp_srv_minprotocol() > PROTOCOL_SMB2_24) { - break; - } - - dialect = SVAL(indyn, c*2); - if (dialect == SMB2_DIALECT_REVISION_224) { - protocol = PROTOCOL_SMB2_24; - break; - } - } - - for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { - if (lp_srv_maxprotocol() < PROTOCOL_SMB2_22) { - break; - } - if (lp_srv_minprotocol() > PROTOCOL_SMB2_22) { - break; - } - - dialect = SVAL(indyn, c*2); - if (dialect == SMB2_DIALECT_REVISION_222) { - protocol = PROTOCOL_SMB2_22; - break; - } - } - - for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { - if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) { - break; - } - if (lp_srv_minprotocol() > PROTOCOL_SMB2_10) { - break; - } - - dialect = SVAL(indyn, c*2); - if (dialect == SMB2_DIALECT_REVISION_210) { - protocol = PROTOCOL_SMB2_10; - break; - } - } - - for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { - if (lp_srv_maxprotocol() < PROTOCOL_SMB2_02) { - break; - } - if (lp_srv_minprotocol() > PROTOCOL_SMB2_02) { - break; - } - - dialect = SVAL(indyn, c*2); - if (dialect == SMB2_DIALECT_REVISION_202) { - protocol = PROTOCOL_SMB2_02; - break; - } - } + protocol = smbd_smb2_protocol_dialect_match(indyn, + dialect_count, + &dialect); for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) { if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) { -- 2.2.0.rc0.207.ga3a616c From 42767811362dd61fbf73c6d9ed59eaf06c067c6c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 31 Mar 2015 16:20:51 -0700 Subject: [PATCH 2/2] s3: Fix fsctl_validate_neg_info to pass MS compliance suite. It turns out that all the client and server need to agree on is what protocol should have been negotiated. If they disagree, they should disconnect. The contents of the list of protocols used during negotiate and during FSCTL_VALIDATE_NEGOTIATE_INFO do not need to match. Back-port of patch 439de096ae0e1c1b8812fa202f5eba7a891d7a0a written by Ira Cooper and reviewed by Stefan Metzmacher . Fixes bug #11187 - Mac OS X 10.10.x fails Validate Negotiate Request to 4.1.x https://bugzilla.samba.org/show_bug.cgi?id=11187 Signed-off-by: Jeremy Allison --- source3/smbd/smb2_ioctl_network_fs.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/source3/smbd/smb2_ioctl_network_fs.c b/source3/smbd/smb2_ioctl_network_fs.c index 49c2715..96d11fd 100644 --- a/source3/smbd/smb2_ioctl_network_fs.c +++ b/source3/smbd/smb2_ioctl_network_fs.c @@ -341,9 +341,10 @@ static NTSTATUS fsctl_validate_neg_info(TALLOC_CTX *mem_ctx, struct GUID in_guid; uint16_t in_security_mode; uint16_t in_num_dialects; - uint16_t i; + uint16_t dialect; DATA_BLOB out_guid_blob; NTSTATUS status; + enum protocol_types protocol = PROTOCOL_NONE; if (in_input->length < 0x18) { return NT_STATUS_INVALID_PARAMETER; @@ -367,20 +368,25 @@ static NTSTATUS fsctl_validate_neg_info(TALLOC_CTX *mem_ctx, return status; } - if (in_num_dialects != conn->smb2.client.num_dialects) { + /* + * From: [MS-SMB2] + * 3.3.5.15.12 Handling a Validate Negotiate Info Request + * + * The server MUST determine the greatest common dialect + * between the dialects it implements and the Dialects array + * of the VALIDATE_NEGOTIATE_INFO request. If no dialect is + * matched, or if the value is not equal to Connection.Dialect, + * the server MUST terminate the transport connection + * and free the Connection object. + */ + protocol = smbd_smb2_protocol_dialect_match(in_input->data + 0x18, + in_num_dialects, + &dialect); + if (conn->protocol != protocol) { *disconnect = true; return NT_STATUS_ACCESS_DENIED; } - for (i=0; i < in_num_dialects; i++) { - uint16_t v = SVAL(in_input->data, 0x18 + i*2); - - if (conn->smb2.client.dialects[i] != v) { - *disconnect = true; - return NT_STATUS_ACCESS_DENIED; - } - } - if (GUID_compare(&in_guid, &conn->smb2.client.guid) != 0) { *disconnect = true; return NT_STATUS_ACCESS_DENIED; -- 2.2.0.rc0.207.ga3a616c