Пример #1
0
/*
  parse any auth information from a dcerpc alter request
  return false if we can't handle the auth request for some 
  reason (in which case we send a bind_nak (is this true for here?))
*/
bool dcesrv_auth_alter(struct dcesrv_call_state *call)
{
	struct ncacn_packet *pkt = &call->pkt;
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;
	uint32_t auth_length;

	/* on a pure interface change there is no auth blob */
	if (pkt->u.alter.auth_info.length == 0) {
		return true;
	}

	/* We can't work without an existing gensec state */
	if (!dce_conn->auth_state.gensec_security) {
		return false;
	}

	dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
	if (!dce_conn->auth_state.auth_info) {
		return false;
	}

	status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
					  dce_conn->auth_state.auth_info,
					  &auth_length, true);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	return true;
}
Пример #2
0
/*
  parse any auth information from a dcerpc bind request
  return false if we can't handle the auth request for some 
  reason (in which case we send a bind_nak)
*/
bool dcesrv_auth_bind(struct dcesrv_call_state *call)
{
	struct cli_credentials *server_credentials;
	struct ncacn_packet *pkt = &call->pkt;
	struct dcesrv_connection *dce_conn = call->conn;
	struct dcesrv_auth *auth = &dce_conn->auth_state;
	NTSTATUS status;
	uint32_t auth_length;

	if (pkt->u.bind.auth_info.length == 0) {
		dce_conn->auth_state.auth_info = NULL;
		return true;
	}

	dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
	if (!dce_conn->auth_state.auth_info) {
		return false;
	}

	status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
					  dce_conn->auth_state.auth_info,
					  &auth_length, false);
	server_credentials 
		= cli_credentials_init(call);
	if (!server_credentials) {
		DEBUG(1, ("Failed to init server credentials\n"));
		return false;
	}
	
	cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx);
	status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
		talloc_free(server_credentials);
		server_credentials = NULL;
	}

	status = samba_server_gensec_start(dce_conn, call->event_ctx, 
					   call->msg_ctx,
					   call->conn->dce_ctx->lp_ctx,
					   server_credentials,
					   NULL,
					   &auth->gensec_security);

	status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 
					       auth->auth_info->auth_level);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n",
			  (int)auth->auth_info->auth_type,
			  (int)auth->auth_info->auth_level,
			  nt_errstr(status)));
		return false;
	}

	return true;
}
Пример #3
0
/*
  process the final stage of a auth request
*/
bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
{
	struct ncacn_packet *pkt = &call->pkt;
	struct dcesrv_connection *dce_conn = call->conn;
	NTSTATUS status;
	uint32_t auth_length;

	/* We can't work without an existing gensec state, and an new blob to feed it */
	if (!dce_conn->auth_state.auth_info ||
	    !dce_conn->auth_state.gensec_security ||
	    pkt->u.auth3.auth_info.length == 0) {
		return false;
	}

	status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
					  dce_conn->auth_state.auth_info, &auth_length, true);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	/* Pass the extra data we got from the client down to gensec for processing */
	status = gensec_update(dce_conn->auth_state.gensec_security,
			       call, call->event_ctx,
			       dce_conn->auth_state.auth_info->credentials, 
			       &dce_conn->auth_state.auth_info->credentials);
	if (NT_STATUS_IS_OK(status)) {
		status = gensec_session_info(dce_conn->auth_state.gensec_security,
					     dce_conn,
					     &dce_conn->auth_state.session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
			return false;
		}
		/* Now that we are authenticated, go back to the generic session key... */
		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
		return true;
	} else {
		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
			  nt_errstr(status)));
		return false;
	}
}
Пример #4
0
/**
* @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;
}
Пример #5
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);
}
Пример #6
0
/**
* @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 schannel_state *schannel_auth;
	struct auth_ntlmssp_state *ntlmssp_ctx;
	struct spnego_context *spnego_ctx;
	struct gse_context *gse_ctx;
	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:
	case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
		return NT_STATUS_OK;

	case DCERPC_AUTH_TYPE_SPNEGO:
		spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
						   struct spnego_context);
		status = get_spnego_auth_footer(pkt, spnego_ctx,
						auth->auth_level,
						&data, &full_pkt,
						&auth_info.credentials);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	case DCERPC_AUTH_TYPE_NTLMSSP:

		DEBUG(10, ("NTLMSSP auth\n"));

		ntlmssp_ctx = talloc_get_type_abort(auth->auth_ctx,
						struct auth_ntlmssp_state);
		status = get_ntlmssp_auth_footer(ntlmssp_ctx,
						 auth->auth_level,
						 &data, &full_pkt,
						 &auth_info.credentials);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	case DCERPC_AUTH_TYPE_SCHANNEL:

		DEBUG(10, ("SCHANNEL auth\n"));

		schannel_auth = talloc_get_type_abort(auth->auth_ctx,
						      struct schannel_state);
		status = get_schannel_auth_footer(pkt, schannel_auth,
						  auth->auth_level,
						  &data, &full_pkt,
						  &auth_info.credentials);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	case DCERPC_AUTH_TYPE_KRB5:

		DEBUG(10, ("KRB5 auth\n"));

		gse_ctx = talloc_get_type_abort(auth->auth_ctx,
						struct gse_context);
		status = get_gssapi_auth_footer(pkt, gse_ctx,
						auth->auth_level,
						&data, &full_pkt,
						&auth_info.credentials);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	default:
		DEBUG(0, ("process_request_pdu: "
			  "unknown auth type %u set.\n",
			  (unsigned int)auth->auth_type));
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* 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;
}
Пример #7
0
/**
* @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;
}