The Samba-Bugzilla – Attachment 5372 Details for
Bug 7146
Samba miss-parses authenticated RPC packets.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
git-am patch for 3.5.x
0001-Fix-bug-7146-Samba-miss-parses-authenticated-RPC-pac.patch (text/plain), 34.51 KB, created by
Jeremy Allison
on 2010-02-17 17:53:19 UTC
(
hide
)
Description:
git-am patch for 3.5.x
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2010-02-17 17:53:19 UTC
Size:
34.51 KB
patch
obsolete
>From 6074cbb8e4b8ad7fbc65df2ca5cae961ca50289b Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 17 Feb 2010 15:27:59 -0800 >Subject: [PATCH] Fix bug #7146 - Samba miss-parses authenticated RPC packets. > >Parts of the Samba RPC client and server code misinterpret authenticated >packets. > >DCE authenticated packets actually look like this : > >+--------------------------+ >|header | >| ... frag_len (packet len)| >| ... auth_len | >+--------------------------+ >| | >| Data payload | >... .... >| | >+--------------------------+ >| | >| auth_pad_len bytes | >+--------------------------+ >| | >| Auth footer | >| auth_pad_len value | >+--------------------------+ >| | >| Auth payload | >| (auth_len bytes long) | >+--------------------------+ > >That's right. The pad bytes come *before* the footer specifying how many pad >bytes there are. In order to read this you must seek to the end of the packet >and subtract the auth_len (in the packet header) and the auth footer length (a >known value). > >The client and server code gets this right (mostly) in 3.0.x -> 3.4.x so long >as the pad alignment is on an 8 byte boundary (there are some special cases in >the code for this). > >Tridge discovered there are some (DRS replication) cases where on 64-bit >machines where the pad alignment is on a 16-byte boundary. This breaks the >existing S3 hand-optimized rpc code. > >This patch removes all the special cases in client and server code, and allows >the pad alignment for generated packets to be specified by changing a constant >in include/local.h (this doesn't affect received packets, the new code always >handles them correctly whatever pad alignment is used). > >This patch also works correctly with rpcclient using sign+seal from >the 3.4.x and 3.3.x builds (testing with 3.0.x and 3.2.x to follow) >so even as a server it should still work with older libsmbclient and >winbindd code. > >Jeremy >--- > source3/include/local.h | 3 + > source3/rpc_client/cli_pipe.c | 62 +++++-- > source3/rpc_parse/parse_rpc.c | 5 +- > source3/rpc_server/srv_pipe.c | 431 +++++++++++++++++++++++++++++------------ > 4 files changed, 363 insertions(+), 138 deletions(-) > >diff --git a/source3/include/local.h b/source3/include/local.h >index a88b17b..a3baf64 100644 >--- a/source3/include/local.h >+++ b/source3/include/local.h >@@ -274,4 +274,7 @@ > /* Maximum size of RPC data we will accept for one call. */ > #define MAX_RPC_DATA_SIZE (15*1024*1024) > >+#define CLIENT_NDR_PADDING_SIZE 8 >+#define SERVER_NDR_PADDING_SIZE 8 >+ > #endif >diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c >index 2f84828..3372ffc 100644 >--- a/source3/rpc_client/cli_pipe.c >+++ b/source3/rpc_client/cli_pipe.c >@@ -649,8 +649,9 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr > } > > /* Ensure there's enough data for an authenticated response. */ >- if ((auth_len > RPC_MAX_SIGN_SIZE) || >- (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) { >+ if (auth_len > RPC_MAX_PDU_FRAG_LEN || >+ prhdr->frag_len < RPC_HEADER_LEN + RPC_HDR_RESP_LEN + >+ RPC_HDR_AUTH_LEN + auth_len) { > DEBUG(0,("cli_pipe_verify_ntlmssp: auth_len %u is too large.\n", > (unsigned int)auth_len )); > return NT_STATUS_BUFFER_TOO_SMALL; >@@ -670,17 +671,31 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, RPC_HDR *pr > full_packet_data_len = prhdr->frag_len - auth_len; > > /* Pull the auth header and the following data into a blob. */ >- if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) { >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. */ >+ if(!prs_set_offset(current_pdu, prhdr->frag_len - RPC_HDR_AUTH_LEN - auth_len)) { > DEBUG(0,("cli_pipe_verify_ntlmssp: cannot move offset to %u.\n", > (unsigned int)RPC_HEADER_LEN + (unsigned int)RPC_HDR_RESP_LEN + (unsigned int)data_len )); > return NT_STATUS_BUFFER_TOO_SMALL; >- } >+ } > > if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, current_pdu, 0)) { > DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall RPC_HDR_AUTH.\n")); > return NT_STATUS_BUFFER_TOO_SMALL; > } > >+ /* Ensure auth_pad_len fits into the packet. */ >+ if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len + >+ RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len) { >+ DEBUG(0,("cli_pipe_verify_ntlmssp: auth_info.auth_pad_len " >+ "too large (%u), auth_len (%u), frag_len = (%u).\n", >+ (unsigned int)auth_info.auth_pad_len, >+ (unsigned int)auth_len, >+ (unsigned int)prhdr->frag_len )); >+ return NT_STATUS_BUFFER_TOO_SMALL; >+ } >+ >+ > auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu); > auth_blob.length = auth_len; > >@@ -774,7 +789,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p > } > > /* Ensure there's enough data for an authenticated response. */ >- if ((auth_len > RPC_MAX_SIGN_SIZE) || >+ if ((auth_len > RPC_MAX_PDU_FRAG_LEN) || > (RPC_HEADER_LEN + RPC_HDR_RESP_LEN + RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len)) { > DEBUG(0,("cli_pipe_verify_schannel: auth_len %u is too large.\n", > (unsigned int)auth_len )); >@@ -783,9 +798,15 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p > > data_len = prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len; > >- if(!prs_set_offset(current_pdu, RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len)) { >- DEBUG(0,("cli_pipe_verify_schannel: cannot move offset to %u.\n", >- (unsigned int)RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len )); >+ /* Pull the auth header and the following data into a blob. */ >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. */ >+ if(!prs_set_offset(current_pdu, >+ prhdr->frag_len - RPC_HDR_AUTH_LEN - auth_len)) { >+ DEBUG(0,("cli_pipe_verify_schannel: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(prhdr->frag_len - >+ RPC_HDR_AUTH_LEN - auth_len) )); > return NT_STATUS_BUFFER_TOO_SMALL; > } > >@@ -794,6 +815,17 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p > return NT_STATUS_BUFFER_TOO_SMALL; > } > >+ /* Ensure auth_pad_len fits into the packet. */ >+ if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len + >+ RPC_HDR_AUTH_LEN + auth_len > prhdr->frag_len) { >+ DEBUG(0,("cli_pipe_verify_schannel: auth_info.auth_pad_len " >+ "too large (%u), auth_len (%u), frag_len = (%u).\n", >+ (unsigned int)auth_info.auth_pad_len, >+ (unsigned int)auth_len, >+ (unsigned int)prhdr->frag_len )); >+ return NT_STATUS_BUFFER_TOO_SMALL; >+ } >+ > if (auth_info.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { > DEBUG(0,("cli_pipe_verify_schannel: Invalid auth info %d on schannel\n", > auth_info.auth_type)); >@@ -1789,8 +1821,8 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type pkt_type, > /* Do we need to pad ? */ > if (auth_len) { > uint16 data_len = RPC_HEADER_LEN + RPC_HDR_RB_LEN(&hdr_rb); >- if (data_len % 8) { >- ss_padding_len = 8 - (data_len % 8); >+ if (data_len % CLIENT_NDR_PADDING_SIZE) { >+ ss_padding_len = CLIENT_NDR_PADDING_SIZE - (data_len % CLIENT_NDR_PADDING_SIZE); > phdr_auth->auth_pad_len = ss_padding_len; > } > frag_len += RPC_HDR_AUTH_LEN + auth_len + ss_padding_len; >@@ -1817,8 +1849,8 @@ static NTSTATUS create_bind_or_alt_ctx_internal(enum dcerpc_pkt_type pkt_type, > > if(auth_len != 0) { > if (ss_padding_len) { >- char pad[8]; >- memset(pad, '\0', 8); >+ char pad[CLIENT_NDR_PADDING_SIZE]; >+ memset(pad, '\0', CLIENT_NDR_PADDING_SIZE); > if (!prs_copy_data_in(rpc_out, pad, ss_padding_len)) { > DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall padding.\n")); > return NT_STATUS_NO_MEMORY; >@@ -2119,8 +2151,8 @@ static uint32 calculate_data_len_tosend(struct rpc_pipe_client *cli, > > data_len = MIN(data_space, data_left); > *p_ss_padding = 0; >- if (data_len % 8) { >- *p_ss_padding = 8 - (data_len % 8); >+ if (data_len % CLIENT_NDR_PADDING_SIZE) { >+ *p_ss_padding = CLIENT_NDR_PADDING_SIZE - (data_len % CLIENT_NDR_PADDING_SIZE); > } > *p_frag_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + /* Normal headers. */ > data_len + *p_ss_padding + /* data plus padding. */ >@@ -2516,7 +2548,7 @@ static NTSTATUS create_rpc_bind_auth3(struct rpc_pipe_client *cli, > > /* > I'm puzzled about this - seems to violate the DCE RPC auth rules, >- about padding - shouldn't this pad to length 8 ? JRA. >+ about padding - shouldn't this pad to length CLIENT_NDR_PADDING_SIZE ? JRA. > */ > > /* 4 bytes padding. */ >diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c >index f720de3..441a00b 100644 >--- a/source3/rpc_parse/parse_rpc.c >+++ b/source3/rpc_parse/parse_rpc.c >@@ -480,6 +480,8 @@ void init_rpc_hdr_auth(RPC_HDR_AUTH *rai, > > /******************************************************************* > Reads or writes an RPC_HDR_AUTH structure. >+ NB This writes UNALIGNED. Ensure you're correctly aligned before >+ calling. > ********************************************************************/ > > bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, int depth) >@@ -490,9 +492,6 @@ bool smb_io_rpc_hdr_auth(const char *desc, RPC_HDR_AUTH *rai, prs_struct *ps, in > prs_debug(ps, depth, desc, "smb_io_rpc_hdr_auth"); > depth++; > >- if(!prs_align(ps)) >- return False; >- > if(!prs_uint8 ("auth_type ", ps, depth, &rai->auth_type)) > return False; > if(!prs_uint8 ("auth_level ", ps, depth, &rai->auth_level)) >diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c >index 46f67f4..bc0ad87 100644 >--- a/source3/rpc_server/srv_pipe.c >+++ b/source3/rpc_server/srv_pipe.c >@@ -130,11 +130,12 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p) > > if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) { > p->hdr.flags |= DCERPC_PFC_FLAG_LAST; >- if (data_len_left % 8) { >- ss_padding_len = 8 - (data_len_left % 8); >- DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n", >- ss_padding_len )); >- } >+ } >+ >+ if (data_len_left % SERVER_NDR_PADDING_SIZE) { >+ ss_padding_len = SERVER_NDR_PADDING_SIZE - (data_len_left % SERVER_NDR_PADDING_SIZE); >+ DEBUG(10,("create_next_pdu_ntlmssp: adding sign/seal padding of %u\n", >+ ss_padding_len )); > } > > /* >@@ -178,9 +179,9 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p) > > /* Copy the sign/seal padding data. */ > if (ss_padding_len) { >- char pad[8]; >+ char pad[SERVER_NDR_PADDING_SIZE]; > >- memset(pad, '\0', 8); >+ memset(pad, '\0', SERVER_NDR_PADDING_SIZE); > if (!prs_copy_data_in(&p->out_data.frag, pad, > ss_padding_len)) { > DEBUG(0,("create_next_pdu_ntlmssp: failed to add %u bytes of pad data.\n", >@@ -204,8 +205,9 @@ static bool create_next_pdu_ntlmssp(pipes_struct *p) > } > > init_rpc_hdr_auth(&auth_info, auth_type, auth_level, ss_padding_len, 1 /* context id. */); >- if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &p->out_data.frag, >- 0)) { >+ >+ if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, >+ &p->out_data.frag, 0)) { > DEBUG(0,("create_next_pdu_ntlmssp: failed to marshall RPC_HDR_AUTH.\n")); > prs_mem_free(&p->out_data.frag); > return False; >@@ -349,11 +351,11 @@ static bool create_next_pdu_schannel(pipes_struct *p) > > if(p->out_data.data_sent_length + data_len >= prs_offset(&p->out_data.rdata)) { > p->hdr.flags |= DCERPC_PFC_FLAG_LAST; >- if (data_len_left % 8) { >- ss_padding_len = 8 - (data_len_left % 8); >- DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n", >- ss_padding_len )); >- } >+ } >+ if (data_len_left % SERVER_NDR_PADDING_SIZE) { >+ ss_padding_len = SERVER_NDR_PADDING_SIZE - (data_len_left % SERVER_NDR_PADDING_SIZE); >+ DEBUG(10,("create_next_pdu_schannel: adding sign/seal padding of %u\n", >+ ss_padding_len )); > } > > p->hdr.frag_len = RPC_HEADER_LEN + RPC_HDR_RESP_LEN + data_len + ss_padding_len + >@@ -394,8 +396,8 @@ static bool create_next_pdu_schannel(pipes_struct *p) > > /* Copy the sign/seal padding data. */ > if (ss_padding_len) { >- char pad[8]; >- memset(pad, '\0', 8); >+ char pad[SERVER_NDR_PADDING_SIZE]; >+ memset(pad, '\0', SERVER_NDR_PADDING_SIZE); > if (!prs_copy_data_in(&p->out_data.frag, pad, > ss_padding_len)) { > DEBUG(0,("create_next_pdu_schannel: failed to add %u bytes of pad data.\n", (unsigned int)ss_padding_len)); >@@ -420,7 +422,7 @@ static bool create_next_pdu_schannel(pipes_struct *p) > DCERPC_AUTH_LEVEL_PRIVACY : DCERPC_AUTH_LEVEL_INTEGRITY, > ss_padding_len, 1); > >- if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, >+ if (!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, > &p->out_data.frag, 0)) { > DEBUG(0,("create_next_pdu_schannel: failed to marshall RPC_HDR_AUTH.\n")); > prs_mem_free(&p->out_data.frag); >@@ -745,12 +747,13 @@ bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p) > RPC_HDR_AUTH auth_info; > uint32 pad = 0; > DATA_BLOB blob; >+ uint32_t auth_len = p->hdr.auth_len; > > ZERO_STRUCT(blob); > > DEBUG(5,("api_pipe_bind_auth3: decode request. %d\n", __LINE__)); > >- if (p->hdr.auth_len == 0) { >+ if (auth_len == 0) { > DEBUG(0,("api_pipe_bind_auth3: No auth field sent !\n")); > goto err; > } >@@ -761,15 +764,45 @@ bool api_pipe_bind_auth3(pipes_struct *p, prs_struct *rpc_in_p) > goto err; > } > >+ /* Ensure there's enough data for an authenticated request. */ >+ if (RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + auth_len > >+ p->hdr.frag_len) { >+ DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len " >+ "%u is too large.\n", >+ (unsigned int)auth_len )); >+ goto err; >+ } >+ > /* > * Decode the authentication verifier response. > */ > >- if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) { >- DEBUG(0,("api_pipe_bind_auth3: unmarshall of RPC_HDR_AUTH failed.\n")); >+ /* Pull the auth header and the following data into a blob. */ >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. Also, the length of the >+ * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN, >+ * as the RPC header isn't included in rpc_in_p. */ >+ if(!prs_set_offset(rpc_in_p, >+ p->hdr.frag_len - RPC_HEADER_LEN - >+ RPC_HDR_AUTH_LEN - auth_len)) { >+ DEBUG(0,("api_pipe_bind_auth3: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(p->hdr.frag_len - >+ RPC_HDR_AUTH_LEN - auth_len) )); >+ goto err; >+ } >+ >+ if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in_p, 0)) { >+ DEBUG(0,("api_pipe_bind_auth3: failed to " >+ "unmarshall RPC_HDR_AUTH.\n")); > goto err; > } > >+ /* We must NEVER look at auth_info->auth_pad_len here, >+ * as old Samba client code gets it wrong and sends it >+ * as zero. JRA. >+ */ >+ > if (auth_info.auth_type != DCERPC_AUTH_TYPE_NTLMSSP) { > DEBUG(0,("api_pipe_bind_auth3: incorrect auth type (%u).\n", > (unsigned int)auth_info.auth_type )); >@@ -1153,6 +1186,7 @@ static bool pipe_spnego_auth_bind_kerberos(pipes_struct *p, prs_struct *rpc_in_p > *******************************************************************/ > > static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_p, >+ uint32_t ss_padding_len, > RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) > { > DATA_BLOB blob; >@@ -1244,8 +1278,11 @@ static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_ > OID_NTLMSSP); > } > >+ /* auth_pad_len will be handled by the caller */ >+ > /* Copy the blob into the pout_auth parse struct */ >- init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1); >+ init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, >+ pauth_info->auth_level, ss_padding_len, 1); > if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) { > DEBUG(0,("pipe_spnego_auth_bind_negotiate: marshalling of RPC_HDR_AUTH failed.\n")); > goto err; >@@ -1285,7 +1322,8 @@ static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_ > *******************************************************************/ > > static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p, >- RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) >+ uint32_t ss_padding_len, >+ RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) > { > RPC_HDR_AUTH auth_info; > DATA_BLOB spnego_blob; >@@ -1342,8 +1380,11 @@ static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p > /* Generate the spnego "accept completed" blob - no incoming data. */ > response = spnego_gen_auth_response(&auth_reply, NT_STATUS_OK, OID_NTLMSSP); > >+ /* FIXME - add auth_pad_len here ! */ >+ > /* Copy the blob into the pout_auth parse struct */ >- init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1); >+ init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SPNEGO, >+ pauth_info->auth_level, ss_padding_len, 1); > if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) { > DEBUG(0,("pipe_spnego_auth_bind_continue: marshalling of RPC_HDR_AUTH failed.\n")); > goto err; >@@ -1379,6 +1420,7 @@ static bool pipe_spnego_auth_bind_continue(pipes_struct *p, prs_struct *rpc_in_p > *******************************************************************/ > > static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, >+ uint32_t ss_padding_len, > RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) > { > RPC_HDR_AUTH auth_info; >@@ -1465,7 +1507,8 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, > return false; > } > >- init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SCHANNEL, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1); >+ init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_SCHANNEL, >+ pauth_info->auth_level, ss_padding_len, 1); > if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) { > DEBUG(0,("pipe_schannel_auth_bind: marshalling of RPC_HDR_AUTH failed.\n")); > return False; >@@ -1511,6 +1554,7 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, > *******************************************************************/ > > static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, >+ uint32_t ss_padding_len, > RPC_HDR_AUTH *pauth_info, prs_struct *pout_auth) > { > RPC_HDR_AUTH auth_info; >@@ -1554,7 +1598,8 @@ static bool pipe_ntlmssp_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, > data_blob_free(&blob); > > /* Copy the blob into the pout_auth parse struct */ >- init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_NTLMSSP, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1); >+ init_rpc_hdr_auth(&auth_info, DCERPC_AUTH_TYPE_NTLMSSP, >+ pauth_info->auth_level, ss_padding_len, 1); > if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) { > DEBUG(0,("pipe_ntlmssp_auth_bind: marshalling of RPC_HDR_AUTH failed.\n")); > goto err; >@@ -1603,6 +1648,7 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > int i = 0; > int auth_len = 0; > unsigned int auth_type = DCERPC_AUTH_TYPE_NONE; >+ uint32_t ss_padding_len = 0; > > /* No rebinds on a bound pipe - use alter context. */ > if (p->pipe_bound) { >@@ -1716,6 +1762,45 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > > DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__)); > >+ assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0; >+ >+ /* >+ * Create the bind response struct. >+ */ >+ >+ /* If the requested abstract synt uuid doesn't match our client pipe, >+ reject the bind_ack & set the transfer interface synt to all 0's, >+ ver 0 (observed when NT5 attempts to bind to abstract interfaces >+ unknown to NT4) >+ Needed when adding entries to a DACL from NT5 - SK */ >+ >+ if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0], >+ hdr_rb.rpc_context[0].context_id )) { >+ init_rpc_hdr_ba(&hdr_ba, >+ RPC_MAX_PDU_FRAG_LEN, >+ RPC_MAX_PDU_FRAG_LEN, >+ assoc_gid, >+ ack_pipe_name, >+ 0x1, 0x0, 0x0, >+ &hdr_rb.rpc_context[0].transfer[0]); >+ } else { >+ /* Rejection reason: abstract syntax not supported */ >+ init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN, >+ RPC_MAX_PDU_FRAG_LEN, assoc_gid, >+ ack_pipe_name, 0x1, 0x2, 0x1, >+ &null_ndr_syntax_id); >+ p->pipe_bound = False; >+ } >+ >+ /* >+ * and marshall it. >+ */ >+ >+ if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) { >+ DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n")); >+ goto err_exit; >+ } >+ > /* > * Check if this is an authenticated bind request. > */ >@@ -1725,6 +1810,40 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > * Decode the authentication verifier. > */ > >+ /* Work out any padding needed before the auth footer. */ >+ if ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE) { >+ ss_padding_len = SERVER_NDR_PADDING_SIZE - >+ ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE); >+ DEBUG(10,("api_pipe_bind_req: auth pad_len = %u\n", >+ (unsigned int)ss_padding_len )); >+ } >+ >+ /* Quick length check. Won't catch a bad auth footer, >+ * prevents overrun. */ >+ >+ if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + p->hdr.auth_len) { >+ DEBUG(0,("api_pipe_bind_req: auth_len (%u) " >+ "too long for fragment %u.\n", >+ (unsigned int)p->hdr.auth_len, >+ (unsigned int)p->hdr.frag_len )); >+ goto err_exit; >+ } >+ >+ /* Pull the auth header and the following data into a blob. */ >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. Also, the length of the >+ * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN, >+ * as the RPC header isn't included in rpc_in_p. */ >+ if(!prs_set_offset(rpc_in_p, >+ p->hdr.frag_len - RPC_HEADER_LEN - >+ RPC_HDR_AUTH_LEN - p->hdr.auth_len)) { >+ DEBUG(0,("api_pipe_bind_req: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(p->hdr.frag_len - >+ RPC_HDR_AUTH_LEN - p->hdr.auth_len) )); >+ goto err_exit; >+ } >+ > if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) { > DEBUG(0,("api_pipe_bind_req: unable to unmarshall RPC_HDR_AUTH struct.\n")); > goto err_exit; >@@ -1749,24 +1868,25 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > ZERO_STRUCT(auth_info); > } > >- assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0; >- > switch(auth_type) { > case DCERPC_AUTH_TYPE_NTLMSSP: >- if (!pipe_ntlmssp_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) { >+ if (!pipe_ntlmssp_auth_bind(p, rpc_in_p, >+ ss_padding_len, &auth_info, &out_auth)) { > goto err_exit; > } > assoc_gid = 0x7a77; > break; > > case DCERPC_AUTH_TYPE_SCHANNEL: >- if (!pipe_schannel_auth_bind(p, rpc_in_p, &auth_info, &out_auth)) { >+ if (!pipe_schannel_auth_bind(p, rpc_in_p, >+ ss_padding_len, &auth_info, &out_auth)) { > goto err_exit; > } > break; > > case DCERPC_AUTH_TYPE_SPNEGO: >- if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p, &auth_info, &out_auth)) { >+ if (!pipe_spnego_auth_bind_negotiate(p, rpc_in_p, >+ ss_padding_len, &auth_info, &out_auth)) { > goto err_exit; > } > break; >@@ -1780,50 +1900,13 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > p->pipe_bound = True; > /* The session key was initialized from the SMB > * session in make_internal_rpc_pipe_p */ >+ ss_padding_len = 0; > break; > > default: > DEBUG(0,("api_pipe_bind_req: unknown auth type %x requested.\n", auth_type )); > goto err_exit; > } >- >- /* >- * Create the bind response struct. >- */ >- >- /* If the requested abstract synt uuid doesn't match our client pipe, >- reject the bind_ack & set the transfer interface synt to all 0's, >- ver 0 (observed when NT5 attempts to bind to abstract interfaces >- unknown to NT4) >- Needed when adding entries to a DACL from NT5 - SK */ >- >- if(check_bind_req(p, &hdr_rb.rpc_context[0].abstract, &hdr_rb.rpc_context[0].transfer[0], >- hdr_rb.rpc_context[0].context_id )) { >- init_rpc_hdr_ba(&hdr_ba, >- RPC_MAX_PDU_FRAG_LEN, >- RPC_MAX_PDU_FRAG_LEN, >- assoc_gid, >- ack_pipe_name, >- 0x1, 0x0, 0x0, >- &hdr_rb.rpc_context[0].transfer[0]); >- } else { >- /* Rejection reason: abstract syntax not supported */ >- init_rpc_hdr_ba(&hdr_ba, RPC_MAX_PDU_FRAG_LEN, >- RPC_MAX_PDU_FRAG_LEN, assoc_gid, >- ack_pipe_name, 0x1, 0x2, 0x1, >- &null_ndr_syntax_id); >- p->pipe_bound = False; >- } >- >- /* >- * and marshall it. >- */ >- >- if(!smb_io_rpc_hdr_ba("", &hdr_ba, &out_hdr_ba, 0)) { >- DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_BA failed.\n")); >- goto err_exit; >- } >- > /* > * Create the header, now we know the length. > */ >@@ -1834,7 +1917,8 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > > init_rpc_hdr(&p->hdr, DCERPC_PKT_BIND_ACK, DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST, > p->hdr.call_id, >- RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + prs_offset(&out_auth), >+ RPC_HEADER_LEN + prs_offset(&out_hdr_ba) + >+ ss_padding_len + prs_offset(&out_auth), > auth_len); > > /* >@@ -1855,9 +1939,23 @@ bool api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p) > goto err_exit; > } > >- if (auth_len && !prs_append_prs_data( &p->out_data.frag, &out_auth)) { >- DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n")); >- goto err_exit; >+ if (auth_len) { >+ if (ss_padding_len) { >+ char pad[SERVER_NDR_PADDING_SIZE]; >+ memset(pad, '\0', SERVER_NDR_PADDING_SIZE); >+ if (!prs_copy_data_in(&p->out_data.frag, pad, >+ ss_padding_len)) { >+ DEBUG(0,("api_pipe_bind_req: failed to add %u " >+ "bytes of pad data.\n", >+ (unsigned int)ss_padding_len)); >+ goto err_exit; >+ } >+ } >+ >+ if (!prs_append_prs_data( &p->out_data.frag, &out_auth)) { >+ DEBUG(0,("api_pipe_bind_req: append of auth info failed.\n")); >+ goto err_exit; >+ } > } > > /* >@@ -1895,6 +1993,7 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p) > prs_struct out_hdr_ba; > prs_struct out_auth; > int auth_len = 0; >+ uint32_t ss_padding_len = 0; > > prs_init_empty(&p->out_data.frag, p->mem_ctx, MARSHALL); > >@@ -1940,39 +2039,6 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p) > > DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__)); > >- /* >- * Check if this is an authenticated alter context request. >- */ >- >- if (p->hdr.auth_len != 0) { >- /* >- * Decode the authentication verifier. >- */ >- >- if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) { >- DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n")); >- goto err_exit; >- } >- >- /* >- * Currently only the SPNEGO auth type uses the alter ctx >- * response in place of the NTLMSSP auth3 type. >- */ >- >- if (auth_info.auth_type == DCERPC_AUTH_TYPE_SPNEGO) { >- /* We can only finish if the pipe is unbound. */ >- if (!p->pipe_bound) { >- if (!pipe_spnego_auth_bind_continue(p, rpc_in_p, &auth_info, &out_auth)) { >- goto err_exit; >- } >- } else { >- goto err_exit; >- } >- } >- } else { >- ZERO_STRUCT(auth_info); >- } >- > assoc_gid = hdr_rb.bba.assoc_gid ? hdr_rb.bba.assoc_gid : 0x53f0; > > /* >@@ -2012,6 +2078,74 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p) > goto err_exit; > } > >+ >+ /* >+ * Check if this is an authenticated alter context request. >+ */ >+ >+ if (p->hdr.auth_len != 0) { >+ /* >+ * Decode the authentication verifier. >+ */ >+ >+ /* Work out any padding needed before the auth footer. */ >+ if ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE) { >+ ss_padding_len = SERVER_NDR_PADDING_SIZE - >+ ((RPC_HEADER_LEN + prs_offset(&out_hdr_ba)) % SERVER_NDR_PADDING_SIZE); >+ DEBUG(10,("api_pipe_alter_context: auth pad_len = %u\n", >+ (unsigned int)ss_padding_len )); >+ } >+ >+ /* Quick length check. Won't catch a bad auth footer, >+ * prevents overrun. */ >+ >+ if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_AUTH_LEN + p->hdr.auth_len) { >+ DEBUG(0,("api_pipe_alter_context: auth_len (%u) " >+ "too long for fragment %u.\n", >+ (unsigned int)p->hdr.auth_len, >+ (unsigned int)p->hdr.frag_len )); >+ goto err_exit; >+ } >+ >+ /* Pull the auth header and the following data into a blob. */ >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. Also, the length of the >+ * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN, >+ * as the RPC header isn't included in rpc_in_p. */ >+ if(!prs_set_offset(rpc_in_p, >+ p->hdr.frag_len - RPC_HEADER_LEN - >+ RPC_HDR_AUTH_LEN - p->hdr.auth_len)) { >+ DEBUG(0,("api_alter_context: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(p->hdr.frag_len - >+ RPC_HDR_AUTH_LEN - p->hdr.auth_len) )); >+ goto err_exit; >+ } >+ >+ if(!smb_io_rpc_hdr_auth("", &auth_info, rpc_in_p, 0)) { >+ DEBUG(0,("api_pipe_alter_context: unable to unmarshall RPC_HDR_AUTH struct.\n")); >+ goto err_exit; >+ } >+ >+ /* >+ * Currently only the SPNEGO auth type uses the alter ctx >+ * response in place of the NTLMSSP auth3 type. >+ */ >+ >+ if (auth_info.auth_type == DCERPC_AUTH_TYPE_SPNEGO) { >+ /* We can only finish if the pipe is unbound. */ >+ if (!p->pipe_bound) { >+ if (!pipe_spnego_auth_bind_continue(p, rpc_in_p, >+ ss_padding_len, &auth_info, &out_auth)) { >+ goto err_exit; >+ } >+ } else { >+ goto err_exit; >+ } >+ } >+ } else { >+ ZERO_STRUCT(auth_info); >+ } > /* > * Create the header, now we know the length. > */ >@@ -2043,9 +2177,23 @@ bool api_pipe_alter_context(pipes_struct *p, prs_struct *rpc_in_p) > goto err_exit; > } > >- if (auth_len && !prs_append_prs_data(&p->out_data.frag, &out_auth)) { >- DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n")); >- goto err_exit; >+ if (auth_len) { >+ if (ss_padding_len) { >+ char pad[SERVER_NDR_PADDING_SIZE]; >+ memset(pad, '\0', SERVER_NDR_PADDING_SIZE); >+ if (!prs_copy_data_in(&p->out_data.frag, pad, >+ ss_padding_len)) { >+ DEBUG(0,("api_pipe_alter_context: failed to add %u " >+ "bytes of pad data.\n", >+ (unsigned int)ss_padding_len)); >+ goto err_exit; >+ } >+ } >+ >+ if (!prs_append_prs_data( &p->out_data.frag, &out_auth)) { >+ DEBUG(0,("api_pipe_alter_context: append of auth info failed.\n")); >+ goto err_exit; >+ } > } > > /* >@@ -2097,8 +2245,8 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in, > } > > /* Ensure there's enough data for an authenticated request. */ >- if ((auth_len > RPC_MAX_SIGN_SIZE) || >- (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len)) { >+ if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN >+ + auth_len > p->hdr.frag_len) { > DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_len %u is too large.\n", > (unsigned int)auth_len )); > *pstatus = NT_STATUS_INVALID_PARAMETER; >@@ -2107,9 +2255,10 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in, > > /* > * We need the full packet data + length (minus auth stuff) as well as the packet data + length >- * after the RPC header. >+ * after the RPC header. > * We need to pass in the full packet (minus auth len) to the NTLMSSP sign and check seal > * functions as NTLMv2 checks the rpc headers also. >+ * Both of these values include any auth_pad_len bytes. > */ > > data = (unsigned char *)(prs_data_p(rpc_in) + RPC_HDR_REQ_LEN); >@@ -2119,15 +2268,36 @@ bool api_pipe_ntlmssp_auth_process(pipes_struct *p, prs_struct *rpc_in, > full_packet_data_len = p->hdr.frag_len - auth_len; > > /* Pull the auth header and the following data into a blob. */ >- if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) { >- DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move offset to %u.\n", >- (unsigned int)RPC_HDR_REQ_LEN + (unsigned int)data_len )); >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. Also, the length of the >+ * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN, >+ * as the RPC header isn't included in rpc_in_p. */ >+ if(!prs_set_offset(rpc_in, >+ p->hdr.frag_len - RPC_HEADER_LEN - >+ RPC_HDR_AUTH_LEN - auth_len)) { >+ DEBUG(0,("api_pipe_ntlmssp_auth_process: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(p->hdr.frag_len - >+ RPC_HDR_AUTH_LEN - auth_len) )); > *pstatus = NT_STATUS_INVALID_PARAMETER; > return False; > } > > if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) { >- DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to unmarshall RPC_HDR_AUTH.\n")); >+ DEBUG(0,("api_pipe_ntlmssp_auth_process: failed to " >+ "unmarshall RPC_HDR_AUTH.\n")); >+ *pstatus = NT_STATUS_INVALID_PARAMETER; >+ return False; >+ } >+ >+ /* Ensure auth_pad_len fits into the packet. */ >+ if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len + >+ RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len) { >+ DEBUG(0,("api_pipe_ntlmssp_auth_process: auth_info.auth_pad_len " >+ "too large (%u), auth_len (%u), frag_len = (%u).\n", >+ (unsigned int)auth_info.auth_pad_len, >+ (unsigned int)auth_len, >+ (unsigned int)p->hdr.frag_len )); > *pstatus = NT_STATUS_INVALID_PARAMETER; > return False; > } >@@ -2212,7 +2382,7 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss > /* > * The following is that length of the data we must verify or unseal. > * This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN >- * preceeding the auth_data. >+ * preceeding the auth_data, but does include the auth_pad_len bytes. > */ > > if (p->hdr.frag_len < RPC_HEADER_LEN + RPC_HDR_REQ_LEN + RPC_HDR_AUTH_LEN + auth_len) { >@@ -2227,14 +2397,35 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss > > DEBUG(5,("data %d auth %d\n", data_len, auth_len)); > >- if(!prs_set_offset(rpc_in, RPC_HDR_REQ_LEN + data_len)) { >- DEBUG(0,("cannot move offset to %u.\n", >- (unsigned int)RPC_HDR_REQ_LEN + data_len )); >+ /* Pull the auth header and the following data into a blob. */ >+ /* NB. The offset of the auth_header is relative to the *end* >+ * of the packet, not the start. Also, the length of the >+ * data in rpc_in_p is p->hdr.frag_len - RPC_HEADER_LEN, >+ * as the RPC header isn't included in rpc_in_p. */ >+ if(!prs_set_offset(rpc_in, >+ p->hdr.frag_len - RPC_HEADER_LEN - >+ RPC_HDR_AUTH_LEN - auth_len)) { >+ DEBUG(0,("api_pipe_schannel_process: cannot move " >+ "offset to %u.\n", >+ (unsigned int)(p->hdr.frag_len - >+ RPC_HDR_AUTH_LEN - auth_len) )); > return False; > } > > if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, rpc_in, 0)) { >- DEBUG(0,("failed to unmarshall RPC_HDR_AUTH.\n")); >+ DEBUG(0,("api_pipe_schannel_process: failed to " >+ "unmarshall RPC_HDR_AUTH.\n")); >+ return False; >+ } >+ >+ /* Ensure auth_pad_len fits into the packet. */ >+ if (RPC_HEADER_LEN + RPC_HDR_REQ_LEN + auth_info.auth_pad_len + >+ RPC_HDR_AUTH_LEN + auth_len > p->hdr.frag_len) { >+ DEBUG(0,("api_pipe_schannel_process: auth_info.auth_pad_len " >+ "too large (%u), auth_len (%u), frag_len = (%u).\n", >+ (unsigned int)auth_info.auth_pad_len, >+ (unsigned int)auth_len, >+ (unsigned int)p->hdr.frag_len )); > return False; > } > >-- >1.6.6.2 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 7146
:
5372
|
5389
|
5390