/** * @brief Check authentication for request/response packets * * @param auth The auth data for the connection * @param pkt The actual ncacn_packet * @param pkt_trailer [in][out] The stub_and_verifier part of the packet, * the auth_trailer and padding will be removed. * @param header_size The header size * @param raw_pkt The whole raw packet data blob * * @return A NTSTATUS error code */ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, struct ncacn_packet *pkt, DATA_BLOB *pkt_trailer, uint8_t header_size, DATA_BLOB *raw_pkt) { struct gensec_security *gensec_security; NTSTATUS status; struct dcerpc_auth auth_info; uint32_t auth_length; DATA_BLOB full_pkt; DATA_BLOB data; /* * These check should be done in the caller. */ SMB_ASSERT(raw_pkt->length == pkt->frag_length); SMB_ASSERT(header_size <= pkt->frag_length); SMB_ASSERT(pkt_trailer->length < pkt->frag_length); SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length); switch (auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: DEBUG(10, ("Requested Privacy.\n")); break; case DCERPC_AUTH_LEVEL_INTEGRITY: DEBUG(10, ("Requested Integrity.\n")); break; case DCERPC_AUTH_LEVEL_PACKET: DEBUG(10, ("Requested packet.\n")); break; case DCERPC_AUTH_LEVEL_CONNECT: if (pkt->auth_length != 0) { break; } return NT_STATUS_OK; case DCERPC_AUTH_LEVEL_NONE: if (pkt->auth_length != 0) { DEBUG(3, ("Got non-zero auth len on non " "authenticated connection!\n")); return NT_STATUS_INVALID_PARAMETER; } return NT_STATUS_OK; default: DEBUG(3, ("Unimplemented Auth Level %d", auth->auth_level)); return NT_STATUS_INVALID_PARAMETER; } if (pkt->auth_length == 0) { return NT_STATUS_INVALID_PARAMETER; } status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer, &auth_info, &auth_length, false); if (!NT_STATUS_IS_OK(status)) { return status; } if (auth_info.auth_type != auth->auth_type) { return NT_STATUS_INVALID_PARAMETER; } if (auth_info.auth_level != auth->auth_level) { return NT_STATUS_INVALID_PARAMETER; } if (auth_info.auth_context_id != auth->auth_context_id) { return NT_STATUS_INVALID_PARAMETER; } pkt_trailer->length -= auth_length; data = data_blob_const(raw_pkt->data + header_size, pkt_trailer->length); full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length); full_pkt.length -= auth_info.credentials.length; switch (auth->auth_type) { case DCERPC_AUTH_TYPE_NONE: return NT_STATUS_OK; default: DEBUG(10, ("GENSEC auth\n")); gensec_security = auth->auth_ctx; status = get_generic_auth_footer(gensec_security, auth->auth_level, &data, &full_pkt, &auth_info.credentials); if (!NT_STATUS_IS_OK(status)) { return status; } break; } /* TODO: remove later * this is still needed because in the server code the * pkt_trailer actually has a copy of the raw data, and they * are still both used in later calls */ if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { if (pkt_trailer->length != data.length) { return NT_STATUS_INVALID_PARAMETER; } memcpy(pkt_trailer->data, data.data, data.length); } pkt_trailer->length -= auth_info.auth_pad_length; data_blob_free(&auth_info.credentials); return NT_STATUS_OK; }
/** * @brief Check authentication for request/response packets * * @param auth The auth data for the connection * @param pkt The actual ncacn_packet * @param pkt_trailer The stub_and_verifier part of the packet * @param header_size The header size * @param raw_pkt The whole raw packet data blob * @param pad_len [out] The padding length used in the packet * * @return A NTSTATUS error code */ NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, struct ncacn_packet *pkt, DATA_BLOB *pkt_trailer, size_t header_size, DATA_BLOB *raw_pkt, size_t *pad_len) { struct gensec_security *gensec_security; NTSTATUS status; struct dcerpc_auth auth_info; uint32_t auth_length; DATA_BLOB full_pkt; DATA_BLOB data; switch (auth->auth_level) { case DCERPC_AUTH_LEVEL_PRIVACY: DEBUG(10, ("Requested Privacy.\n")); break; case DCERPC_AUTH_LEVEL_INTEGRITY: DEBUG(10, ("Requested Integrity.\n")); break; case DCERPC_AUTH_LEVEL_CONNECT: if (pkt->auth_length != 0) { break; } *pad_len = 0; return NT_STATUS_OK; case DCERPC_AUTH_LEVEL_NONE: if (pkt->auth_length != 0) { DEBUG(3, ("Got non-zero auth len on non " "authenticated connection!\n")); return NT_STATUS_INVALID_PARAMETER; } *pad_len = 0; return NT_STATUS_OK; default: DEBUG(3, ("Unimplemented Auth Level %d", auth->auth_level)); return NT_STATUS_INVALID_PARAMETER; } /* Paranioa checks for auth_length. */ if (pkt->auth_length > pkt->frag_length) { return NT_STATUS_INFO_LENGTH_MISMATCH; } if (((unsigned int)pkt->auth_length + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) || ((unsigned int)pkt->auth_length + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) { /* Integer wrap attempt. */ return NT_STATUS_INFO_LENGTH_MISMATCH; } status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer, &auth_info, &auth_length, false); if (!NT_STATUS_IS_OK(status)) { return status; } data = data_blob_const(raw_pkt->data + header_size, pkt_trailer->length - auth_length); full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length - auth_info.credentials.length); switch (auth->auth_type) { case DCERPC_AUTH_TYPE_NONE: return NT_STATUS_OK; default: DEBUG(10, ("GENSEC auth\n")); gensec_security = auth->auth_ctx; status = get_generic_auth_footer(gensec_security, auth->auth_level, &data, &full_pkt, &auth_info.credentials); if (!NT_STATUS_IS_OK(status)) { return status; } break; } /* TODO: remove later * this is still needed because in the server code the * pkt_trailer actually has a copy of the raw data, and they * are still both used in later calls */ if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { memcpy(pkt_trailer->data, data.data, data.length); } *pad_len = auth_info.auth_pad_length; data_blob_free(&auth_info.credentials); return NT_STATUS_OK; }