From a7b7ece7aa3c8288f3373e8101f3d5abca8fac39 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Mar 2010 19:48:56 +0100 Subject: [PATCH 01/20] libcli/util: add more NT_STATUS_RPC_* defines metze (cherry picked from commit 6a1f8e67eb6e15bbafca570ac9b3714681025a1f) --- libcli/util/ntstatus.h | 15 +++++++++++---- source4/libcli/util/nterr.c | 8 ++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h index 1025f47..d6191e4 100644 --- a/libcli/util/ntstatus.h +++ b/libcli/util/ntstatus.h @@ -604,9 +604,14 @@ typedef uint32_t NTSTATUS; #define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE) /* scheduler */ #define NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x20004) #define NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX NT_STATUS(0xC0000000 | 0x20026) -#define NT_STATUS_RPC_NT_CALL_FAILED NT_STATUS(0xC0000000 | 0x2001B) -#define NT_STATUS_RPC_NT_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x2001D) -#define NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE NT_STATUS(0xC0000000 | 0x2002E) +#define NT_STAUTS_RPC_UNKNOWN_IF NT_STATUS(0xC0000000 | 0x20012) +#define NT_STATUS_RPC_CALL_FAILED NT_STATUS(0xC0000000 | 0x2001B) +#define NT_STATUS_RPC_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x2001D) +#define NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE NT_STATUS(0xC0000000 | 0x2002E) +#define NT_STATUS_RPC_CANNOT_SUPPORT NT_STATUS(0xC0000000 | 0x20041) +#define NT_STATUS_RPC_SS_CONTEXT_MISMATCH NT_STATUS(0xC0000000 | 0x30005) +#define NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE NT_STATUS(0xC000000 | 0x3000A) +#define NT_STATUS_RPC_BAD_STUB_DATA NT_STATUS(0xC0000000 | 0x3000C) #define NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS NT_STATUS(0xC0000000 | 0x2071) #define NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION NT_STATUS(0xC0000000 | 0x00002177) @@ -699,6 +704,8 @@ extern bool ntstatus_check_dos_mapping; #define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF2000000) #define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000) -#define NT_STATUS_RPC_CANNOT_SUPPORT NT_STATUS(0xC0000000 | 0x20041) +#define NT_STATUS_IS_RPC(status) \ + (((NT_STATUS_V(status) & 0xFFFF) == 0xC0020000) || \ + ((NT_STATUS_V(status) & 0xFFFF) == 0xC0030000)) #endif /* _NTSTATUS_H */ diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c index 75bbbde..c9466dd 100644 --- a/source4/libcli/util/nterr.c +++ b/source4/libcli/util/nterr.c @@ -546,6 +546,14 @@ static const nt_err_code_struct nt_errs[] = { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES }, { "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED }, { "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX }, + { "NT_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF }, + { "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED }, + { "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR }, + { "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE }, + { "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT }, + { "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", NT_STATUS_RPC_SS_CONTEXT_MISMATCH }, + { "NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE", NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE }, + { "NT_STATUS_RPC_BAD_STUB_DATA", NT_STATUS_RPC_BAD_STUB_DATA }, { "NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED", NT_STATUS_CURRENT_DOMAIN_NOT_ALLOWED }, { "NT_STATUS_OBJECTID_NOT_FOUND", NT_STATUS_OBJECTID_NOT_FOUND }, { "NT_STATUS_DOWNGRADE_DETECTED", NT_STATUS_DOWNGRADE_DETECTED }, -- 1.7.9.5 From 46f1a08ab4348618c973a4ec16eee7e0c0c14fee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 18 Mar 2010 15:27:05 +0100 Subject: [PATCH 02/20] s3:libsmb/nterr.c: fix/add NT_STATUS_RPC_* codes metze (cherry picked from commit 421a926237f94ebdb90aaf0cf7678a9804bd5cdc) --- source3/libsmb/nterr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c index 197d5bd..52dc5b8 100644 --- a/source3/libsmb/nterr.c +++ b/source3/libsmb/nterr.c @@ -539,11 +539,16 @@ static const nt_err_code_struct nt_errs[] = { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES }, { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED }, { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES }, - { "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT }, - { "NT_STATUS_RPC_NT_CALL_FAILED", NT_STATUS_RPC_NT_CALL_FAILED }, - { "NT_STATUS_RPC_NT_PROTOCOL_ERROR", NT_STATUS_RPC_NT_PROTOCOL_ERROR }, - { "NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_NT_PROCNUM_OUT_OF_RANGE }, { "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED }, + { "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX }, + { "NT_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF }, + { "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED }, + { "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR }, + { "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE }, + { "NT_STATUS_RPC_CANNOT_SUPPORT", NT_STATUS_RPC_CANNOT_SUPPORT }, + { "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", NT_STATUS_RPC_SS_CONTEXT_MISMATCH }, + { "NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE", NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE }, + { "NT_STATUS_RPC_BAD_STUB_DATA", NT_STATUS_RPC_BAD_STUB_DATA }, { NULL, NT_STATUS(0) } }; -- 1.7.9.5 From a4749747d364c795cac1284e40e70ed20b58507b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Fri, 19 Mar 2010 09:30:36 +0100 Subject: [PATCH 03/20] error_codes: fix NT_STATUS_RPC_UNKNOWN_IF typo. Metze, please check. Guenther (cherry picked from commit e7cc45cb140e1df5731619ae09af6c10b8f9fffa) --- libcli/util/ntstatus.h | 2 +- source3/libsmb/nterr.c | 2 +- source4/libcli/util/nterr.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h index d6191e4..2989764 100644 --- a/libcli/util/ntstatus.h +++ b/libcli/util/ntstatus.h @@ -604,7 +604,7 @@ typedef uint32_t NTSTATUS; #define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE) /* scheduler */ #define NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED NT_STATUS(0xC0000000 | 0x20004) #define NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX NT_STATUS(0xC0000000 | 0x20026) -#define NT_STAUTS_RPC_UNKNOWN_IF NT_STATUS(0xC0000000 | 0x20012) +#define NT_STATUS_RPC_UNKNOWN_IF NT_STATUS(0xC0000000 | 0x20012) #define NT_STATUS_RPC_CALL_FAILED NT_STATUS(0xC0000000 | 0x2001B) #define NT_STATUS_RPC_PROTOCOL_ERROR NT_STATUS(0xC0000000 | 0x2001D) #define NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE NT_STATUS(0xC0000000 | 0x2002E) diff --git a/source3/libsmb/nterr.c b/source3/libsmb/nterr.c index 52dc5b8..ae41a9b 100644 --- a/source3/libsmb/nterr.c +++ b/source3/libsmb/nterr.c @@ -541,7 +541,7 @@ static const nt_err_code_struct nt_errs[] = { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES }, { "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED }, { "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX }, - { "NT_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF }, + { "NT_STATUS_RPC_UNKNOWN_IF", NT_STATUS_RPC_UNKNOWN_IF }, { "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED }, { "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR }, { "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE }, diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c index c9466dd..0764a28 100644 --- a/source4/libcli/util/nterr.c +++ b/source4/libcli/util/nterr.c @@ -546,7 +546,7 @@ static const nt_err_code_struct nt_errs[] = { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES }, { "NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED", NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED }, { "NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX", NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX }, - { "NT_STAUTS_RPC_UNKNOWN_IF", NT_STAUTS_RPC_UNKNOWN_IF }, + { "NT_STATUS_RPC_UNKNOWN_IF", NT_STATUS_RPC_UNKNOWN_IF }, { "NT_STATUS_RPC_CALL_FAILED", NT_STATUS_RPC_CALL_FAILED }, { "NT_STATUS_RPC_PROTOCOL_ERROR", NT_STATUS_RPC_PROTOCOL_ERROR }, { "NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE", NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE }, -- 1.7.9.5 From 131d5d789d5ed5550ee6060dd1cc805753a42395 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 25 Sep 2013 23:25:12 +0200 Subject: [PATCH 04/20] CVE-2013-4408:s3:rpc_client: verify frag_len at least contains the header size Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source3/rpc_client/cli_pipe.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 0298f79..609f209 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -455,6 +455,12 @@ static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli, return NT_STATUS_BUFFER_TOO_SMALL; } + if (prhdr->frag_len < RPC_HEADER_LEN) { + DEBUG(0, ("parse_rpc_header: Server sent fraglen %d," + " < RPC_HEADER_LEN\n", (int)prhdr->frag_len)); + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + if (prhdr->frag_len > cli->max_recv_frag) { DEBUG(0, ("cli_pipe_get_current_pdu: Server sent fraglen %d," " we only allow %d\n", (int)prhdr->frag_len, -- 1.7.9.5 From b968b39f4d874b6b7fbc14bd833ebdc33a13ab76 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 24 Sep 2013 05:03:40 +0200 Subject: [PATCH 05/20] CVE-2013-4408:s4:rpc_server: check for invalid frag_len within dcerpc_read_ncacn_packet_done() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/rpc_server/service_rpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c index ea41689..ca3b3cb 100644 --- a/source4/rpc_server/service_rpc.c +++ b/source4/rpc_server/service_rpc.c @@ -303,6 +303,11 @@ static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq) return; } + if (state->pkt->frag_length != state->buffer.length) { + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + tevent_req_done(req); } -- 1.7.9.5 From e86230c9175bb4eefbecf0d36dffaf15c8254ce8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 24 Sep 2013 05:03:40 +0200 Subject: [PATCH 06/20] CVE-2013-4408:s4:rpc_server: check for invalid frag_len within dcerpc_read_ncacn_packet_next_vector() We should do this explicit instead of relying on tstream_readv_pdu_ask_for_next_vector() to catch the overflow. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/rpc_server/service_rpc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source4/rpc_server/service_rpc.c b/source4/rpc_server/service_rpc.c index ca3b3cb..1c9c76a 100644 --- a/source4/rpc_server/service_rpc.c +++ b/source4/rpc_server/service_rpc.c @@ -232,6 +232,15 @@ static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream, ofs = state->buffer.length; + if (frag_len < ofs) { + /* + * something is wrong, let the caller deal with it + */ + *_vector = NULL; + *_count = 0; + return 0; + } + state->buffer.data = talloc_realloc(state, state->buffer.data, uint8_t, frag_len); -- 1.7.9.5 From 0a9482c35325a2d3e3d915274b997dfb6812a4dd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 25 Sep 2013 23:25:12 +0200 Subject: [PATCH 07/20] CVE-2013-4408:s4:dcerpc: check for invalid frag_len in ncacn_pull() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/librpc/rpc/dcerpc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 87d4438..277c7c6 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -213,6 +213,10 @@ static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_ return ndr_map_error2ntstatus(ndr_err); } + if (pkt->frag_length != blob->length) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + return NT_STATUS_OK; } -- 1.7.9.5 From 27ad9277415735c6ab3ec174e02826d85f8b8d91 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 25 Sep 2013 23:25:12 +0200 Subject: [PATCH 08/20] CVE-2013-4408:s4:dcerpc_smb: check for invalid frag_len in send_read_request_continue() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/librpc/rpc/dcerpc_smb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index f4e6b8c..909e7e4 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -159,6 +159,12 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO } else { uint32_t frag_length = blob->length>=16? dcerpc_get_frag_length(blob):0x2000; + + if (frag_length < state->data.length) { + talloc_free(state); + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + state->received = blob->length; state->data = data_blob_talloc(state, NULL, frag_length); if (!state->data.data) { -- 1.7.9.5 From 0c87e0818834f9b982ad824a8952803e1ddfdf09 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 25 Sep 2013 23:25:12 +0200 Subject: [PATCH 09/20] CVE-2013-4408:s4:dcerpc_smb2: check for invalid frag_len in send_read_request_continue() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/librpc/rpc/dcerpc_smb2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c index fbd8476..d322a0b 100644 --- a/source4/librpc/rpc/dcerpc_smb2.c +++ b/source4/librpc/rpc/dcerpc_smb2.c @@ -169,6 +169,12 @@ static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLO if (state->data.length >= 16) { uint16_t frag_length = dcerpc_get_frag_length(&state->data); + + if (frag_length < state->data.length) { + talloc_free(state); + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + io.in.length = frag_length - state->data.length; } else { io.in.length = 0x2000; -- 1.7.9.5 From 6b8495ca22252af01fc0a90c67b5950210c50380 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 24 Sep 2013 05:03:40 +0200 Subject: [PATCH 10/20] CVE-2013-4408:s4:dcerpc_sock: check for invalid frag_len within sock_complete_packet() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/librpc/rpc/dcerpc_sock.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c index d8bd6d2..f70880f 100644 --- a/source4/librpc/rpc/dcerpc_sock.c +++ b/source4/librpc/rpc/dcerpc_sock.c @@ -101,6 +101,12 @@ static NTSTATUS sock_complete_packet(void *private_data, DATA_BLOB blob, size_t return STATUS_MORE_ENTRIES; } *size = dcerpc_get_frag_length(&blob); + if (*size < blob.length) { + /* + * something is wrong, let the caller deal with it + */ + *size = blob.length; + } if (*size > blob.length) { return STATUS_MORE_ENTRIES; } -- 1.7.9.5 From 1232bf297d6d618cf31b590900c707978571fd1e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Oct 2013 14:17:49 +0200 Subject: [PATCH 11/20] CVE-2013-4408:async_sock: add some overflow detection to read_packet_handler() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- lib/async_req/async_sock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c index 18adb42..ab7f884 100644 --- a/lib/async_req/async_sock.c +++ b/lib/async_req/async_sock.c @@ -594,6 +594,11 @@ static void read_packet_handler(struct tevent_context *ev, return; } + if (total + more < total) { + tevent_req_error(req, EMSGSIZE); + return; + } + tmp = talloc_realloc(state, state->buf, uint8_t, total+more); if (tevent_req_nomem(tmp, req)) { return; -- 1.7.9.5 From 2abfeaeeff334bec2bcfe7db8af3d122847a985e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 9 Oct 2013 11:16:08 -0700 Subject: [PATCH 12/20] CVE-2013-4408:s3:rpc_server: ensure frag_len is at least as large as RPC_HEADER_LEN. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- source3/rpc_server/srv_pipe_hnd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index 83f27fe..ca14886 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -1311,6 +1311,10 @@ static ssize_t rpc_frag_more_fn(uint8_t *buf, size_t buflen, void *priv) return -1; } + if (hdr.frag_len < RPC_HEADER_LEN) { + return -1; + } + return (hdr.frag_len - RPC_HEADER_LEN); } -- 1.7.9.5 From 0c04a663f2683a5e8334400bc775fd81664dc07b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 9 Oct 2013 11:20:53 -0700 Subject: [PATCH 13/20] CVE-2013-4408:s3:rpc_server: check a pipe with PIPE_AUTH_TYPE_NONE does not receive auth_len. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- source3/rpc_server/srv_pipe_hnd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index ca14886..54f4208 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -388,6 +388,11 @@ static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) switch(p->auth.auth_type) { case PIPE_AUTH_TYPE_NONE: + if (p->hdr.auth_len != 0) { + DEBUG(0,("process_request_pdu: PIPE_AUTH_TYPE_NONE given auth_data.\n")); + set_incoming_fault(p); + return False; + } break; case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: -- 1.7.9.5 From db6ab8b22588b9c483fe9d0bf5f4d52f2c5273c1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 16 Oct 2013 10:45:02 -0700 Subject: [PATCH 14/20] CVE-2013-4408:s3:rpc_server: for auth_level DCERPC_AUTH_LEVEL_NONE or DCERPC_AUTH_LEVEL_CONNECT auth_len must be zero. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- source3/rpc_server/srv_pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 9c80fa2..893fa1b 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -2089,7 +2089,8 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in, *pstatus = NT_STATUS_OK; if (p->auth.auth_level == DCERPC_AUTH_LEVEL_NONE || p->auth.auth_level == DCERPC_AUTH_LEVEL_CONNECT) { - return True; + /* For these auth_levels the auth_len must be zero. */ + return (auth_len == 0); } if (!a) { -- 1.7.9.5 From 0f8f75562aeba87c0d5bdca2c710f704dcabb586 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 9 Oct 2013 11:23:38 -0700 Subject: [PATCH 15/20] CVE-2013-4408:s3:rpc_server: integer wrap check on data_len. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- source3/rpc_server/srv_pipe_hnd.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index 54f4208..9c0546a 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -362,8 +362,7 @@ static void free_pipe_context(pipes_struct *p) static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) { uint32 ss_padding_len = 0; - size_t data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - - (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; + size_t data_len = 0; if(!p->pipe_bound) { DEBUG(0,("process_request_pdu: rpc request with no bind.\n")); @@ -422,6 +421,16 @@ static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) return False; } + data_len = p->hdr.frag_len - RPC_HEADER_LEN - RPC_HDR_REQ_LEN - + (p->hdr.auth_len ? RPC_HDR_AUTH_LEN : 0) - p->hdr.auth_len; + + if (data_len > p->hdr.frag_len) { + DEBUG(0,("process_request_pdu: rpc frag size too small (%u)\n", + (unsigned int)p->hdr.frag_len)); + set_incoming_fault(p); + return False; + } + /* Now we've done the sign/seal we can remove any padding data. */ if (data_len > ss_padding_len) { data_len -= ss_padding_len; -- 1.7.9.5 From 1cfcb587e27c807dd07644b0868f619cf223f5ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 16 Oct 2013 14:17:49 +0200 Subject: [PATCH 16/20] CVE-2013-4408:s3:util_tsock: add some overflow detection to tstream_read_packet_done() Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source3/lib/util_tsock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/lib/util_tsock.c b/source3/lib/util_tsock.c index 7588857..9b48f69 100644 --- a/source3/lib/util_tsock.c +++ b/source3/lib/util_tsock.c @@ -108,6 +108,11 @@ static void tstream_read_packet_done(struct tevent_req *subreq) return; } + if (total + more < total) { + tevent_req_error(req, EMSGSIZE); + return; + } + tmp = talloc_realloc(state, state->buf, uint8_t, total+more); if (tevent_req_nomem(tmp, req)) { return; -- 1.7.9.5 From d756dae474213d37dac08fe0951872dd5a76b37d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 24 Oct 2013 11:58:48 -0700 Subject: [PATCH 17/20] CVE-2013-4408:s3:Ensure we always check call_id when validating an RPC reply. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- source3/rpc_client/cli_pipe.c | 56 +++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 609f209..fe1b3fe 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -443,7 +443,8 @@ static NTSTATUS rpc_write_recv(struct tevent_req *req) static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli, struct rpc_hdr_info *prhdr, - prs_struct *pdu) + prs_struct *pdu, + uint32_t call_id) { /* * This next call sets the endian bit correctly in current_pdu. We @@ -468,6 +469,14 @@ static NTSTATUS parse_rpc_header(struct rpc_pipe_client *cli, return NT_STATUS_BUFFER_TOO_SMALL; } + if (prhdr->call_id != call_id) { + DEBUG(0, ("parse_rpc_header: call_id was %u," + " expected %u\n", + (unsigned int)prhdr->call_id, + (unsigned int)call_id)); + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + return NT_STATUS_OK; } @@ -480,6 +489,7 @@ struct get_complete_frag_state { struct event_context *ev; struct rpc_pipe_client *cli; struct rpc_hdr_info *prhdr; + uint32_t call_id; prs_struct *pdu; }; @@ -489,6 +499,7 @@ static void get_complete_frag_got_rest(struct tevent_req *subreq); static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, + uint32_t call_id, struct rpc_hdr_info *prhdr, prs_struct *pdu) { @@ -505,6 +516,7 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->cli = cli; state->prhdr = prhdr; + state->call_id = call_id; state->pdu = pdu; pdu_len = prs_data_size(pdu); @@ -527,7 +539,7 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx, return req; } - status = parse_rpc_header(cli, prhdr, pdu); + status = parse_rpc_header(cli, prhdr, pdu, call_id); if (!NT_STATUS_IS_OK(status)) { goto post_status; } @@ -578,7 +590,8 @@ static void get_complete_frag_got_header(struct tevent_req *subreq) return; } - status = parse_rpc_header(state->cli, state->prhdr, state->pdu); + status = parse_rpc_header(state->cli, state->prhdr, state->pdu, + state->call_id); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; @@ -1321,6 +1334,7 @@ struct rpc_api_pipe_state { struct event_context *ev; struct rpc_pipe_client *cli; uint8_t expected_pkt_type; + uint32_t call_id; prs_struct incoming_frag; struct rpc_hdr_info rhdr; @@ -1343,7 +1357,8 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct rpc_pipe_client *cli, prs_struct *data, /* Outgoing PDU */ - uint8_t expected_pkt_type) + uint8_t expected_pkt_type, + uint32_t call_id) { struct tevent_req *req, *subreq; struct rpc_api_pipe_state *state; @@ -1357,6 +1372,7 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->cli = cli; state->expected_pkt_type = expected_pkt_type; + state->call_id = call_id; state->incoming_pdu_offset = 0; prs_init_empty(&state->incoming_frag, state, UNMARSHALL); @@ -1440,6 +1456,7 @@ static void rpc_api_pipe_trans_done(struct tevent_req *subreq) /* Ensure we have enough data for a pdu. */ subreq = get_complete_frag_send(state, state->ev, state->cli, + state->call_id, &state->rhdr, &state->incoming_frag); if (tevent_req_nomem(subreq, req)) { return; @@ -1531,6 +1548,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq) } subreq = get_complete_frag_send(state, state->ev, state->cli, + state->call_id, &state->rhdr, &state->incoming_frag); if (tevent_req_nomem(subreq, req)) { return; @@ -2217,7 +2235,8 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx, if (is_last_frag) { subreq = rpc_api_pipe_send(state, ev, state->cli, &state->outgoing_frag, - DCERPC_PKT_RESPONSE); + DCERPC_PKT_RESPONSE, + state->call_id); if (subreq == NULL) { goto fail; } @@ -2353,7 +2372,8 @@ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq) if (is_last_frag) { subreq = rpc_api_pipe_send(state, state->ev, state->cli, &state->outgoing_frag, - DCERPC_PKT_RESPONSE); + DCERPC_PKT_RESPONSE, + state->call_id); if (tevent_req_nomem(subreq, req)) { return; } @@ -2664,7 +2684,7 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx, } subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out, - DCERPC_PKT_BIND_ACK); + DCERPC_PKT_BIND_ACK, state->rpc_call_id); if (subreq == NULL) { goto fail; } @@ -2708,6 +2728,16 @@ static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq) return; } + if (hdr.call_id != state->rpc_call_id) { + DEBUG(0, ("rpc_pipe_bind: Missmatched call_id " + "(was %u, should be %u).\n", + (unsigned int)hdr.call_id, + (unsigned int)state->rpc_call_id)); + prs_mem_free(&reply_pdu); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + if (!smb_io_rpc_hdr_ba("", &hdr_ba, &reply_pdu, 0)) { DEBUG(0, ("rpc_pipe_bind: Failed to unmarshall " "RPC_HDR_BA.\n")); @@ -2932,7 +2962,8 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, } subreq = rpc_api_pipe_send(state, state->ev, state->cli, - &state->rpc_out, DCERPC_PKT_ALTER_RESP); + &state->rpc_out, DCERPC_PKT_ALTER_RESP, + state->rpc_call_id); if (subreq == NULL) { return NT_STATUS_NO_MEMORY; } @@ -2968,6 +2999,15 @@ static void rpc_bind_ntlmssp_api_done(struct tevent_req *subreq) return; } + if (hdr.call_id != state->rpc_call_id) { + DEBUG(0, ("Missmatched call_id " + "(was %u, should be %u).\n", + (unsigned int)hdr.call_id, + (unsigned int)state->rpc_call_id)); + tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR); + return; + } + if (!prs_set_offset( &reply_pdu, hdr.frag_len - hdr.auth_len - RPC_HDR_AUTH_LEN)) { -- 1.7.9.5 From d0b51b31ad37807a27fbbd42557f06673366ae10 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 19 Nov 2013 15:36:11 -0800 Subject: [PATCH 18/20] CVE-2013-4408:s3:Ensure LookupSids replies arrays are range checked. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Signed-off-by: Jeremy Allison --- source3/rpc_client/cli_lsarpc.c | 13 +++++++++++++ source3/rpcclient/cmd_lsarpc.c | 9 +++++++-- source4/libcli/util/clilsa.c | 16 +++++++++++++++- source4/winbind/wb_async_helpers.c | 13 ++++++++++++- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index caa2583..5f89840 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -198,6 +198,11 @@ static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli, goto done; } + if (num_sids != lsa_names.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + /* Return output parameters */ if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) || @@ -219,6 +224,14 @@ static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli, /* Translate optimised name through domain index array */ if (dom_idx != 0xffffffff) { + if (ref_domains == NULL) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (dom_idx >= ref_domains->count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } dom_name = ref_domains->domains[dom_idx].name.string; name = lsa_names.names[i].name.string; diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index e0f4ac4..fea1096 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -430,7 +430,7 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli, NTSTATUS result = NT_STATUS_UNSUCCESSFUL; int i; struct lsa_SidArray sids; - struct lsa_RefDomainList *domains; + struct lsa_RefDomainList *domains = NULL; struct lsa_TransNameArray2 names; uint32_t count = 0; @@ -472,11 +472,16 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli, NT_STATUS_V(STATUS_SOME_UNMAPPED)) goto done; + if (sids.num_sids != names.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = NT_STATUS_OK; /* Print results */ - for (i = 0; i < count; i++) { + for (i = 0; i < names.count; i++) { fstring sid_str; sid_to_fstring(sid_str, sids.sids[i].sid); diff --git a/source4/libcli/util/clilsa.c b/source4/libcli/util/clilsa.c index 16967d7..a7d202d 100644 --- a/source4/libcli/util/clilsa.c +++ b/source4/libcli/util/clilsa.c @@ -241,7 +241,21 @@ NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli, } if (names.count != 1) { talloc_free(mem_ctx2); - return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (domains == NULL) { + talloc_free(mem_ctx2); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (domains->count != 1) { + talloc_free(mem_ctx2); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (names.names[0].sid_index != UINT32_MAX && + names.names[0].sid_index >= domains->count) + { + talloc_free(mem_ctx2); + return NT_STATUS_INVALID_NETWORK_RESPONSE; } (*name) = talloc_asprintf(mem_ctx, "%s\\%s", diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c index a50a0fe..266634c 100644 --- a/source4/winbind/wb_async_helpers.c +++ b/source4/winbind/wb_async_helpers.c @@ -122,6 +122,12 @@ static void lsa_lookupsids_recv_names(struct rpc_request *req) return; } + if (state->names.count != state->num_sids) { + composite_error(state->ctx, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + state->result = talloc_array(state, struct wb_sid_object *, state->num_sids); if (composite_nomem(state->result, state->ctx)) return; @@ -142,9 +148,14 @@ static void lsa_lookupsids_recv_names(struct rpc_request *req) continue; } + if (domains == NULL) { + composite_error(state->ctx, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } if (name->sid_index >= domains->count) { composite_error(state->ctx, - NT_STATUS_INVALID_PARAMETER); + NT_STATUS_INVALID_NETWORK_RESPONSE); return; } -- 1.7.9.5 From 26eb2dd21f9e08ab75fbf37bccb3477fc37eca7d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 19 Nov 2013 16:34:52 -0800 Subject: [PATCH 19/20] CVE-2013-4408:s3:Ensure LookupNames replies arrays are range checked. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Stefan Metzmacher Signed-off-by: Jeremy Allison --- source3/lib/netapi/group.c | 84 ++++++++++++++++++++++++++++++++++++ source3/lib/netapi/localgroup.c | 9 +++- source3/lib/netapi/user.c | 56 ++++++++++++++++++++++++ source3/libnet/libnet_join.c | 16 +++++++ source3/rpc_client/cli_lsarpc.c | 18 ++++++++ source3/rpcclient/cmd_lsarpc.c | 6 ++- source3/rpcclient/cmd_samr.c | 62 ++++++++++++++++++++++++++ source3/smbd/lanman.c | 8 ++++ source3/utils/net_rpc.c | 41 +++++++++++++++++- source3/utils/net_rpc_join.c | 9 ++++ source4/libcli/util/clilsa.c | 6 ++- source4/libnet/groupinfo.c | 10 +++-- source4/libnet/groupman.c | 10 ++--- source4/libnet/libnet_join.c | 12 +++++- source4/libnet/libnet_lookup.c | 5 +++ source4/libnet/libnet_passwd.c | 10 ++++- source4/libnet/userinfo.c | 9 +++- source4/libnet/userman.c | 24 +++++------ source4/winbind/wb_async_helpers.c | 13 +++++- 19 files changed, 376 insertions(+), 32 deletions(-) diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c index f5a7e77..c511ecd 100644 --- a/source3/lib/netapi/group.c +++ b/source3/lib/netapi/group.c @@ -273,6 +273,15 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx, goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; goto done; @@ -437,6 +446,14 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; @@ -672,6 +689,14 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; @@ -788,6 +813,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx, werr = WERR_GROUPNOTFOUND; goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_GROUPNOTFOUND; @@ -816,6 +849,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx, werr = WERR_USER_NOT_FOUND; goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_USER) { werr = WERR_USER_NOT_FOUND; @@ -909,6 +950,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx, werr = WERR_GROUPNOTFOUND; goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_GROUPNOTFOUND; @@ -937,6 +986,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx, werr = WERR_USER_NOT_FOUND; goto done; } + if (rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } if (types.ids[0] != SID_NAME_USER) { werr = WERR_USER_NOT_FOUND; @@ -1319,6 +1376,15 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx, goto done; } + if (group_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + status = rpccli_samr_OpenGroup(pipe_cli, talloc_tos(), &domain_handle, SAMR_GROUP_ACCESS_GET_MEMBERS, @@ -1471,6 +1537,15 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx, goto done; } + if (group_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (group_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + status = rpccli_samr_OpenGroup(pipe_cli, talloc_tos(), &domain_handle, SAMR_GROUP_ACCESS_GET_MEMBERS | @@ -1533,6 +1608,15 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx, goto done; } + if (r->in.num_entries != user_rids.count) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (r->in.num_entries != name_types.count) { + werr = WERR_BAD_NET_RESP; + goto done; + } + member_rids = user_rids.ids; num_member_rids = user_rids.count; diff --git a/source3/lib/netapi/localgroup.c b/source3/lib/netapi/localgroup.c index 03f9da5..6e83d5d 100644 --- a/source3/lib/netapi/localgroup.c +++ b/source3/lib/netapi/localgroup.c @@ -50,6 +50,13 @@ static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx, return status; } + if (user_rids.count != 1) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (name_types.count != 1) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + switch (name_types.ids[0]) { case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: @@ -951,7 +958,7 @@ static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx, NT_STATUS_NOT_OK_RETURN(status); if (count != 1 || sids.count != 1) { - return NT_STATUS_NONE_MAPPED; + return NT_STATUS_INVALID_NETWORK_RESPONSE; } sid_copy(sid, sids.sids[0].sid); diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c index c5f7b37..e15a8f8 100644 --- a/source3/lib/netapi/user.c +++ b/source3/lib/netapi/user.c @@ -546,6 +546,14 @@ WERROR NetUserDel_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = rpccli_samr_OpenUser(pipe_cli, talloc_tos(), &domain_handle, @@ -1678,6 +1686,14 @@ WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli, domain_sid, @@ -1833,6 +1849,14 @@ WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = rpccli_samr_OpenUser(pipe_cli, talloc_tos(), &domain_handle, @@ -2852,6 +2876,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = rpccli_samr_OpenUser(pipe_cli, talloc_tos(), &domain_handle, @@ -3003,6 +3035,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = rpccli_samr_OpenUser(pipe_cli, talloc_tos(), &domain_handle, @@ -3053,6 +3093,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (group_rids.count != r->in.num_entries) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != r->in.num_entries) { + werr = WERR_BAD_NET_RESP; + goto done; + } member_rids = group_rids.ids; num_member_rids = group_rids.count; @@ -3297,6 +3345,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (user_rids.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (name_types.count != 1) { + werr = WERR_BAD_NET_RESP; + goto done; + } status = rpccli_samr_OpenUser(pipe_cli, talloc_tos(), &domain_handle, diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 8522c17..c7dad56 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -948,6 +948,14 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx, if (!NT_STATUS_IS_OK(status)) { goto done; } + if (user_rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0,("%s is not a user account (type=%d)\n", @@ -1274,6 +1282,14 @@ static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx, if (!NT_STATUS_IS_OK(status)) { goto done; } + if (user_rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 5f89840..90f97c7 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -516,9 +516,19 @@ static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli, DOM_SID *sid = &(*sids)[i]; if (use_lookupnames4) { + if (i >= sid_array3.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + dom_idx = sid_array3.sids[i].sid_index; (*types)[i] = sid_array3.sids[i].sid_type; } else { + if (i >= sid_array.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + dom_idx = sid_array.sids[i].sid_index; (*types)[i] = sid_array.sids[i].sid_type; } @@ -531,6 +541,14 @@ static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli, (*types)[i] = SID_NAME_UNKNOWN; continue; } + if (domains == NULL) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (dom_idx >= domains->count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } if (use_lookupnames4) { sid_copy(sid, sid_array3.sids[i].sid); diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index fea1096..7b8506c 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -309,7 +309,7 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli, uint32_t num_names; struct lsa_String *names; - struct lsa_RefDomainList *domains; + struct lsa_RefDomainList *domains = NULL; struct lsa_TransSidArray3 sids; uint32_t count = 0; int i; @@ -342,6 +342,10 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli, return result; } + if (sids.count != num_names) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + for (i = 0; i < sids.count; i++) { fstring sid_str; sid_to_fstring(sid_str, sids.sids[i].sid); diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c index 3964b7d..9b42eef 100644 --- a/source3/rpcclient/cmd_samr.c +++ b/source3/rpcclient/cmd_samr.c @@ -360,6 +360,15 @@ static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli, &types); if (NT_STATUS_IS_OK(result)) { + if (rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = rpccli_samr_OpenUser(cli, mem_ctx, &domain_pol, access_mask, @@ -1309,6 +1318,15 @@ static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli, &types); if (NT_STATUS_IS_OK(result)) { + if (rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = rpccli_samr_OpenAlias(cli, mem_ctx, &domain_pol, access_mask, @@ -1899,6 +1917,15 @@ static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(result)) goto done; + if (rids.count != num_names) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != num_names) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + /* Display results */ for (i = 0; i < num_names; i++) @@ -2039,6 +2066,15 @@ static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(result)) goto done; + if (group_rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = rpccli_samr_OpenGroup(cli, mem_ctx, &domain_pol, access_mask, @@ -2121,6 +2157,15 @@ static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(result)) goto done; + if (user_rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = rpccli_samr_OpenUser(cli, mem_ctx, &domain_pol, access_mask, @@ -2436,6 +2481,15 @@ static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *cli, goto done; } + if (rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + result = rpccli_samr_OpenUser(cli, mem_ctx, &domain_pol, access_mask, @@ -2804,6 +2858,14 @@ static NTSTATUS cmd_samr_setuserinfo_int(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(status)) { return status; } + if (rids.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (types.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } status = rpccli_samr_OpenUser(cli, mem_ctx, &domain_pol, diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c index 9b173d4..18ab1e3 100644 --- a/source3/smbd/lanman.c +++ b/source3/smbd/lanman.c @@ -2494,6 +2494,14 @@ static bool api_NetUserGetGroups(connection_struct *conn,uint16 vuid, nt_errstr(status))); goto close_domain; } + if (rid.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto close_domain; + } + if (type.count != 1) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto close_domain; + } if (type.ids[0] != SID_NAME_USER) { DEBUG(10, ("%s is a %s, not a user\n", UserName, diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 749b0c2..6e155ea 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -1493,6 +1493,15 @@ static NTSTATUS rpc_group_delete_internals(struct net_context *c, goto done; } + if (group_rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + switch (name_types.ids[0]) { case SID_NAME_DOM_GRP: @@ -1826,6 +1835,14 @@ static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd, member); goto done; } + if (rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (rid_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx, &domain_pol, @@ -2034,6 +2051,14 @@ static NTSTATUS rpc_del_groupmem(struct net_context *c, member); goto done; } + if (rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (rid_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx, &domain_pol, @@ -2695,9 +2720,15 @@ static NTSTATUS rpc_group_members_internals(struct net_context *c, if (rids.count != 1) { d_fprintf(stderr, _("Couldn't find group %s\n"), argv[0]); - return result; + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (rid_types.count != 1) { + d_fprintf(stderr, _("Couldn't find group %s\n"), + argv[0]); + return NT_STATUS_INVALID_NETWORK_RESPONSE; } + if (rid_types.ids[0] == SID_NAME_DOM_GRP) { return rpc_list_group_members(c, pipe_hnd, mem_ctx, domain_name, domain_sid, &domain_pol, @@ -5479,6 +5510,14 @@ static NTSTATUS rpc_trustdom_del_internals(struct net_context *c, acct_name, nt_errstr(result) ); goto done; } + if (user_rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx, &domain_pol, diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c index bb7d74b..2a4477c 100644 --- a/source3/utils/net_rpc_join.c +++ b/source3/utils/net_rpc_join.c @@ -322,6 +322,15 @@ int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv) ("error looking up rid for user %s: %s\n", acct_name, nt_errstr(result))); + if (user_rids.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.count != 1) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0])); goto done; diff --git a/source4/libcli/util/clilsa.c b/source4/libcli/util/clilsa.c index a7d202d..d4e02c0 100644 --- a/source4/libcli/util/clilsa.c +++ b/source4/libcli/util/clilsa.c @@ -312,7 +312,11 @@ NTSTATUS smblsa_lookup_name(struct smbcli_state *cli, } if (sids.count != 1) { talloc_free(mem_ctx2); - return NT_STATUS_UNSUCCESSFUL; + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (domains->count != 1) { + talloc_free(mem_ctx2); + return NT_STATUS_INVALID_NETWORK_RESPONSE; } sid = domains->domains[0].sid; diff --git a/source4/libnet/groupinfo.c b/source4/libnet/groupinfo.c index 1779c28..6020350 100644 --- a/source4/libnet/groupinfo.c +++ b/source4/libnet/groupinfo.c @@ -87,12 +87,16 @@ static void continue_groupinfo_lookup(struct rpc_request *req) s->monitor_fn(&msg); } - /* have we actually got name resolved - we're looking for only one at the moment */ - if (s->lookup.out.rids->count == 0) { - composite_error(c, NT_STATUS_NO_SUCH_USER); + if (s->lookup.out.rids->count != s->lookup.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + if (s->lookup.out.types->count != s->lookup.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } /* TODO: find proper status code for more than one rid found */ diff --git a/source4/libnet/groupman.c b/source4/libnet/groupman.c index 0f54db9..2bc318a 100644 --- a/source4/libnet/groupman.c +++ b/source4/libnet/groupman.c @@ -207,13 +207,13 @@ static void continue_groupdel_name_found(struct rpc_request *req) /* what to do when there's no group account to delete and what if there's more than one rid resolved */ - if (!s->lookupname.out.rids->count) { - c->status = NT_STATUS_NO_SUCH_GROUP; + if (s->lookupname.out.rids->count != s->lookupname.in.num_names) { + c->status = NT_STATUS_INVALID_NETWORK_RESPONSE; composite_error(c, c->status); return; - - } else if (!s->lookupname.out.rids->count > 1) { - c->status = NT_STATUS_INVALID_ACCOUNT_NAME; + } + if (s->lookupname.out.types->count != s->lookupname.in.num_names) { + c->status = NT_STATUS_INVALID_NETWORK_RESPONSE; composite_error(c, c->status); return; } diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c index fc7de10..d5d7ee0 100644 --- a/source4/libnet/libnet_join.c +++ b/source4/libnet/libnet_join.c @@ -643,9 +643,17 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru "samr_LookupNames for [%s] returns %d RIDs", r->in.account_name, ln.out.rids->count); talloc_free(tmp_ctx); - return NT_STATUS_INVALID_PARAMETER; + return NT_STATUS_INVALID_NETWORK_RESPONSE; } - + + if (ln.out.types->count != 1) { + r->out.error_string = talloc_asprintf(mem_ctx, + "samr_LookupNames for [%s] returns %d RID TYPEs", + r->in.account_name, ln.out.types->count); + talloc_free(tmp_ctx); + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + /* prepare samr_OpenUser */ ZERO_STRUCTP(u_handle); ou.in.domain_handle = &d_handle; diff --git a/source4/libnet/libnet_lookup.c b/source4/libnet/libnet_lookup.c index 4548864..24642ba 100644 --- a/source4/libnet/libnet_lookup.c +++ b/source4/libnet/libnet_lookup.c @@ -354,6 +354,11 @@ static void continue_name_found(struct rpc_request *req) c->status = s->lookup.out.result; if (!composite_is_ok(c)) return; + if (s->lookup.out.sids->count != s->lookup.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + composite_done(c); } diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index e558c93..bd1110a 100644 --- a/source4/libnet/libnet_passwd.c +++ b/source4/libnet/libnet_passwd.c @@ -594,10 +594,18 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX * r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_LookupNames for [%s] returns %d RIDs", r->samr.in.account_name, ln.out.rids->count); - status = NT_STATUS_INVALID_PARAMETER; + status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto disconnect; } + if (ln.out.types->count != 1) { + r->samr.out.error_string = talloc_asprintf(mem_ctx, + "samr_LookupNames for [%s] returns %d RID TYPEs", + r->samr.in.account_name, ln.out.types->count); + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto disconnect; + } + /* prepare samr_OpenUser */ ZERO_STRUCT(u_handle); ou.in.domain_handle = &d_handle; diff --git a/source4/libnet/userinfo.c b/source4/libnet/userinfo.c index a718ab9..283b126 100644 --- a/source4/libnet/userinfo.c +++ b/source4/libnet/userinfo.c @@ -90,8 +90,13 @@ static void continue_userinfo_lookup(struct rpc_request *req) /* have we actually got name resolved - we're looking for only one at the moment */ - if (s->lookup.out.rids->count == 0) { - composite_error(c, NT_STATUS_NO_SUCH_USER); + if (s->lookup.out.rids->count != s->lookup.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + if (s->lookup.out.types->count != s->lookup.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } /* TODO: find proper status code for more than one rid found */ diff --git a/source4/libnet/userman.c b/source4/libnet/userman.c index 62d4e0e..9e5a30d 100644 --- a/source4/libnet/userman.c +++ b/source4/libnet/userman.c @@ -233,14 +233,12 @@ static void continue_userdel_name_found(struct rpc_request *req) /* what to do when there's no user account to delete and what if there's more than one rid resolved */ - if (!s->lookupname.out.rids->count) { - c->status = NT_STATUS_NO_SUCH_USER; - composite_error(c, c->status); + if (s->lookupname.out.rids->count != s->lookupname.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; - - } else if (!s->lookupname.out.rids->count > 1) { - c->status = NT_STATUS_INVALID_ACCOUNT_NAME; - composite_error(c, c->status); + } + if (s->lookupname.out.types->count != s->lookupname.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } @@ -501,14 +499,12 @@ static void continue_usermod_name_found(struct rpc_request *req) /* what to do when there's no user account to delete and what if there's more than one rid resolved */ - if (!s->lookupname.out.rids->count) { - c->status = NT_STATUS_NO_SUCH_USER; - composite_error(c, c->status); + if (s->lookupname.out.rids->count != s->lookupname.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; - - } else if (!s->lookupname.out.rids->count > 1) { - c->status = NT_STATUS_INVALID_ACCOUNT_NAME; - composite_error(c, c->status); + } + if (s->lookupname.out.types->count != s->lookupname.in.num_names) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c index 266634c..433754b 100644 --- a/source4/winbind/wb_async_helpers.c +++ b/source4/winbind/wb_async_helpers.c @@ -282,6 +282,12 @@ static void lsa_lookupnames_recv_sids(struct rpc_request *req) return; } + if (state->sids.count != state->num_names) { + composite_error(state->ctx, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + state->result = talloc_array(state, struct wb_sid_object *, state->num_names); if (composite_nomem(state->result, state->ctx)) return; @@ -300,9 +306,14 @@ static void lsa_lookupnames_recv_sids(struct rpc_request *req) continue; } + if (domains == NULL) { + composite_error(state->ctx, + NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } if (sid->sid_index >= domains->count) { composite_error(state->ctx, - NT_STATUS_INVALID_PARAMETER); + NT_STATUS_INVALID_NETWORK_RESPONSE); return; } -- 1.7.9.5 From 1c392c7fe7794428a4f02c0e3405fb5194803336 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 19 Nov 2013 17:14:48 -0800 Subject: [PATCH 20/20] CVE-2013-4408:s3:Ensure LookupRids() replies arrays are range checked. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10185 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher --- source3/lib/netapi/group.c | 16 ++++++++++++++++ source3/lib/netapi/user.c | 16 ++++++++++++++++ source3/rpcclient/cmd_samr.c | 8 ++++++++ source3/utils/net_rpc.c | 7 +++++++ source3/winbindd/winbindd_rpc.c | 8 +++++--- 5 files changed, 52 insertions(+), 3 deletions(-) diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c index c511ecd..1081c86 100644 --- a/source3/lib/netapi/group.c +++ b/source3/lib/netapi/group.c @@ -339,6 +339,14 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (names.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (member_types.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } } for (i=0; i < rid_array->count; i++) { @@ -1413,6 +1421,14 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (names.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (member_types.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } for (i=0; i < names.count; i++) { diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c index e15a8f8..39c6b66 100644 --- a/source3/lib/netapi/user.c +++ b/source3/lib/netapi/user.c @@ -2924,6 +2924,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (names.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != rid_array->count) { + werr = WERR_BAD_NET_RESP; + goto done; + } for (i=0; i < names.count; i++) { status = add_GROUP_USERS_INFO_X_buffer(ctx, @@ -3449,6 +3457,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx, werr = ntstatus_to_werror(status); goto done; } + if (names.count != num_rids) { + werr = WERR_BAD_NET_RESP; + goto done; + } + if (types.count != num_rids) { + werr = WERR_BAD_NET_RESP; + goto done; + } for (i=0; i < names.count; i++) { status = add_LOCALGROUP_USERS_INFO_X_buffer(ctx, diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c index 9b42eef..368e845 100644 --- a/source3/rpcclient/cmd_samr.c +++ b/source3/rpcclient/cmd_samr.c @@ -2001,6 +2001,14 @@ static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli, goto done; /* Display results */ + if (num_rids != names.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } + if (num_rids != types.count) { + result = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto done; + } for (i = 0; i < num_rids; i++) { printf("rid 0x%x: %s (%d)\n", diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c index 6e155ea..517ee9c 100644 --- a/source3/utils/net_rpc.c +++ b/source3/utils/net_rpc.c @@ -2513,6 +2513,13 @@ static NTSTATUS rpc_list_group_members(struct net_context *c, if (!NT_STATUS_IS_OK(result)) return result; + if (names.count != this_time) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (types.count != this_time) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + /* We only have users as members, but make the output the same as the output of alias members */ diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index 59d3457..a379b0b 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -839,9 +839,11 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, /* Copy result into array. The talloc system will take care of freeing the temporary arrays later on. */ - - if (tmp_names.count != tmp_types.count) { - return NT_STATUS_UNSUCCESSFUL; + if (tmp_names.count != num_lookup_rids) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (tmp_types.count != num_lookup_rids) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; } for (r=0; r