Пример #1
0
static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
					enum dcerpc_AuthLevel auth_level,
					DATA_BLOB *data, DATA_BLOB *full_pkt,
					DATA_BLOB *auth_token)
{
	if (gensec_security == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	switch (auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
		/* Data portion is encrypted. */
		return gensec_unseal_packet(gensec_security,
					    data->data,
					    data->length,
					    full_pkt->data,
					    full_pkt->length,
					    auth_token);

	case DCERPC_AUTH_LEVEL_INTEGRITY:
	case DCERPC_AUTH_LEVEL_PACKET:
		/* Data is signed. */
		return gensec_check_packet(gensec_security,
					   data->data,
					   data->length,
					   full_pkt->data,
					   full_pkt->length,
					   auth_token);

	default:
		return NT_STATUS_INVALID_PARAMETER;
	}
}
Пример #2
0
/* 
   parse the authentication information on a dcerpc response packet
*/
static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 
					DATA_BLOB *raw_packet,
					struct ncacn_packet *pkt)
{
	struct ndr_pull *ndr;
	NTSTATUS status;
	struct dcerpc_auth auth;
	DATA_BLOB auth_blob;
	enum ndr_err_code ndr_err;

	if (!c->security_state.auth_info ||
	    !c->security_state.generic_state) {
		return NT_STATUS_OK;
	}

	switch (c->security_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
	case DCERPC_AUTH_LEVEL_INTEGRITY:
		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) {
			return NT_STATUS_INVALID_NETWORK_RESPONSE;
		}
		return NT_STATUS_OK;

	default:
		return NT_STATUS_INVALID_LEVEL;
	}

	auth_blob.length = 8 + pkt->auth_length;

	/* check for a valid length */
	if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
		return NT_STATUS_INFO_LENGTH_MISMATCH;
	}

	auth_blob.data = 
		pkt->u.response.stub_and_verifier.data + 
		pkt->u.response.stub_and_verifier.length - auth_blob.length;
	pkt->u.response.stub_and_verifier.length -= auth_blob.length;

	/* pull the auth structure */
	ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
	if (!ndr) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
	}

	ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return ndr_map_error2ntstatus(ndr_err);
	}
	status = NT_STATUS_OK;

	/* check signature or unseal the packet */
	switch (c->security_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
		status = gensec_unseal_packet(c->security_state.generic_state, 
					      mem_ctx, 
					      raw_packet->data + DCERPC_REQUEST_LENGTH,
					      pkt->u.response.stub_and_verifier.length, 
					      raw_packet->data,
					      raw_packet->length - auth.credentials.length,
					      &auth.credentials);
		memcpy(pkt->u.response.stub_and_verifier.data,
		       raw_packet->data + DCERPC_REQUEST_LENGTH,
		       pkt->u.response.stub_and_verifier.length);
		break;
		
	case DCERPC_AUTH_LEVEL_INTEGRITY:
		status = gensec_check_packet(c->security_state.generic_state, 
					     mem_ctx, 
					     pkt->u.response.stub_and_verifier.data, 
					     pkt->u.response.stub_and_verifier.length, 
					     raw_packet->data,
					     raw_packet->length - auth.credentials.length,
					     &auth.credentials);
		break;

	case DCERPC_AUTH_LEVEL_CONNECT:
		/* for now we ignore possible signatures here */
		status = NT_STATUS_OK;
		break;

	default:
		status = NT_STATUS_INVALID_LEVEL;
		break;
	}
	
	/* remove the indicated amount of paddiing */
	if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
		return NT_STATUS_INFO_LENGTH_MISMATCH;
	}
	pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;

	return status;
}
Пример #3
0
/*
  check credentials on a request
*/
bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
{
	struct ncacn_packet *pkt = &call->pkt;
	struct dcesrv_connection *dce_conn = call->conn;
	struct dcerpc_auth auth;
	NTSTATUS status;
	uint32_t auth_length;
	size_t hdr_size = DCERPC_REQUEST_LENGTH;

	if (!dce_conn->auth_state.auth_info ||
	    !dce_conn->auth_state.gensec_security) {
		return true;
	}

	if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
		hdr_size += 16;
	}

	switch (dce_conn->auth_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
	case DCERPC_AUTH_LEVEL_INTEGRITY:
		break;

	case DCERPC_AUTH_LEVEL_CONNECT:
		if (pkt->auth_length != 0) {
			break;
		}
		return true;
	case DCERPC_AUTH_LEVEL_NONE:
		if (pkt->auth_length != 0) {
			return false;
		}
		return true;

	default:
		return false;
	}

	status = dcerpc_pull_auth_trailer(pkt, call,
					  &pkt->u.request.stub_and_verifier,
					  &auth, &auth_length, false);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	pkt->u.request.stub_and_verifier.length -= auth_length;

	/* check signature or unseal the packet */
	switch (dce_conn->auth_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
		status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
					      full_packet->data + hdr_size,
					      pkt->u.request.stub_and_verifier.length, 
					      full_packet->data,
					      full_packet->length-auth.credentials.length,
					      &auth.credentials);
		memcpy(pkt->u.request.stub_and_verifier.data, 
		       full_packet->data + hdr_size,
		       pkt->u.request.stub_and_verifier.length);
		break;

	case DCERPC_AUTH_LEVEL_INTEGRITY:
		status = gensec_check_packet(dce_conn->auth_state.gensec_security,
					     pkt->u.request.stub_and_verifier.data, 
					     pkt->u.request.stub_and_verifier.length,
					     full_packet->data,
					     full_packet->length-auth.credentials.length,
					     &auth.credentials);
		break;

	case DCERPC_AUTH_LEVEL_CONNECT:
		/* for now we ignore possible signatures here */
		status = NT_STATUS_OK;
		break;

	default:
		status = NT_STATUS_INVALID_LEVEL;
		break;
	}

	/* remove the indicated amount of padding */
	if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
		return false;
	}
	pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;

	return NT_STATUS_IS_OK(status);
}
Пример #4
0
WERROR dns_verify_tsig(struct dns_server *dns,
		       TALLOC_CTX *mem_ctx,
		       struct dns_request_state *state,
		       struct dns_name_packet *packet,
		       DATA_BLOB *in)
{
	WERROR werror;
	NTSTATUS status;
	enum ndr_err_code ndr_err;
	bool found_tsig = false;
	uint16_t i, arcount = 0;
	DATA_BLOB tsig_blob, fake_tsig_blob, sig;
	uint8_t *buffer = NULL;
	size_t buffer_len = 0, packet_len = 0;
	struct dns_server_tkey *tkey = NULL;
	struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx,
			struct dns_fake_tsig_rec);


	/* Find the first TSIG record in the additional records */
	for (i=0; i < packet->arcount; i++) {
		if (packet->additional[i].rr_type == DNS_QTYPE_TSIG) {
			found_tsig = true;
			break;
		}
	}

	if (!found_tsig) {
		return WERR_OK;
	}

	/* The TSIG record needs to be the last additional record */
	if (found_tsig && i + 1 != packet->arcount) {
		DEBUG(1, ("TSIG record not the last additional record!\n"));
		return DNS_ERR(FORMAT_ERROR);
	}

	/* We got a TSIG, so we need to sign our reply */
	state->sign = true;

	state->tsig = talloc_zero(state->mem_ctx, struct dns_res_rec);
	if (state->tsig == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}

	werror = dns_copy_tsig(state->tsig, &packet->additional[i],
			       state->tsig);
	if (!W_ERROR_IS_OK(werror)) {
		return werror;
	}

	packet->arcount--;

	tkey = dns_find_tkey(dns->tkeys, state->tsig->name);
	if (tkey == NULL) {
		/*
		 * We must save the name for use in the TSIG error
		 * response and have no choice here but to save the
		 * keyname from the TSIG request.
		 */
		state->key_name = talloc_strdup(state->mem_ctx,
						state->tsig->name);
		if (state->key_name == NULL) {
			return WERR_NOT_ENOUGH_MEMORY;
		}
		state->tsig_error = DNS_RCODE_BADKEY;
		return DNS_ERR(NOTAUTH);
	}

	/*
	 * Remember the keyname that found an existing tkey, used
	 * later to fetch the key with dns_find_tkey() when signing
	 * and adding a TSIG record with MAC.
	 */
	state->key_name = talloc_strdup(state->mem_ctx, tkey->name);
	if (state->key_name == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}

	/* FIXME: check TSIG here */
	if (check_rec == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}

	/* first build and verify check packet */
	check_rec->name = talloc_strdup(check_rec, tkey->name);
	if (check_rec->name == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}
	check_rec->rr_class = DNS_QCLASS_ANY;
	check_rec->ttl = 0;
	check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm);
	if (check_rec->algorithm_name == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}
	check_rec->time_prefix = 0;
	check_rec->time = state->tsig->rdata.tsig_record.time;
	check_rec->fudge = state->tsig->rdata.tsig_record.fudge;
	check_rec->error = 0;
	check_rec->other_size = 0;
	check_rec->other_data = NULL;

	ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, state->tsig,
		(ndr_push_flags_fn_t)ndr_push_dns_res_rec);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(1, ("Failed to push packet: %s!\n",
			  ndr_errstr(ndr_err)));
		return DNS_ERR(SERVER_FAILURE);
	}

	ndr_err = ndr_push_struct_blob(&fake_tsig_blob, mem_ctx, check_rec,
		(ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(1, ("Failed to push packet: %s!\n",
			  ndr_errstr(ndr_err)));
		return DNS_ERR(SERVER_FAILURE);
	}

	/* we need to work some magic here. we need to keep the input packet
	 * exactly like we got it, but we need to cut off the tsig record */
	packet_len = in->length - tsig_blob.length;
	buffer_len = packet_len + fake_tsig_blob.length;
	buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
	if (buffer == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}

	memcpy(buffer, in->data, packet_len);
	memcpy(buffer + packet_len, fake_tsig_blob.data, fake_tsig_blob.length);

	sig.length = state->tsig->rdata.tsig_record.mac_size;
	sig.data = talloc_memdup(mem_ctx, state->tsig->rdata.tsig_record.mac, sig.length);
	if (sig.data == NULL) {
		return WERR_NOT_ENOUGH_MEMORY;
	}

	/* Now we also need to count down the additional record counter */
	arcount = RSVAL(buffer, 10);
	RSSVAL(buffer, 10, arcount-1);

	status = gensec_check_packet(tkey->gensec, buffer, buffer_len,
				    buffer, buffer_len, &sig);
	if (NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
		state->tsig_error = DNS_RCODE_BADSIG;
		return DNS_ERR(NOTAUTH);
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Verifying tsig failed: %s\n", nt_errstr(status)));
		return ntstatus_to_werror(status);
	}

	state->authenticated = true;

	return WERR_OK;
}