diff options
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 361 |
1 files changed, 18 insertions, 343 deletions
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 759cfc5c22..ef9b921fe1 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -366,328 +366,6 @@ static NTSTATUS get_complete_frag_recv(struct tevent_req *req) } /**************************************************************************** - NTLMSSP specific sign/seal. - Virtually identical to rpc_server/srv_pipe.c:api_pipe_ntlmssp_auth_process. - In fact I should probably abstract these into identical pieces of code... JRA. - ****************************************************************************/ - -static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, - struct ncacn_packet *pkt, - DATA_BLOB *pdu, - uint8 *p_ss_padding_len) -{ - struct dcerpc_auth auth_info; - DATA_BLOB blob; - NTSTATUS status; - - if (cli->auth->auth_level == DCERPC_AUTH_LEVEL_NONE - || cli->auth->auth_level == DCERPC_AUTH_LEVEL_CONNECT) { - return NT_STATUS_OK; - } - - if (!cli->auth->a_u.auth_ntlmssp_state) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* Ensure there's enough data for an authenticated response. */ - if ((pkt->auth_length > RPC_MAX_PDU_FRAG_LEN) || - (pkt->frag_length < DCERPC_RESPONSE_LENGTH - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length)) { - DEBUG(0, ("auth_len %u is too long.\n", - (unsigned int)pkt->auth_length)); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - /* get the auth blob at the end of the packet */ - blob = data_blob_const(pdu->data + pkt->frag_length - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length); - - status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info, false); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall dcerpc_auth.\n")); - return status; - } - - /* Ensure auth_pad_len fits into the packet. */ - if (pkt->frag_length < DCERPC_RESPONSE_LENGTH - + auth_info.auth_pad_length - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - 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_length, - (unsigned int)pkt->auth_length, - (unsigned int)pkt->frag_length)); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - /* - * We need the full packet data + length (minus auth stuff) as well as the packet data + length - * 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. - */ - - switch (cli->auth->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - /* Data is encrypted. */ - status = auth_ntlmssp_unseal_packet( - cli->auth->a_u.auth_ntlmssp_state, - pdu->data + DCERPC_RESPONSE_LENGTH, - pkt->frag_length - - DCERPC_RESPONSE_LENGTH - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - pdu->data, - pkt->frag_length - pkt->auth_length, - &auth_info.credentials); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("failed to unseal packet from %s." - " Error was %s.\n", - rpccli_pipe_txt(talloc_tos(), cli), - nt_errstr(status))); - return status; - } - break; - - case DCERPC_AUTH_LEVEL_INTEGRITY: - /* Data is signed. */ - status = auth_ntlmssp_check_packet( - cli->auth->a_u.auth_ntlmssp_state, - pdu->data + DCERPC_RESPONSE_LENGTH, - pkt->frag_length - - DCERPC_RESPONSE_LENGTH - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - pdu->data, - pkt->frag_length - pkt->auth_length, - &auth_info.credentials); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("check signing failed on packet from %s." - " Error was %s.\n", - rpccli_pipe_txt(talloc_tos(), cli), - nt_errstr(status))); - return status; - } - break; - - default: - DEBUG(0, ("cli_pipe_verify_ntlmssp: unknown internal " - "auth level %d\n", cli->auth->auth_level)); - return NT_STATUS_INVALID_INFO_CLASS; - } - - /* - * Remember the padding length. We must remove it from the real data - * stream once the sign/seal is done. - */ - - *p_ss_padding_len = auth_info.auth_pad_length; - - return NT_STATUS_OK; -} - -/**************************************************************************** - schannel specific sign/seal. - ****************************************************************************/ - -static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, - struct ncacn_packet *pkt, - DATA_BLOB *pdu, - uint8 *p_ss_padding_len) -{ - struct dcerpc_auth auth_info; - DATA_BLOB blob; - NTSTATUS status; - - if (cli->auth->auth_level == DCERPC_AUTH_LEVEL_NONE - || cli->auth->auth_level == DCERPC_AUTH_LEVEL_CONNECT) { - return NT_STATUS_OK; - } - - if (pkt->auth_length < NL_AUTH_SIGNATURE_SIZE) { - DEBUG(0, ("auth_len %u.\n", (unsigned int)pkt->auth_length)); - return NT_STATUS_INVALID_PARAMETER; - } - - if (!cli->auth->a_u.schannel_auth) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* Ensure there's enough data for an authenticated response. */ - if ((pkt->auth_length > RPC_MAX_PDU_FRAG_LEN) || - (pkt->frag_length < DCERPC_RESPONSE_LENGTH - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length)) { - DEBUG(0, ("auth_len %u is too long.\n", - (unsigned int)pkt->auth_length)); - return NT_STATUS_INVALID_PARAMETER; - } - - /* get the auth blob at the end of the packet */ - blob = data_blob_const(pdu->data + pkt->frag_length - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length); - - - status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info, false); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall dcerpc_auth.\n")); - return status; - } - - /* Ensure auth_pad_len fits into the packet. */ - if (pkt->frag_length < DCERPC_RESPONSE_LENGTH - + auth_info.auth_pad_length - + DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - 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_length, - (unsigned int)pkt->auth_length, - (unsigned int)pkt->frag_length)); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - if (auth_info.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0, ("Invalid auth info %d on schannel\n", - auth_info.auth_type)); - return NT_STATUS_BUFFER_TOO_SMALL; - } - - if (DEBUGLEVEL >= 10) { - dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_info.credentials); - } - - switch (cli->auth->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - status = netsec_incoming_packet( - cli->auth->a_u.schannel_auth, - talloc_tos(), - true, - pdu->data + DCERPC_RESPONSE_LENGTH, - pkt->frag_length - - DCERPC_RESPONSE_LENGTH - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - &auth_info.credentials); - break; - case DCERPC_AUTH_LEVEL_INTEGRITY: - status = netsec_incoming_packet( - cli->auth->a_u.schannel_auth, - talloc_tos(), - false, - pdu->data + DCERPC_RESPONSE_LENGTH, - pkt->frag_length - - DCERPC_RESPONSE_LENGTH - - DCERPC_AUTH_TRAILER_LENGTH - - pkt->auth_length, - &auth_info.credentials); - break; - default: - status = NT_STATUS_INTERNAL_ERROR; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU " - "Connection to %s (%s).\n", - rpccli_pipe_txt(talloc_tos(), cli), - nt_errstr(status))); - return NT_STATUS_INVALID_PARAMETER; - } - - /* - * Remember the padding length. We must remove it from the real data - * stream once the sign/seal is done. - */ - - *p_ss_padding_len = auth_info.auth_pad_length; - - return NT_STATUS_OK; -} - -/**************************************************************************** - Do the authentication checks on an incoming pdu. Check sign and unseal etc. - ****************************************************************************/ - -static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli, - struct ncacn_packet *pkt, - DATA_BLOB *pdu, - uint8 *p_ss_padding_len) -{ - NTSTATUS ret = NT_STATUS_OK; - - /* Paranioa checks for auth_len. */ - if (pkt->auth_length) { - if (pkt->auth_length > pkt->frag_length) { - return NT_STATUS_INVALID_PARAMETER; - } - - if ((pkt->auth_length - + (unsigned int)DCERPC_AUTH_TRAILER_LENGTH - < pkt->auth_length) || - (pkt->auth_length - + (unsigned int)DCERPC_AUTH_TRAILER_LENGTH - < (unsigned int)DCERPC_AUTH_TRAILER_LENGTH)) { - /* Integer wrap attempt. */ - return NT_STATUS_INVALID_PARAMETER; - } - } - - /* - * Now we have a complete RPC request PDU fragment, try and verify any auth data. - */ - - switch(cli->auth->auth_type) { - case PIPE_AUTH_TYPE_NONE: - if (pkt->auth_length) { - DEBUG(3, ("cli_pipe_validate_rpc_response: " - "Connection to %s - got non-zero " - "auth len %u.\n", - rpccli_pipe_txt(talloc_tos(), cli), - (unsigned int)pkt->auth_length)); - return NT_STATUS_INVALID_PARAMETER; - } - break; - - case PIPE_AUTH_TYPE_NTLMSSP: - case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: - ret = cli_pipe_verify_ntlmssp(cli, pkt, pdu, - p_ss_padding_len); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } - break; - - case PIPE_AUTH_TYPE_SCHANNEL: - ret = cli_pipe_verify_schannel(cli, pkt, pdu, - p_ss_padding_len); - if (!NT_STATUS_IS_OK(ret)) { - return ret; - } - break; - - case PIPE_AUTH_TYPE_KRB5: - case PIPE_AUTH_TYPE_SPNEGO_KRB5: - default: - DEBUG(3, ("cli_pipe_validate_rpc_response: Connection " - "to %s - unknown internal auth type %u.\n", - rpccli_pipe_txt(talloc_tos(), cli), - cli->auth->auth_type )); - return NT_STATUS_INVALID_INFO_CLASS; - } - - return NT_STATUS_OK; -} - -/**************************************************************************** Do basic authentication checks on an incoming pdu. ****************************************************************************/ @@ -700,7 +378,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, DATA_BLOB *reply_pdu) { NTSTATUS ret = NT_STATUS_OK; - uint8 ss_padding_len = 0; + size_t pad_len = 0; ret = dcerpc_pull_ncacn_packet(cli, pdu, pkt, false); if (!NT_STATUS_IS_OK(ret)) { @@ -732,40 +410,37 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, case DCERPC_PKT_RESPONSE: /* Here's where we deal with incoming sign/seal. */ - ret = cli_pipe_validate_rpc_response(cli, pkt, pdu, - &ss_padding_len); + ret = dcerpc_check_auth(cli->auth, pkt, + &pkt->u.response.stub_and_verifier, + DCERPC_RESPONSE_LENGTH, + pdu, &pad_len); if (!NT_STATUS_IS_OK(ret)) { return ret; } - /* Point the return values at the NDR data. - * Remember to remove any ss padding. */ - rdata->data = pdu->data + DCERPC_RESPONSE_LENGTH; - - if (pdu->length < DCERPC_RESPONSE_LENGTH + ss_padding_len) { + if (pdu->length < DCERPC_RESPONSE_LENGTH + pad_len) { return NT_STATUS_BUFFER_TOO_SMALL; } - rdata->length = pdu->length - - DCERPC_RESPONSE_LENGTH - - ss_padding_len; + /* Point the return values at the NDR data. */ + rdata->data = pdu->data + DCERPC_RESPONSE_LENGTH; - /* Remember to remove the auth footer. */ if (pkt->auth_length) { - /* We've already done integer wrap tests on auth_len in - cli_pipe_validate_rpc_response(). */ - if (rdata->length < DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - rdata->length -= (DCERPC_AUTH_TRAILER_LENGTH - + pkt->auth_length); + /* We've already done integer wrap tests in + * dcerpc_check_auth(). */ + rdata->length = pdu->length + - DCERPC_RESPONSE_LENGTH + - pad_len + - DCERPC_AUTH_TRAILER_LENGTH + - pkt->auth_length; + } else { + rdata->length = pdu->length - DCERPC_RESPONSE_LENGTH; } DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n", (long unsigned int)pdu->length, (long unsigned int)rdata->length, - (unsigned int)ss_padding_len)); + (unsigned int)pad_len)); /* * If this is the first reply, and the allocation hint is |