From 19bc6f33cc1956db668b2468be3dc47880fbb40a Mon Sep 17 00:00:00 2001 From: Dennis Potman Date: Tue, 14 Apr 2020 20:25:20 +0200 Subject: [PATCH] Access control tests Add test cases for the join_access_control governance setting and for the access control plugin check_create_ and check_remote_ hooks, using a wrapper plugin that simulates failure for each of these, to test the DDSI integration with the access control plugin. This commit also contains fixes for: - an assert on DDS_RETCODE_OK in dds_create_reader and dds_create_writer that cased the application to terminate in case creation of a reader or writer is not allowed by security - do not match a proxy reader that has the 'relay_only' set to true, which is currently unsupported Signed-off-by: Dennis Potman --- src/core/ddsc/src/dds_reader.c | 43 +- src/core/ddsc/src/dds_writer.c | 48 +- .../include/dds/ddsi/ddsi_security_util.h | 31 +- src/core/ddsi/include/dds/ddsi/q_entity.h | 5 +- src/core/ddsi/src/ddsi_security_omg.c | 56 +- src/core/ddsi/src/ddsi_security_util.c | 18 + src/core/ddsi/src/q_entity.c | 50 +- .../include/dds/security/dds_security_api.h | 2 +- src/security/core/tests/CMakeLists.txt | 4 +- src/security/core/tests/access_control.c | 265 +++++-- src/security/core/tests/authentication.c | 5 +- .../tests/common/access_control_wrapper.c | 728 +++++++++++++----- .../tests/common/access_control_wrapper.h | 32 +- .../tests/common/authentication_wrapper.c | 24 +- .../tests/common/authentication_wrapper.h | 16 +- .../core/tests/common/cryptography_wrapper.c | 20 +- .../core/tests/common/cryptography_wrapper.h | 12 +- .../tests/common/security_config_test_utils.c | 9 +- .../tests/common/security_config_test_utils.h | 2 +- src/security/core/tests/common/test_utils.c | 80 +- src/security/core/tests/common/test_utils.h | 9 +- 21 files changed, 1022 insertions(+), 437 deletions(-) diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index 2bd7995..bffe59a 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -30,6 +30,7 @@ #include "dds__builtin.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader) @@ -430,6 +431,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null argument, but that isn't the case here */ + struct ddsi_domaingv *gv = &sub->m_entity.m_domain->gv; rqos = dds_create_qos (); if (qos) ddsi_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK); @@ -437,25 +439,43 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_ktopic->qos) ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0); - ddsi_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0); + ddsi_xqos_mergein_missing (rqos, &gv->default_xqos_rd, ~(uint64_t)0); - if ((rc = ddsi_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) < 0 || - (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK) - { - dds_delete_qos (rqos); + if ((rc = ddsi_xqos_valid (&gv->logconfig, rqos)) < 0 || (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK) goto err_bad_qos; - } /* Additional checks required for built-in topics: we don't want to run into a resource limit on a built-in topic, it is a needless complication */ if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos)) { - dds_delete_qos (rqos); rc = DDS_RETCODE_INCONSISTENT_POLICY; goto err_bad_qos; } + thread_state_awake (lookup_thread_state (), gv); + const struct ddsi_guid * ppguid = dds_entity_participant_guid (&sub->m_entity); + struct participant * pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); + if (pp == NULL) + { + GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); + rc = DDS_RETCODE_BAD_PARAMETER; + goto err_pp_not_found; + } + +#ifdef DDSI_INCLUDE_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create reader permissions */ + if (!q_omg_security_check_create_reader (pp, gv->config.domainId, tp->m_stopic->name, rqos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } + } +#endif + /* Create reader and associated read cache (if not provided by caller) */ struct dds_reader * const rd = dds_alloc (sizeof (*rd)); const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); @@ -474,8 +494,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe it; and then invoke those listeners that are in the pending set */ dds_entity_init_complete (&rd->m_entity); - thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv); - rc = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, dds_entity_participant_guid (&sub->m_entity), tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); + rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ thread_state_asleep (lookup_thread_state ()); @@ -487,7 +506,13 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe dds_subscriber_unlock (sub); return reader; +#ifdef DDSI_INCLUDE_SECURITY +err_not_allowed: +#endif +err_pp_not_found: + thread_state_asleep (lookup_thread_state ()); err_bad_qos: + dds_delete_qos (rqos); dds_topic_allow_set_qos (tp); err_pp_mismatch: dds_topic_unpin (tp); diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index caedd81..12d2676 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -20,6 +20,7 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds__writer.h" #include "dds__listener.h" #include "dds__init.h" @@ -312,6 +313,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_topic_defer_set_qos (tp); /* Merge Topic & Publisher qos */ + struct ddsi_domaingv *gv = &pub->m_entity.m_domain->gv; wqos = dds_create_qos (); if (qos) ddsi_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK); @@ -319,29 +321,47 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_ktopic->qos) ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0); - ddsi_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0); + ddsi_xqos_mergein_missing (wqos, &gv->default_xqos_wr, ~(uint64_t)0); - if ((rc = ddsi_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 || - (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) - { - dds_delete_qos(wqos); + if ((rc = ddsi_xqos_valid (&gv->logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) goto err_bad_qos; + + thread_state_awake (lookup_thread_state (), gv); + const struct ddsi_guid *ppguid = dds_entity_participant_guid (&pub->m_entity); + struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); + if (pp == NULL) + { + GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); + rc = DDS_RETCODE_BAD_PARAMETER; + goto err_pp_not_found; } +#ifdef DDSI_INCLUDE_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create writer permissions */ + if (!q_omg_security_check_create_writer (pp, gv->config.domainId, tp->m_stopic->name, wqos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } + } +#endif + /* Create writer */ - ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.xmit_conn; + ddsi_tran_conn_t conn = gv->xmit_conn; struct dds_writer * const wr = dds_alloc (sizeof (*wr)); const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK); wr->m_topic = tp; dds_entity_add_ref_locked (&tp->m_entity); - wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), pub->m_entity.m_domain->gv.config.xpack_send_async); + wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), gv->config.xpack_send_async); wrinfo = whc_make_wrinfo (wr, wqos); - wr->m_whc = whc_new (&pub->m_entity.m_domain->gv, wrinfo); + wr->m_whc = whc_new (gv, wrinfo); whc_free_wrinfo (wrinfo); - wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch; + wr->whc_batch = gv->config.whc_batch; - thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv); - rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, dds_entity_participant_guid (&pub->m_entity), tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); + rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); assert(rc == DDS_RETCODE_OK); thread_state_asleep (lookup_thread_state ()); @@ -355,7 +375,13 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_publisher_unlock (pub); return writer; +#ifdef DDSI_INCLUDE_SECURITY +err_not_allowed: +#endif +err_pp_not_found: + thread_state_asleep (lookup_thread_state ()); err_bad_qos: + dds_delete_qos(wqos); dds_topic_allow_set_qos (tp); err_pp_mismatch: dds_topic_unpin (tp); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h index 7c03496..188675e 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h @@ -22,64 +22,37 @@ extern "C" { #endif void g_omg_shallow_copy_StringSeq(DDS_Security_StringSeq *dst, const ddsi_stringseq_t *src); - void g_omg_shallow_free_StringSeq(DDS_Security_StringSeq *obj); - void q_omg_copy_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src); - void q_omg_shallow_copyin_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src); - void q_omg_shallow_copyout_PropertySeq(dds_propertyseq_t *dst, const DDS_Security_PropertySeq *src); - void q_omg_shallow_free_PropertySeq(DDS_Security_PropertySeq *obj); - void q_omg_shallow_copyin_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *dst, const dds_binarypropertyseq_t *src); - void q_omg_shallow_copyout_BinaryPropertySeq(dds_binarypropertyseq_t *dst, const DDS_Security_BinaryPropertySeq *src); - void q_omg_shallow_free_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *obj); - void q_omg_shallow_copy_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *dst, const dds_property_qospolicy_t *src); - void q_omg_shallow_copy_security_qos(DDS_Security_Qos *dst, const struct dds_qos *src); - void q_omg_shallow_free_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *obj); - void q_omg_shallow_free_security_qos(DDS_Security_Qos *obj); - void q_omg_security_dataholder_copyin(nn_dataholder_t *dh, const DDS_Security_DataHolder *holder); - void q_omg_security_dataholder_copyout(DDS_Security_DataHolder *holder, const nn_dataholder_t *dh); - void q_omg_shallow_copyin_DataHolder(DDS_Security_DataHolder *dst, const nn_dataholder_t *src); - void q_omg_shallow_copyout_DataHolder(nn_dataholder_t *dst, const DDS_Security_DataHolder *src); - void q_omg_shallow_free_DataHolder(DDS_Security_DataHolder *obj); - void q_omg_shallow_free_nn_dataholder(nn_dataholder_t *holder); - void q_omg_shallow_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src); - void q_omg_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src); - void q_omg_shallow_copyout_DataHolderSeq(nn_dataholderseq_t *dst, const DDS_Security_DataHolderSeq *src); - void q_omg_shallow_free_DataHolderSeq(DDS_Security_DataHolderSeq *obj); - void q_omg_shallow_free_nn_dataholderseq(nn_dataholderseq_t *obj); - void q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const ddsi_plist_t *plist); - void q_omg_shallow_free_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *obj); - void q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo); - void q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *obj); - void q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo); - void q_omg_shallow_free_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *obj); +void q_omg_shallow_copy_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *dst, const char *topic_name, const char *type_name); +void q_omg_shallow_free_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *obj); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h index a6f6543..9d2765e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -642,9 +642,8 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi GUID "ppguid". May return NULL if participant unknown or writer/reader already known. */ -dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); - -dds_return_t new_reader (struct reader **rd_out, struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); void update_reader_qos (struct reader *rd, const struct dds_qos *xqos); void update_writer_qos (struct writer *wr, const struct dds_qos *xqos); diff --git a/src/core/ddsi/src/ddsi_security_omg.c b/src/core/ddsi/src/ddsi_security_omg.c index aae4ebf..c7f2b10 100644 --- a/src/core/ddsi/src/ddsi_security_omg.c +++ b/src/core/ddsi/src/ddsi_security_omg.c @@ -2136,7 +2136,8 @@ bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *p struct dds_security_context *sc = q_omg_security_get_secure_context(pp); DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; DDS_Security_PublicationBuiltinTopicDataSecure publication_data; - bool ok = true; + DDS_Security_TopicBuiltinTopicData topic_data; + bool result = true; if (!sc) return true; @@ -2167,19 +2168,32 @@ bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *p else { q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(&publication_data, &pwr->e.guid, pwr->c.xqos, &pwr->c.security_info); - ok = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception); - q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data); - if (!ok) + result = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception); + if (!result) { if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, publication_data.topic_name)) EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote writer "PGUIDFMT": %s", PGUID(pwr->e.guid)); else DDS_Security_Exception_reset(&exception); } + else + { + q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, publication_data.topic_name, publication_data.type_name); + result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception); + q_omg_shallow_free_TopicBuiltinTopicData(&topic_data); + if (!result) + { + if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, publication_data.topic_name)) + EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote topic %s: %s", publication_data.topic_name); + else + DDS_Security_Exception_reset(&exception); + } + } + q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data); } } - return ok; + return result; } static void send_reader_crypto_tokens(struct reader *rd, struct proxy_writer *pwr, DDS_Security_DatareaderCryptoHandle local_crypto, DDS_Security_DatawriterCryptoHandle remote_crypto) @@ -2363,7 +2377,10 @@ bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *p struct ddsi_domaingv *gv = pp->e.gv; struct dds_security_context *sc = q_omg_security_get_secure_context(pp); DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; - bool ok = true; + DDS_Security_SubscriptionBuiltinTopicDataSecure subscription_data; + DDS_Security_TopicBuiltinTopicData topic_data; + DDS_Security_boolean sec_relay_only; + bool result = true; /* relay_only is meaningless in all cases except the one where the access control plugin says otherwise */ *relay_only = false; @@ -2396,25 +2413,34 @@ bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *p } else { - DDS_Security_SubscriptionBuiltinTopicDataSecure subscription_data; - DDS_Security_boolean sec_relay_only; - q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(&subscription_data, &prd->e.guid, prd->c.xqos, &prd->c.security_info); - ok = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, &sec_relay_only, &exception); - q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data); - if (ok) - *relay_only = !!sec_relay_only; - else + result = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, &sec_relay_only, &exception); + if (!result) { if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, subscription_data.topic_name)) EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote reader "PGUIDFMT": %s", PGUID(prd->e.guid)); else DDS_Security_Exception_reset(&exception); } + else + { + *relay_only = !!sec_relay_only; + q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, subscription_data.topic_name, subscription_data.type_name); + result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception); + q_omg_shallow_free_TopicBuiltinTopicData(&topic_data); + if (!result) + { + if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, subscription_data.topic_name)) + EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote topic %s: %s", subscription_data.topic_name); + else + DDS_Security_Exception_reset(&exception); + } + } + q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data); } } - return ok; + return result; } void q_omg_get_proxy_endpoint_security_info(const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const ddsi_plist_t *plist, nn_security_info_t *info) diff --git a/src/core/ddsi/src/ddsi_security_util.c b/src/core/ddsi/src/ddsi_security_util.c index 388fb4e..11f39b5 100644 --- a/src/core/ddsi/src/ddsi_security_util.c +++ b/src/core/ddsi/src/ddsi_security_util.c @@ -703,6 +703,24 @@ q_omg_shallow_free_PublicationBuiltinTopicDataSecure( g_omg_shallow_free_StringSeq(&obj->partition.name); } +void +q_omg_shallow_copy_TopicBuiltinTopicData( + DDS_Security_TopicBuiltinTopicData *dst, + const char *topic_name, + const char *type_name) +{ + memset(dst, 0, sizeof(DDS_Security_TopicBuiltinTopicData)); + dst->name = (DDS_Security_string)topic_name; + dst->type_name = (DDS_Security_string)type_name; +} + +void +q_omg_shallow_free_TopicBuiltinTopicData( + DDS_Security_TopicBuiltinTopicData *obj) +{ + DDSRT_UNUSED_ARG(obj); +} + #endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 2669c09..c1f4573 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -2771,6 +2771,7 @@ void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_wri static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, ddsrt_mtime_t tnow) { + struct ddsi_domaingv *gv = wr->e.gv; const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); const int isb1 = (is_builtin_entityid (prd->e.guid.entityid, prd->c.vendor) != 0); dds_qos_policy_id_t reason; @@ -2790,13 +2791,15 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re if (!q_omg_security_check_remote_reader_permissions (prd, wr->e.gv->config.domainId, wr->c.pp, &relay_only)) { - EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") not allowed by security\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + GVLOGDISC ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") not allowed by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); + } + else if (relay_only) + { + GVWARNING ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") relay_only not supported\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); } else if (!q_omg_security_match_remote_reader_enabled (wr, prd, relay_only, &crypto_handle)) { - EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") waiting for approval by security\n", - PGUID (wr->e.guid), PGUID (prd->e.guid)); + GVLOGDISC ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") waiting for approval by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); } else { @@ -3801,28 +3804,11 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g return 0; } -dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) { - struct participant *pp; dds_return_t rc; uint32_t kind; - if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL) - { - GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_BAD_PARAMETER; - } - -#ifdef DDSI_INCLUDE_SECURITY - /* Check if DDS Security is enabled */ - if (q_omg_participant_is_secure (pp)) - { - /* ask to access control security plugin for create writer permissions */ - if (!q_omg_security_check_create_writer (pp, gv->config.domainId, topic->name, xqos)) - return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; - } -#endif - /* participant can't be freed while we're mucking around cos we are awake and do not touch the thread's vtime (entidx_lookup already verifies we're awake) */ @@ -4367,10 +4353,9 @@ static dds_return_t new_reader_guid dds_return_t new_reader ( struct reader **rd_out, - struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, - const struct ddsi_guid *ppguid, + struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, @@ -4378,26 +4363,9 @@ dds_return_t new_reader void * status_cbarg ) { - struct participant * pp; dds_return_t rc; uint32_t kind; - if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL) - { - GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_BAD_PARAMETER; - } - -#ifdef DDSI_INCLUDE_SECURITY - /* Check if DDS Security is enabled */ - if (q_omg_participant_is_secure (pp)) - { - /* ask to access control security plugin for create writer permissions */ - if (!q_omg_security_check_create_reader (pp, gv->config.domainId, topic->name, xqos)) - return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; - } -#endif - rdguid->prefix = pp->e.guid.prefix; kind = topic->topickind_no_key ? NN_ENTITYID_KIND_READER_NO_KEY : NN_ENTITYID_KIND_READER_WITH_KEY; if ((rc = pp_allocate_entityid (&rdguid->entityid, kind, pp)) < 0) diff --git a/src/security/api/include/dds/security/dds_security_api.h b/src/security/api/include/dds/security/dds_security_api.h index 55ab6a0..d242b02 100644 --- a/src/security/api/include/dds/security/dds_security_api.h +++ b/src/security/api/include/dds/security/dds_security_api.h @@ -25,7 +25,7 @@ extern "C" { /* Integration functions for Security plugins */ typedef int (*plugin_init)(const char *argument, void **context, struct ddsi_domaingv *gv); -typedef int (*plugin_finalize)(void *context); +typedef int (*plugin_finalize)(void *context); #if defined (__cplusplus) } diff --git a/src/security/core/tests/CMakeLists.txt b/src/security/core/tests/CMakeLists.txt index 35337ab..299487e 100644 --- a/src/security/core/tests/CMakeLists.txt +++ b/src/security/core/tests/CMakeLists.txt @@ -68,7 +68,7 @@ set(security_core_test_sources ) if(ENABLE_SSL) - add_wrapper(access_control "") + add_wrapper(access_control dds_security_ac) add_wrapper(authentication dds_security_auth) add_wrapper(cryptography dds_security_crypto) @@ -108,7 +108,7 @@ configure_file("common/config_env.h.in" "common/config_env.h") target_link_libraries(cunit_security_core PRIVATE ddsc security_api SecurityCoreTests) if(ENABLE_SSL) - target_link_libraries(cunit_security_core PRIVATE dds_security_auth dds_security_ac dds_security_crypto dds_security_authentication_wrapper dds_security_cryptography_wrapper) + target_link_libraries(cunit_security_core PRIVATE dds_security_auth dds_security_ac dds_security_crypto dds_security_access_control_wrapper dds_security_authentication_wrapper dds_security_cryptography_wrapper) target_link_libraries(cunit_security_core PRIVATE OpenSSL::SSL) endif() target_include_directories(cunit_security_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/src/security/core/tests/access_control.c b/src/security/core/tests/access_control.c index 9fdf1ae..3b04fc6 100644 --- a/src/security/core/tests/access_control.c +++ b/src/security/core/tests/access_control.c @@ -47,13 +47,13 @@ static const char *config = " " " " " " - " " + " " " data:,${TEST_IDENTITY_CERTIFICATE}" " data:,${TEST_IDENTITY_PRIVATE_KEY}" " data:,${TEST_IDENTITY_CA_CERTIFICATE}" " " " " - " " + " " " ${INCL_GOV:+}" " ${INCL_PERM_CA:+}${TEST_PERMISSIONS_CA}${INCL_PERM_CA:+}" " ${INCL_PERM:+}" @@ -65,19 +65,22 @@ static const char *config = ""; #define MAX_DOMAINS 10 -#define DDS_DOMAINID +#define DDS_DOMAINID 0 + +#define PF_F "file:" +#define PF_D "data:," static dds_entity_t g_domain[MAX_DOMAINS]; static dds_entity_t g_participant[MAX_DOMAINS]; -static dds_entity_t g_pubsub[MAX_DOMAINS]; -static dds_entity_t g_topic[MAX_DOMAINS]; static uint32_t g_topic_nr = 0; static void access_control_init( - const char * id_certs[], const char * id_keys[], const char * id_ca[], bool exp_pp_fail[], size_t n_nodes, - bool incl_gov, const char * gov, - bool incl_perm, const char * perm, - bool incl_ca, const char * ca) + size_t n_nodes, + const char * id_certs[], const char * id_keys[], const char * id_ca[], bool exp_pp_fail[], + const char * ac_init_fns[], const char * ac_fini_fns[], + bool incl_gov[], const char * gov[], + bool incl_perm[], const char * perm[], + bool incl_ca[], const char * ca[]) { CU_ASSERT_FATAL (n_nodes <= MAX_DOMAINS); for (size_t i = 0; i < n_nodes; i++) @@ -86,12 +89,14 @@ static void access_control_init( { "TEST_IDENTITY_CERTIFICATE", id_certs[i], 1 }, { "TEST_IDENTITY_PRIVATE_KEY", id_keys[i], 1 }, { "TEST_IDENTITY_CA_CERTIFICATE", id_ca[i], 1 }, - { "INCL_GOV", incl_gov ? "1" : "", 2 }, - { "INCL_PERM", incl_perm ? "1" : "", 2 }, - { "INCL_PERM_CA", incl_ca ? "1" : "", 2 }, - { "TEST_GOVERNANCE", gov, 1 }, - { "TEST_PERMISSIONS", perm, 1 }, - { "TEST_PERMISSIONS_CA", ca, 1 }, + { "ACCESS_CONTROL_INIT", ac_init_fns ? ac_init_fns[i] : NULL, 1 }, + { "ACCESS_CONTROL_FINI", ac_fini_fns ? ac_fini_fns[i] : NULL, 1 }, + { "INCL_GOV", incl_gov[i] ? "1" : "", 2 }, + { "INCL_PERM", incl_perm[i] ? "1" : "", 2 }, + { "INCL_PERM_CA", incl_ca[i] ? "1" : "", 2 }, + { "TEST_GOVERNANCE", gov[i], 1 }, + { "TEST_PERMISSIONS", perm[i], 1 }, + { "TEST_PERMISSIONS_CA", ca[i], 1 }, { NULL, NULL, 0 } }; char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); @@ -109,9 +114,6 @@ static void access_control_fini(size_t n) CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain[i]), DDS_RETCODE_OK); } - -#define PF_F "file:" -#define PF_D "data:," #define GOV_F PF_F COMMON_ETC_PATH("default_governance.p7s") #define GOV_FNE PF_F COMMON_ETC_PATH("default_governance_non_existing.p7s") #define GOV_DI PF_D COMMON_ETC_PATH("default_governance.p7s") @@ -149,14 +151,18 @@ CU_Theory((const char * test_descr, const char * gov, const char * perm, const c ddssec_access_control, config_parameters_file) { print_test_msg ("running test config_parameters_file: %s\n", test_descr); + bool has_gov = incl_empty_els || strlen (gov); + bool has_perm = incl_empty_els || strlen (perm); + bool has_ca = incl_empty_els || strlen (ca); access_control_init ( + 2, (const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE }, (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, (const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE }, - (bool []) { exp_fail, exp_fail }, 2, - incl_empty_els || strlen (gov), gov, - incl_empty_els || strlen (perm), perm, - incl_empty_els || strlen (ca), ca); + (bool []) { exp_fail, exp_fail }, NULL, NULL, + (bool []) { has_gov, has_gov }, (const char *[]) { gov, gov }, + (bool []) { has_perm, has_perm }, (const char *[]) { perm, perm }, + (bool []) { has_ca, has_ca }, (const char *[]) { ca, ca }); access_control_fini (2); } @@ -170,8 +176,8 @@ CU_TheoryDataPoints(ddssec_access_control, permissions_expiry) = { /* | */"valid -1 minute until now", /* | | */"1s valid, create pp after 1100ms", /* | | | */"node 2 permissions expired", - /* | | | | */"node 1 3s valid, write/read for 10s", - /* | | | | | */"node 2 3s valid, write/read for 10s"), + /* | | | | */"node 1 4s valid, write/read for 10s", + /* | | | | | */"node 2 4s valid, write/read for 10s"), CU_DataPoints(int32_t, 0, -M(1), 0, 0, 0, 0), /* node 1 permissions not before (offset from local time) */ CU_DataPoints(int32_t, M(1), 0, S(1), D(1), S(4), D(1)), /* node 1 permissions not after (offset from local time) */ CU_DataPoints(int32_t, 0, -M(1), 0, -D(1), 0, 0), /* node 2 permissions not before (offset from local time) */ @@ -179,14 +185,18 @@ CU_TheoryDataPoints(ddssec_access_control, permissions_expiry) = { CU_DataPoints(uint32_t, 0, 0, 1100, 0, 0, 0), /* delay (ms) after generating permissions */ CU_DataPoints(bool, false, true, true, false, false, false), /* expect pp 1 create failure */ CU_DataPoints(bool, false, true, true, true, false, false), /* expect pp 2 create failure */ - CU_DataPoints(uint32_t, 1, 0, 0, 0, 10000, 10000), /* write/read data during x ms */ + CU_DataPoints(uint32_t, 1, 0, 0, 0, 10000, 10000), /* write/read data during x ms */ CU_DataPoints(bool, false, false, false, false, true, true), /* expect read data failure */ }; +#undef S +#undef D +#undef H +#undef M CU_Theory( (const char * test_descr, int32_t perm1_not_before, int32_t perm1_not_after, int32_t perm2_not_before, int32_t perm2_not_after, uint32_t delay_perm, bool exp_pp1_fail, bool exp_pp2_fail, uint32_t write_read_dur, bool exp_read_fail), - ddssec_access_control, permissions_expiry, .timeout=20) + ddssec_access_control, permissions_expiry, .timeout=30) { print_test_msg ("running test permissions_expiry: %s\n", test_descr); @@ -195,32 +205,38 @@ CU_Theory( /* create ca and id1/id2 certs that will not expire during this test */ char *ca, *id1, *id2, *id1_subj, *id2_subj; - ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, D(1)); - id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, D(1), &id1_subj); - id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, D(1), &id2_subj); + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); /* localtime will be converted to gmtime in get_permissions_grant */ dds_time_t now = dds_time (); char * perm_topic = get_permissions_topic (topic_name); char * grants[] = { - get_permissions_grant ("id1", id1_subj, now + DDS_SECS(perm1_not_before), now + DDS_SECS(perm1_not_after), perm_topic, perm_topic, NULL), - get_permissions_grant ("id2", id2_subj, now + DDS_SECS(perm2_not_before), now + DDS_SECS(perm2_not_after), perm_topic, perm_topic, NULL) }; + get_permissions_grant ("id1", id1_subj, NULL, now + DDS_SECS(perm1_not_before), now + DDS_SECS(perm1_not_after), perm_topic, perm_topic, NULL), + get_permissions_grant ("id2", id2_subj, NULL, now + DDS_SECS(perm2_not_before), now + DDS_SECS(perm2_not_after), perm_topic, perm_topic, NULL) }; char * perm_config = get_permissions_config (grants, 2, true); dds_sleepfor (DDS_MSECS (delay_perm)); + const char * def_gov = PF_F COMMON_ETC_PATH("default_governance.p7s"); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); access_control_init ( + 2, (const char *[]) { id1, id2 }, (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, (const char *[]) { ca, ca }, - (bool []) { exp_pp1_fail, exp_pp2_fail }, 2, - true, PF_F COMMON_ETC_PATH("default_governance.p7s"), - true, perm_config, - true, PF_F COMMON_ETC_PATH("default_permissions_ca.pem")); + (bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { def_gov, def_gov }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); if (write_read_dur > 0) { dds_entity_t wr = 0, rd = 0; - rd_wr_init (g_participant[0], &g_pubsub[0], &g_topic[0], &wr, g_participant[1], &g_pubsub[1], &g_topic[1], &rd, topic_name); + dds_entity_t pub, sub; + dds_entity_t topic0, topic1; + rd_wr_init (g_participant[0], &pub, &topic0, &wr, g_participant[1], &sub, &topic1, &rd, topic_name); + sync_writer_to_readers(g_participant[0], wr, 1); write_read_for (wr, g_participant[1], rd, DDS_MSECS (write_read_dur), false, exp_read_fail); } @@ -236,9 +252,6 @@ CU_Theory( ddsrt_free (id1); ddsrt_free (id2); } -#undef D -#undef H -#undef M #define N_RD 1 // N_RD > 1 not yet implemented @@ -256,9 +269,10 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20) // 1st node used as reader, other nodes as writer print_test_msg ("creating permissions grants\n"); - const char *id[N_NODES], *pk[N_NODES], *ca_list[N_NODES]; + const char *id[N_NODES], *pk[N_NODES], *ca_list[N_NODES], *gov[N_NODES], *perm_conf[N_NODES], *perm_ca[N_NODES]; char * id_subj[N_NODES], *grants[N_NODES]; - bool exp_fail[N_NODES]; + bool exp_fail[N_NODES], incl_el[N_NODES]; + for (int i = 0; i < N_NODES; i++) { char *id_name; @@ -267,20 +281,25 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20) ca_list[i] = ca; id[i] = generate_identity (ca_list[i], TEST_IDENTITY_CA1_PRIVATE_KEY, id_name, pk[i], 0, 3600, &id_subj[i]); exp_fail[i] = false; + gov[i] = PF_F COMMON_ETC_PATH ("default_governance.p7s"); + perm_ca[i] = PF_F COMMON_ETC_PATH ("default_permissions_ca.pem"); + incl_el[i] = true; dds_duration_t v = DDS_SECS(i < N_RD ? 3600 : PERM_EXP_BASE + 2 * i); /* readers should not expire */ dds_time_t t_exp = ddsrt_time_add_duration (t_perm, v); if (i >= N_RD) print_test_msg ("w[%d] grant expires at %d.%06d\n", i - N_RD, (int32_t) (t_exp / DDS_NSECS_IN_SEC), (int32_t) (t_exp % DDS_NSECS_IN_SEC) / 1000); - grants[i] = get_permissions_grant (id_name, id_subj[i], t_perm, t_exp, perm_topic, perm_topic, NULL); + grants[i] = get_permissions_grant (id_name, id_subj[i], NULL, t_perm, t_exp, perm_topic, perm_topic, NULL); ddsrt_free (id_name); } - char * perm_config = get_permissions_config (grants, N_NODES, true); + char * perm_config_str = get_permissions_config (grants, N_NODES, true); + for (int i = 0; i < N_NODES; i++) + perm_conf[i] = perm_config_str; + access_control_init ( - id, pk, ca_list, exp_fail, N_NODES, - true, PF_F COMMON_ETC_PATH ("default_governance.p7s"), - true, perm_config, - true, PF_F COMMON_ETC_PATH ("default_permissions_ca.pem")); + N_NODES, + id, pk, ca_list, exp_fail, NULL, NULL, + incl_el, gov, incl_el, perm_conf, incl_el, perm_ca); dds_qos_t * qos = dds_create_qos (); CU_ASSERT_FATAL (qos != NULL); @@ -374,6 +393,156 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20) } ddsrt_free (ca); ddsrt_free (perm_topic); - ddsrt_free (perm_config); + ddsrt_free (perm_config_str); } +#undef N_RD +#undef N_WR #undef N_NODES +#undef PERM_EXP_BASE + +#define na false +CU_TheoryDataPoints(ddssec_access_control, hooks) = { + CU_DataPoints(const char *, + /* */"init_test_access_control_local_participant_not_allowed", + /* | */"init_test_access_control_local_topic_not_allowed", + /* | | */"init_test_access_control_local_publishing_not_allowed", + /* | | | */"init_test_access_control_local_subscribing_not_allowed", + /* | | | | */"init_test_access_control_remote_permissions_invalidate", + /* | | | | | */"init_test_access_control_remote_participant_not_allowed", + /* | | | | | | */"init_test_access_control_remote_topic_not_allowed", + /* | | | | | | | */"init_test_access_control_remote_writer_not_allowed", + /* | | | | | | | | */"init_test_access_control_remote_reader_not_allowed", + /* | | | | | | | | | */"init_test_access_control_remote_reader_relay_only"), + CU_DataPoints(bool, true, false, false, false, false, false, false, false, false, false), // exp_pp_fail + CU_DataPoints(bool, na, true, false, false, false, false, false, false, false, false), // exp_local_topic_fail + CU_DataPoints(bool, na, false, false, false, false, false, false, false, false, false), // exp_remote_topic_fail + CU_DataPoints(bool, na, na, true, false, false, false, false, false, false, false), // exp_wr_fail + CU_DataPoints(bool, na, na, false, true, false, false, false, false, false, false), // exp_rd_fail + CU_DataPoints(bool, na, na, na, na, true, true, true, false, true, true), // exp_wr_rd_sync_fail + CU_DataPoints(bool, na, na, false, na, true, true, true, true, false, false), // exp_rd_wr_sync_fail +}; +#undef na +CU_Theory( + (const char * init_fn, bool exp_pp_fail, bool exp_local_topic_fail, bool exp_remote_topic_fail, bool exp_wr_fail, bool exp_rd_fail, bool exp_wr_rd_sync_fail, bool exp_rd_wr_sync_fail), + ddssec_access_control, hooks, .timeout=40) +{ + print_test_msg ("running test access_control_hooks: %s\n", init_fn); + + const char * def_gov = PF_F COMMON_ETC_PATH("default_governance.p7s"); + const char * def_perm = PF_F COMMON_ETC_PATH("default_permissions.p7s"); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE }, + (bool []) { exp_pp_fail, false }, + (const char *[]) { init_fn, "init_test_access_control_wrapped" }, (const char *[]) { "finalize_test_access_control_not_allowed", "finalize_test_access_control_wrapped" }, + (bool []) { true, true, true }, (const char *[]) { def_gov, def_gov }, + (bool []) { true, true, true }, (const char *[]) { def_perm, def_perm }, + (bool []) { true, true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (!exp_pp_fail) + { + dds_entity_t lwr = 0, rwr = 0, lrd = 0, rrd = 0; + dds_entity_t ltopic[2], rtopic[2]; + dds_entity_t lpub, lsub, rpub, rsub; + char topic_name[100]; + + // Local writer, remote reader + create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init_fail ( + g_participant[0], &lpub, <opic[0], &lwr, + g_participant[1], &rsub, &rtopic[0], &rrd, + topic_name, exp_local_topic_fail, exp_wr_fail, exp_remote_topic_fail, false); + if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_wr_fail) + sync_writer_to_readers (g_participant[0], lwr, exp_wr_rd_sync_fail ? 0 : 1); + + // Local reader, remote writer + create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init_fail ( + g_participant[1], &rpub, &rtopic[1], &rwr, + g_participant[0], &lsub, <opic[1], &lrd, + topic_name, exp_remote_topic_fail, false, exp_local_topic_fail, exp_rd_fail); + if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_rd_fail) + sync_reader_to_writers (g_participant[0], lrd, exp_rd_wr_sync_fail ? 0 : 1); + } + + access_control_fini (2); +} + +#define na false +CU_TheoryDataPoints(ddssec_access_control, join_access_control) = { + CU_DataPoints(const char *, + /* */"no join access control", + /* | */"join access control pp1, valid", + /* | | */"join access control pp1 and pp2, valid", + /* | | | */"join access control pp1, invalid", + /* | | | | */"join access control pp1 and pp2, invalid"), + CU_DataPoints(bool, false, true, true, true, true), /* join access control pp 1 enabled */ + CU_DataPoints(bool, false, false, true, false, true), /* join access control pp 2 enabled */ + CU_DataPoints(bool, false, false, false, true, true), /* permissions pp 1 invalid */ + CU_DataPoints(bool, false, false, false, false, true), /* permissions pp 2 invalid */ + CU_DataPoints(bool, false, false, false, true, true), /* expect pp 1 create failure */ + CU_DataPoints(bool, false, false, false, false, true), /* expect pp 2 create failure */ + CU_DataPoints(bool, false, false, false, na, na), /* expect handshake failure */ +}; +#undef na +CU_Theory( + (const char * test_descr, bool join_ac_pp1, bool join_ac_pp2, bool perm_inv_pp1, bool perm_inv_pp2, bool exp_pp1_fail, bool exp_pp2_fail, bool exp_hs_fail), + ddssec_access_control, join_access_control, .timeout=30) +{ + print_test_msg ("running test join_access_control: %s\n", test_descr); + + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + /* localtime will be converted to gmtime in get_permissions_grant */ + dds_time_t now = dds_time (); + char * perm_topic = get_permissions_topic (topic_name); + char * grants[] = { + get_permissions_grant ("id1", id1_subj, perm_inv_pp1 ? "99" : NULL, now, now + DDS_SECS(3600), perm_topic, perm_topic, NULL), + get_permissions_grant ("id2", id2_subj, perm_inv_pp2 ? "99" : NULL, now, now + DDS_SECS(3600), perm_topic, perm_topic, NULL) }; + char * perm_config = get_permissions_config (grants, 2, true); + + struct kvp governance_vars_pp1[] = { { "ENABLE_JOIN_AC", join_ac_pp1 ? "true" : "false", 1 }, { NULL, NULL, 0 } }; + struct kvp governance_vars_pp2[] = { { "ENABLE_JOIN_AC", join_ac_pp2 ? "true" : "false", 1 }, { NULL, NULL, 0 } }; + + char * gov_config_pp1 = get_governance_config (governance_vars_pp1, true); + char * gov_config_pp2 = get_governance_config (governance_vars_pp2, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config_pp1, gov_config_pp2 }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (!exp_pp1_fail && !exp_pp2_fail) + validate_handshake (DDS_DOMAINID, exp_hs_fail, NULL, NULL, NULL); + + access_control_fini (2); + + ddsrt_free (gov_config_pp1); + ddsrt_free (gov_config_pp2); + ddsrt_free (perm_topic); + ddsrt_free (grants[0]); + ddsrt_free (grants[1]); + ddsrt_free (perm_config); + ddsrt_free (ca); + ddsrt_free (id1_subj); + ddsrt_free (id2_subj); + ddsrt_free (id1); + ddsrt_free (id2); +} diff --git a/src/security/core/tests/authentication.c b/src/security/core/tests/authentication.c index 7a9a21a..fe6aa6a 100644 --- a/src/security/core/tests/authentication.c +++ b/src/security/core/tests/authentication.c @@ -309,8 +309,8 @@ CU_Theory( dds_time_t now = dds_time (); char * grants[] = { - get_permissions_grant ("id1", id1_subj, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL), - get_permissions_grant ("id2", id2_subj, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL) }; + get_permissions_grant ("id1", id1_subj, NULL, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL), + get_permissions_grant ("id2", id2_subj, NULL, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL) }; char * perm_config = get_permissions_config (grants, 2, true); authentication_init (id1, ID1K, ca, id2, ID1K, ca, NULL, perm_config, id1_local_fail, id2_local_fail); validate_handshake (DDS_DOMAINID1, id1_local_fail, NULL, NULL, NULL); @@ -318,6 +318,7 @@ CU_Theory( if (write_read_dur > 0) { rd_wr_init (g_participant1, &g_pub, &g_pub_tp, &g_wr, g_participant2, &g_sub, &g_sub_tp, &g_rd, topic_name); + sync_writer_to_readers(g_participant1, g_wr, 1); write_read_for (g_wr, g_participant2, g_rd, DDS_MSECS (write_read_dur), false, exp_read_fail); } authentication_fini (!id1_local_fail, !id2_local_fail); diff --git a/src/security/core/tests/common/access_control_wrapper.c b/src/security/core/tests/common/access_control_wrapper.c index 3ba5b68..aead7e6 100644 --- a/src/security/core/tests/common/access_control_wrapper.c +++ b/src/security/core/tests/common/access_control_wrapper.c @@ -20,18 +20,49 @@ #include "dds/security/core/dds_security_utils.h" #include "access_control_wrapper.h" +int init_access_control(const char *argument, void **context, struct ddsi_domaingv *gv); +int finalize_access_control(void *context); + enum ac_plugin_mode { PLUGIN_MODE_ALL_OK, + PLUGIN_MODE_WRAPPED, + PLUGIN_MODE_NOT_ALLOWED, PLUGIN_MODE_MISSING_FUNC }; +enum ac_plugin_not_allowed { + NOT_ALLOWED_ID_LOCAL_PP, + NOT_ALLOWED_ID_LOCAL_TOPIC, + NOT_ALLOWED_ID_LOCAL_PUB, + NOT_ALLOWED_ID_LOCAL_SUB, + NOT_ALLOWED_ID_REMOTE_PERM, + NOT_ALLOWED_ID_REMOTE_PP, + NOT_ALLOWED_ID_REMOTE_TOPIC, + NOT_ALLOWED_ID_REMOTE_WRITER, + NOT_ALLOWED_ID_REMOTE_READER, + NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY +}; + +#define NOT_ALLOWED_LOCAL_PP (1u << NOT_ALLOWED_ID_LOCAL_PP) +#define NOT_ALLOWED_LOCAL_TOPIC (1u << NOT_ALLOWED_ID_LOCAL_TOPIC) +#define NOT_ALLOWED_LOCAL_PUB (1u << NOT_ALLOWED_ID_LOCAL_PUB) +#define NOT_ALLOWED_LOCAL_SUB (1u << NOT_ALLOWED_ID_LOCAL_SUB) +#define NOT_ALLOWED_REMOTE_PERM (1u << NOT_ALLOWED_ID_REMOTE_PERM) +#define NOT_ALLOWED_REMOTE_PP (1u << NOT_ALLOWED_ID_REMOTE_PP) +#define NOT_ALLOWED_REMOTE_TOPIC (1u << NOT_ALLOWED_ID_REMOTE_TOPIC) +#define NOT_ALLOWED_REMOTE_WRITER (1u << NOT_ALLOWED_ID_REMOTE_WRITER) +#define NOT_ALLOWED_REMOTE_READER (1u << NOT_ALLOWED_ID_REMOTE_READER) +#define NOT_ALLOWED_REMOTE_READER_RELAY_ONLY (1u << NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY) + /** * Implementation structure for storing encapsulated members of the instance * while giving only the interface definition to user */ struct dds_security_access_control_impl { dds_security_access_control base; + dds_security_access_control *instance; enum ac_plugin_mode mode; + uint32_t not_allowed_mask; }; static DDS_Security_PermissionsHandle validate_local_permissions( @@ -42,14 +73,16 @@ static DDS_Security_PermissionsHandle validate_local_permissions( const DDS_Security_Qos *participant_qos, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(auth_plugin); - DDSRT_UNUSED_ARG(auth_plugin); - DDSRT_UNUSED_ARG(identity); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(participant_qos); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return 1; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->validate_local_permissions(impl->instance, auth_plugin, identity, domain_id, participant_qos, ex); + + default: + return 1; + } } static DDS_Security_PermissionsHandle validate_remote_permissions( @@ -61,31 +94,54 @@ static DDS_Security_PermissionsHandle validate_remote_permissions( const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(auth_plugin); - DDSRT_UNUSED_ARG(local_identity_handle); - DDSRT_UNUSED_ARG(remote_identity_handle); - DDSRT_UNUSED_ARG(remote_permissions_token); - DDSRT_UNUSED_ARG(remote_credential_token); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return 0; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PERM) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: validate_remote_permissions"); + return 0; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->validate_remote_permissions(impl->instance, auth_plugin, local_identity_handle, remote_identity_handle, + remote_permissions_token, remote_credential_token, ex); + + default: + return 0; + } } -static DDS_Security_boolean check_create_participant( dds_security_access_control *instance, +static DDS_Security_boolean check_create_participant( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const DDS_Security_Qos *participant_qos, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(participant_qos); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PP) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_participant"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_participant(impl->instance, permissions_handle, domain_id, participant_qos, ex); + + default: + return true; + } } -static DDS_Security_boolean check_create_datawriter( dds_security_access_control *instance, +static DDS_Security_boolean check_create_datawriter( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const char *topic_name, @@ -94,18 +150,30 @@ static DDS_Security_boolean check_create_datawriter( dds_security_access_control const DDS_Security_DataTags *data_tag, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(writer_qos); - DDSRT_UNUSED_ARG(partition); - DDSRT_UNUSED_ARG(data_tag); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PUB) + { + if (topic_name && strncmp (topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_datawriter"); + return false; + } + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_datawriter(impl->instance, permissions_handle, domain_id, topic_name, writer_qos, partition, data_tag, ex); + + default: + return true; + } } -static DDS_Security_boolean check_create_datareader( dds_security_access_control *instance, +static DDS_Security_boolean check_create_datareader( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const char *topic_name, @@ -114,31 +182,50 @@ static DDS_Security_boolean check_create_datareader( dds_security_access_control const DDS_Security_DataTags *data_tag, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(reader_qos); - DDSRT_UNUSED_ARG(partition); - DDSRT_UNUSED_ARG(data_tag); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_SUB) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_datareader"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_datareader(impl->instance, permissions_handle, domain_id, topic_name, reader_qos, partition, data_tag, ex); + + default: + return true; + } } -static DDS_Security_boolean check_create_topic( dds_security_access_control *instance, +static DDS_Security_boolean check_create_topic( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const char *topic_name, const DDS_Security_Qos *qos, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(qos); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_TOPIC) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_topic"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_topic(impl->instance, permissions_handle, domain_id, topic_name, qos, ex); + + default: + return true; + } } static DDS_Security_boolean check_local_datawriter_register_instance( @@ -148,12 +235,16 @@ static DDS_Security_boolean check_local_datawriter_register_instance( const DDS_Security_DynamicData *key, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(writer); - DDSRT_UNUSED_ARG(key); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_register_instance(impl->instance, permissions_handle, writer, key, ex); + + default: + return true; + } } static DDS_Security_boolean check_local_datawriter_dispose_instance( @@ -163,69 +254,137 @@ static DDS_Security_boolean check_local_datawriter_dispose_instance( const DDS_Security_DynamicData key, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(writer); - DDSRT_UNUSED_ARG(key); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_dispose_instance(impl->instance, permissions_handle, writer, key, ex); + + default: + return true; + } } -static DDS_Security_boolean check_remote_participant( dds_security_access_control *instance, +static DDS_Security_boolean check_remote_participant( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const DDS_Security_ParticipantBuiltinTopicDataSecure *participant_data, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(participant_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PP) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_participant"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_participant(impl->instance, permissions_handle, domain_id, participant_data, ex); + + default: + return true; + } } -static DDS_Security_boolean check_remote_datawriter( dds_security_access_control *instance, +static DDS_Security_boolean check_remote_datawriter( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(publication_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_WRITER) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_datawriter"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_datawriter(impl->instance, permissions_handle, domain_id, publication_data, ex); + + default: + return true; + } } -static DDS_Security_boolean check_remote_datareader( dds_security_access_control *instance, +static DDS_Security_boolean check_remote_datareader( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, - DDS_Security_boolean *relay_only, DDS_Security_SecurityException *ex) + DDS_Security_boolean *relay_only, + DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(subscription_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - *relay_only = false; - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER) + { + if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_datareader"); + return false; + } + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + { + bool ret; + if ((ret = impl->instance->check_remote_datareader(impl->instance, permissions_handle, domain_id, subscription_data, relay_only, ex))) + { + /* Only relay_only for the user reader, not the builtin ones. */ + if (impl->mode == PLUGIN_MODE_NOT_ALLOWED && impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER_RELAY_ONLY) + { + if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + *relay_only = true; + } + } + return ret; + } + + default: + *relay_only = false; + return true; + } } -static DDS_Security_boolean check_remote_topic( dds_security_access_control *instance, +static DDS_Security_boolean check_remote_topic( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const DDS_Security_DomainId domain_id, const DDS_Security_TopicBuiltinTopicData *topic_data, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(domain_id); - DDSRT_UNUSED_ARG(topic_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_TOPIC) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_topic"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_topic(impl->instance, permissions_handle, domain_id, topic_data, ex); + + default: + return true; + } } static DDS_Security_boolean check_local_datawriter_match( @@ -236,13 +395,16 @@ static DDS_Security_boolean check_local_datawriter_match( const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(writer_permissions_handle); - DDSRT_UNUSED_ARG(reader_permissions_handle); - DDSRT_UNUSED_ARG(publication_data); - DDSRT_UNUSED_ARG(subscription_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_match(impl->instance, writer_permissions_handle, reader_permissions_handle, publication_data, subscription_data, ex); + + default: + return true; + } } static DDS_Security_boolean check_local_datareader_match( @@ -253,13 +415,16 @@ static DDS_Security_boolean check_local_datareader_match( const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(reader_permissions_handle); - DDSRT_UNUSED_ARG(writer_permissions_handle); - DDSRT_UNUSED_ARG(subscription_data); - DDSRT_UNUSED_ARG(publication_data); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datareader_match(impl->instance, reader_permissions_handle, writer_permissions_handle, subscription_data, publication_data, ex); + + default: + return true; + } } static DDS_Security_boolean check_remote_datawriter_register_instance( @@ -271,14 +436,16 @@ static DDS_Security_boolean check_remote_datawriter_register_instance( const DDS_Security_InstanceHandle instance_handle, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(reader); - DDSRT_UNUSED_ARG(publication_handle); - DDSRT_UNUSED_ARG(key); - DDSRT_UNUSED_ARG(instance_handle); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_remote_datawriter_register_instance(impl->instance, permissions_handle, reader, publication_handle, key, instance_handle, ex); + + default: + return true; + } } static DDS_Security_boolean check_remote_datawriter_dispose_instance( @@ -289,13 +456,16 @@ static DDS_Security_boolean check_remote_datawriter_dispose_instance( const DDS_Security_DynamicData key, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(reader); - DDSRT_UNUSED_ARG(publication_handle); - DDSRT_UNUSED_ARG(key); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_remote_datawriter_dispose_instance(impl->instance, permissions_handle, reader, publication_handle, key, ex); + + default: + return true; + } } static DDS_Security_boolean get_permissions_token( @@ -304,12 +474,18 @@ static DDS_Security_boolean get_permissions_token( const DDS_Security_PermissionsHandle handle, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(handle); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - memset(permissions_token, 0, sizeof(*permissions_token)); - permissions_token->class_id = ddsrt_strdup(""); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_permissions_token(impl->instance, permissions_token, handle, ex); + + default: + memset(permissions_token, 0, sizeof(*permissions_token)); + permissions_token->class_id = ddsrt_strdup (""); + return true; + } } static DDS_Security_boolean get_permissions_credential_token( @@ -318,31 +494,51 @@ static DDS_Security_boolean get_permissions_credential_token( const DDS_Security_PermissionsHandle handle, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_credential_token); - DDSRT_UNUSED_ARG(handle); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_permissions_credential_token(impl->instance, permissions_credential_token, handle, ex); + + default: + return true; + } } -static DDS_Security_boolean set_listener( dds_security_access_control *instance, +static DDS_Security_boolean set_listener( + dds_security_access_control *instance, const dds_security_access_control_listener *listener, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(listener); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->set_listener (impl->instance, listener, ex); + + default: + return true; + } } -static DDS_Security_boolean return_permissions_token( dds_security_access_control *instance, +static DDS_Security_boolean return_permissions_token( + dds_security_access_control *instance, const DDS_Security_PermissionsToken *token, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - ddsrt_free (token->class_id); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_token (impl->instance, token, ex); + + default: + ddsrt_free (token->class_id); + return true; + } } static DDS_Security_boolean return_permissions_credential_token( @@ -350,10 +546,16 @@ static DDS_Security_boolean return_permissions_credential_token( const DDS_Security_PermissionsCredentialToken *permissions_credential_token, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_credential_token); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_credential_token(impl->instance, permissions_credential_token, ex); + + default: + return true; + } } static DDS_Security_boolean get_participant_sec_attributes( @@ -362,25 +564,35 @@ static DDS_Security_boolean get_participant_sec_attributes( DDS_Security_ParticipantSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_participant_sec_attributes(impl->instance, permissions_handle, attributes, ex); + + default: + return true; + } } -static DDS_Security_boolean get_topic_sec_attributes( dds_security_access_control *instance, +static DDS_Security_boolean get_topic_sec_attributes( + dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, const char *topic_name, DDS_Security_TopicSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_topic_sec_attributes(impl->instance, permissions_handle, topic_name, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean get_datawriter_sec_attributes( @@ -392,14 +604,16 @@ static DDS_Security_boolean get_datawriter_sec_attributes( DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(partition); - DDSRT_UNUSED_ARG(data_tag); - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_datawriter_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean get_datareader_sec_attributes( @@ -411,14 +625,16 @@ static DDS_Security_boolean get_datareader_sec_attributes( DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(topic_name); - DDSRT_UNUSED_ARG(partition); - DDSRT_UNUSED_ARG(data_tag); - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_datareader_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean return_participant_sec_attributes( @@ -426,10 +642,16 @@ static DDS_Security_boolean return_participant_sec_attributes( const DDS_Security_ParticipantSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_participant_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean return_topic_sec_attributes( @@ -437,10 +659,16 @@ static DDS_Security_boolean return_topic_sec_attributes( const DDS_Security_TopicSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_topic_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean return_datawriter_sec_attributes( @@ -448,10 +676,16 @@ static DDS_Security_boolean return_datawriter_sec_attributes( const DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_datawriter_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean return_datareader_sec_attributes( @@ -459,10 +693,16 @@ static DDS_Security_boolean return_datareader_sec_attributes( const DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(attributes); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_datareader_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } } static DDS_Security_boolean return_permissions_handle( @@ -470,17 +710,29 @@ static DDS_Security_boolean return_permissions_handle( const DDS_Security_PermissionsHandle permissions_handle, DDS_Security_SecurityException *ex) { - DDSRT_UNUSED_ARG(permissions_handle); - DDSRT_UNUSED_ARG(ex); - DDSRT_UNUSED_ARG(instance); - return true; + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_handle(impl->instance, permissions_handle, ex); + + default: + return true; + } } - -static struct dds_security_access_control_impl * init_test_access_control_common() +static struct dds_security_access_control_impl * init_test_access_control_common(const char *argument, bool wrapped, struct ddsi_domaingv *gv) { struct dds_security_access_control_impl *impl = ddsrt_malloc(sizeof(*impl)); memset(impl, 0, sizeof(*impl)); + + if (wrapped) + { + if (init_access_control(argument, (void **)&impl->instance, gv) != DDS_SECURITY_SUCCESS) + return NULL; + } + impl->base.validate_local_permissions = &validate_local_permissions; impl->base.validate_remote_permissions = &validate_remote_permissions; impl->base.check_create_participant = &check_create_participant; @@ -514,40 +766,90 @@ static struct dds_security_access_control_impl * init_test_access_control_common return impl; } -int32_t init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +static int finalize_test_access_control_common(struct dds_security_access_control_impl * impl, bool wrapped) +{ + int32_t ret; + if (wrapped && (ret = finalize_access_control(impl->instance)) != DDS_SECURITY_SUCCESS) + return ret; + ddsrt_free(impl); + return DDS_SECURITY_SUCCESS; +} + +int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) { - DDSRT_UNUSED_ARG(argument); DDSRT_UNUSED_ARG(context); - DDSRT_UNUSED_ARG(gv); - struct dds_security_access_control_impl *impl = init_test_access_control_common(); + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv); impl->mode = PLUGIN_MODE_ALL_OK; *context = impl; return 0; } -int32_t finalize_test_access_control_all_ok(void *context) +int finalize_test_access_control_all_ok(void *context) { - assert(((struct dds_security_access_control_impl *)context)->mode == PLUGIN_MODE_ALL_OK); - ddsrt_free(context); - return 0; + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_ALL_OK); + return finalize_test_access_control_common(impl, false); } -int32_t init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_WRAPPED; + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_access_control_wrapped(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_WRAPPED); + return finalize_test_access_control_common(impl, true); +} + +int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) { - DDSRT_UNUSED_ARG(argument); DDSRT_UNUSED_ARG(context); - DDSRT_UNUSED_ARG(gv); - struct dds_security_access_control_impl *impl = init_test_access_control_common(); + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv); impl->base.check_create_datareader = NULL; impl->mode = PLUGIN_MODE_MISSING_FUNC; *context = impl; return 0; } -int32_t finalize_test_access_control_missing_func(void *context) +int finalize_test_access_control_missing_func(void *context) { - assert(((struct dds_security_access_control_impl *)context)->mode == PLUGIN_MODE_MISSING_FUNC); - ddsrt_free(context); - return 0; + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_MISSING_FUNC); + return finalize_test_access_control_common(impl, false); } +#define INIT_NOT_ALLOWED(name_, mask_) \ + int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv) \ + { \ + DDSRT_UNUSED_ARG(context); \ + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv); \ + impl->mode = PLUGIN_MODE_NOT_ALLOWED; \ + impl->not_allowed_mask = mask_; \ + *context = impl; \ + return 0; \ + } + +INIT_NOT_ALLOWED(local_participant_not_allowed, NOT_ALLOWED_LOCAL_PP) +INIT_NOT_ALLOWED(local_topic_not_allowed, NOT_ALLOWED_LOCAL_TOPIC) +INIT_NOT_ALLOWED(local_publishing_not_allowed, NOT_ALLOWED_LOCAL_PUB) +INIT_NOT_ALLOWED(local_subscribing_not_allowed, NOT_ALLOWED_LOCAL_SUB) +INIT_NOT_ALLOWED(remote_permissions_invalidate, NOT_ALLOWED_REMOTE_PERM) +INIT_NOT_ALLOWED(remote_participant_not_allowed, NOT_ALLOWED_REMOTE_PP) +INIT_NOT_ALLOWED(remote_topic_not_allowed, NOT_ALLOWED_REMOTE_TOPIC) +INIT_NOT_ALLOWED(remote_writer_not_allowed, NOT_ALLOWED_REMOTE_WRITER) +INIT_NOT_ALLOWED(remote_reader_not_allowed, NOT_ALLOWED_REMOTE_READER) +INIT_NOT_ALLOWED(remote_reader_relay_only, NOT_ALLOWED_REMOTE_READER_RELAY_ONLY) + +int finalize_test_access_control_not_allowed(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_NOT_ALLOWED); + return finalize_test_access_control_common(impl, true); +} diff --git a/src/security/core/tests/common/access_control_wrapper.h b/src/security/core/tests/common/access_control_wrapper.h index a7c2e7c..3fb04bf 100644 --- a/src/security/core/tests/common/access_control_wrapper.h +++ b/src/security/core/tests/common/access_control_wrapper.h @@ -16,12 +16,36 @@ #include "dds/security/dds_security_api.h" #include "dds/security/access_control_wrapper_export.h" +/* Topic name prefix expected by this wrapper when running in not-allowed + mode. This prefix is used to exclude built-in topics from being disallowed. */ +#define AC_WRAPPER_TOPIC_PREFIX "ddssec_access_control_" + /* Init in all-ok mode: all functions return success without calling the actual plugin */ -SECURITY_EXPORT int32_t init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_access_control_all_ok(void *context); +SECURITY_EXPORT int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_all_ok(void *context); /* Init in missing function mode: one of the function pointers is null */ -SECURITY_EXPORT int32_t init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_access_control_missing_func(void *context); +SECURITY_EXPORT int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_missing_func(void *context); + +SECURITY_EXPORT int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_wrapped(void *context); + +/* Init functions for not-allowed modes */ +#define INIT_NOT_ALLOWED_DECL(name_) \ + SECURITY_EXPORT int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv); + +INIT_NOT_ALLOWED_DECL(local_participant_not_allowed) +INIT_NOT_ALLOWED_DECL(local_topic_not_allowed) +INIT_NOT_ALLOWED_DECL(local_publishing_not_allowed) +INIT_NOT_ALLOWED_DECL(local_subscribing_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_permissions_invalidate) +INIT_NOT_ALLOWED_DECL(remote_participant_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_topic_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_writer_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_reader_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_reader_relay_only) + +SECURITY_EXPORT int finalize_test_access_control_not_allowed(void *context); #endif /* SECURITY_CORE_TEST_ACCESS_CONTROL_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/authentication_wrapper.c b/src/security/core/tests/common/authentication_wrapper.c index a2d3709..86290df 100644 --- a/src/security/core/tests/common/authentication_wrapper.c +++ b/src/security/core/tests/common/authentication_wrapper.c @@ -22,8 +22,8 @@ #include "test_identity.h" #include "plugin_wrapper_msg_q.h" -int32_t init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv); -int32_t finalize_authentication(void *context); +int init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv); +int finalize_authentication(void *context); enum auth_plugin_mode { PLUGIN_MODE_ALL_OK, @@ -482,7 +482,7 @@ static struct dds_security_authentication_impl * init_test_authentication_common return impl; } -int32_t init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) { DDSRT_UNUSED_ARG(argument); DDSRT_UNUSED_ARG(context); @@ -493,14 +493,14 @@ int32_t init_test_authentication_all_ok(const char *argument, void **context, st return 0; } -int32_t finalize_test_authentication_all_ok(void *context) +int finalize_test_authentication_all_ok(void *context) { assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_ALL_OK); ddsrt_free(context); return 0; } -int32_t init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) { DDSRT_UNUSED_ARG(argument); DDSRT_UNUSED_ARG(context); @@ -512,14 +512,14 @@ int32_t init_test_authentication_missing_func(const char *argument, void **conte return 0; } -int32_t finalize_test_authentication_missing_func(void *context) +int finalize_test_authentication_missing_func(void *context) { assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_MISSING_FUNC); ddsrt_free(context); return 0; } -int32_t init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv) { DDSRT_UNUSED_ARG(argument); DDSRT_UNUSED_ARG(context); @@ -527,7 +527,7 @@ int32_t init_test_authentication_init_error(const char *argument, void **context return 1; } -int32_t finalize_test_authentication_init_error(void *context) +int finalize_test_authentication_init_error(void *context) { DDSRT_UNUSED_ARG(context); return 0; @@ -537,9 +537,9 @@ int32_t finalize_test_authentication_init_error(void *context) * Init and fini functions for using wrapped mode for the authentication plugin. * These functions assumes that there are no concurrent calls, as the static * variables used here are not protected by a lock. */ -int32_t init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) { - int32_t ret; + int ret; struct dds_security_authentication_impl *impl = init_test_authentication_common(); impl->mode = PLUGIN_MODE_WRAPPED; @@ -553,9 +553,9 @@ int32_t init_test_authentication_wrapped(const char *argument, void **context, s return ret; } -int32_t finalize_test_authentication_wrapped(void *context) +int finalize_test_authentication_wrapped(void *context) { - int32_t ret; + int ret; struct dds_security_authentication_impl *impl = context; assert(impl->mode == PLUGIN_MODE_WRAPPED); deinit_message_queue(&impl->msg_queue); diff --git a/src/security/core/tests/common/authentication_wrapper.h b/src/security/core/tests/common/authentication_wrapper.h index d784454..f58121d 100644 --- a/src/security/core/tests/common/authentication_wrapper.h +++ b/src/security/core/tests/common/authentication_wrapper.h @@ -18,20 +18,20 @@ #include "plugin_wrapper_msg_q.h" /* Init in wrapper mode */ -SECURITY_EXPORT int32_t init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_authentication_wrapped(void *context); +SECURITY_EXPORT int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_wrapped(void *context); /* Init in all-ok mode: all functions return success without calling the actual plugin */ -SECURITY_EXPORT int32_t init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_authentication_all_ok(void *context); +SECURITY_EXPORT int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_all_ok(void *context); /* Init in missing function mode: one of the function pointers is null */ -SECURITY_EXPORT int32_t init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_authentication_missing_func(void *context); +SECURITY_EXPORT int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_missing_func(void *context); /* Init function fails */ -SECURITY_EXPORT int32_t init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_authentication_init_error(void *context); +SECURITY_EXPORT int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_init_error(void *context); SECURITY_EXPORT struct message * test_authentication_plugin_take_msg(dds_domainid_t domain_id, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_duration_t timeout); SECURITY_EXPORT void test_authentication_plugin_release_msg(struct message *msg); diff --git a/src/security/core/tests/common/cryptography_wrapper.c b/src/security/core/tests/common/cryptography_wrapper.c index a3d1508..034d81d 100644 --- a/src/security/core/tests/common/cryptography_wrapper.c +++ b/src/security/core/tests/common/cryptography_wrapper.c @@ -22,8 +22,8 @@ #include "dds/security/core/dds_security_utils.h" #include "cryptography_wrapper.h" -int32_t init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); -int32_t finalize_crypto(void *context); +int init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); +int finalize_crypto(void *context); enum crypto_plugin_mode { PLUGIN_MODE_ALL_OK, @@ -754,16 +754,16 @@ static struct dds_security_cryptography_impl * init_test_cryptography_common(con return impl; } -static int32_t finalize_test_cryptography_common(struct dds_security_cryptography_impl * impl, bool wrapped) +static int finalize_test_cryptography_common(struct dds_security_cryptography_impl * impl, bool wrapped) { - int32_t ret; + int ret; if (wrapped && (ret = finalize_crypto(impl->instance)) != DDS_SECURITY_SUCCESS) return ret; ddsrt_free(impl); return DDS_SECURITY_SUCCESS; } -int32_t init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) { struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv); if (!impl) @@ -773,14 +773,14 @@ int32_t init_test_cryptography_all_ok(const char *argument, void **context, stru return DDS_SECURITY_SUCCESS; } -int32_t finalize_test_cryptography_all_ok(void *context) +int finalize_test_cryptography_all_ok(void *context) { struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; assert(impl->mode == PLUGIN_MODE_ALL_OK); return finalize_test_cryptography_common(impl, false); } -int32_t init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) { struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv); if (!impl) @@ -791,14 +791,14 @@ int32_t init_test_cryptography_missing_func(const char *argument, void **context return DDS_SECURITY_SUCCESS; } -int32_t finalize_test_cryptography_missing_func(void *context) +int finalize_test_cryptography_missing_func(void *context) { struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; assert(impl->mode == PLUGIN_MODE_MISSING_FUNC); return finalize_test_cryptography_common(impl, false); } -int32_t init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) { struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv); if (!impl) @@ -808,7 +808,7 @@ int32_t init_test_cryptography_wrapped(const char *argument, void **context, str return DDS_SECURITY_SUCCESS; } -int32_t finalize_test_cryptography_wrapped(void *context) +int finalize_test_cryptography_wrapped(void *context) { struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; assert(impl->mode == PLUGIN_MODE_WRAPPED); diff --git a/src/security/core/tests/common/cryptography_wrapper.h b/src/security/core/tests/common/cryptography_wrapper.h index f379727..0c50adc 100644 --- a/src/security/core/tests/common/cryptography_wrapper.h +++ b/src/security/core/tests/common/cryptography_wrapper.h @@ -35,15 +35,15 @@ SECURITY_EXPORT void set_disc_protection_kinds( SECURITY_EXPORT void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const char * pp_secret, const char * groupdata_secret, const char * ep_secret); /* Init in all-ok mode: all functions return success without calling the actual plugin */ -SECURITY_EXPORT int32_t init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_cryptography_all_ok(void *context); +SECURITY_EXPORT int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_all_ok(void *context); /* Init in missing function mode: one of the function pointers is null */ -SECURITY_EXPORT int32_t init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_cryptography_missing_func(void *context); +SECURITY_EXPORT int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_missing_func(void *context); /* Init in wrapper mode */ -SECURITY_EXPORT int32_t init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); -SECURITY_EXPORT int32_t finalize_test_cryptography_wrapped(void *context); +SECURITY_EXPORT int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_wrapped(void *context); #endif /* SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/security_config_test_utils.c b/src/security/core/tests/common/security_config_test_utils.c index 51a0a9f..d66ff2d 100644 --- a/src/security/core/tests/common/security_config_test_utils.c +++ b/src/security/core/tests/common/security_config_test_utils.c @@ -50,8 +50,8 @@ static const char *governance_xml = " *" " ${ENABLE_DISC_PROTECTION:-false}" " ${ENABLE_LIVELINESS_PROTECTION:-false}" - " ${ENABLE_READ_AC:-false}" - " ${ENABLE_WRITE_AC:-false}" + " ${ENABLE_READ_AC:-true}" + " ${ENABLE_WRITE_AC:-true}" " ${METADATA_PROTECTION_KIND:-NONE}" " ${DATA_PROTECTION_KIND:-NONE}" " " @@ -68,7 +68,7 @@ static const char *permissions_xml_grant = " ${SUBJECT_NAME}" " ${NOT_BEFORE:-2015-09-15T01:00:00}${NOT_AFTER:-2115-09-15T01:00:00}" " " - " 0230" + " ${DOMAIN_ID:+}${DOMAIN_ID:-0230}${DOMAIN_ID:+}" " " " ${PUB_TOPICS:-*}" " *" @@ -239,7 +239,7 @@ static char * get_xml_datetime(dds_time_t t, char * buf, size_t len) return buf; } -char * get_permissions_grant(const char * name, const char * subject, +char * get_permissions_grant(const char * name, const char * subject, const char * domain_id, dds_time_t not_before, dds_time_t not_after, const char * pub_topics, const char * sub_topics, const char * default_policy) { char not_before_str[] = "0000-00-00T00:00:00Z"; @@ -252,6 +252,7 @@ char * get_permissions_grant(const char * name, const char * subject, { "SUBJECT_NAME", subject, 1 }, { "NOT_BEFORE", not_before_str, 1 }, { "NOT_AFTER", not_after_str, 1 }, + { "DOMAIN_ID", domain_id, 3 }, { "PUB_TOPICS", pub_topics, 1 }, { "SUB_TOPICS", sub_topics, 1 }, { "DEFAULT_POLICY", default_policy, 1 }, diff --git a/src/security/core/tests/common/security_config_test_utils.h b/src/security/core/tests/common/security_config_test_utils.h index 87f8e4b..3cf20de 100644 --- a/src/security/core/tests/common/security_config_test_utils.h +++ b/src/security/core/tests/common/security_config_test_utils.h @@ -27,7 +27,7 @@ int32_t expand_lookup_unmatched (const struct kvp * lookup_table); char * get_governance_config (struct kvp *config_vars, bool add_prefix); char * get_permissions_topic(const char * name); -char * get_permissions_grant(const char * name, const char * subject, +char * get_permissions_grant(const char * name, const char * subject, const char * domain_id, dds_time_t not_before, dds_time_t not_after, const char * pub_topics, const char * sub_topics, const char * default_policy); char * get_permissions_config(char * grants[], size_t ngrants, bool add_prefix); diff --git a/src/security/core/tests/common/test_utils.c b/src/security/core/tests/common/test_utils.c index bf8c300..a75c6b9 100644 --- a/src/security/core/tests/common/test_utils.c +++ b/src/security/core/tests/common/test_utils.c @@ -294,10 +294,11 @@ void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_c CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); while (true) { - ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(5)); - CU_ASSERT_FATAL (ret >= 1); - CU_ASSERT_EQUAL_FATAL (wr, (dds_entity_t)(intptr_t) triggered); - ret = dds_get_publication_matched_status(wr, &pub_matched); + ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(2)); + CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1); + if (exp_count > 0) + CU_ASSERT_EQUAL_FATAL (wr, (dds_entity_t)(intptr_t) triggered); + ret = dds_get_publication_matched_status (wr, &pub_matched); CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); if (pub_matched.total_count >= exp_count) break; @@ -306,6 +307,30 @@ void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_c CU_ASSERT_EQUAL_FATAL (pub_matched.total_count, exp_count); } +void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count) +{ + dds_attach_t triggered; + dds_entity_t ws = dds_create_waitset (pp_rd); + CU_ASSERT_FATAL (ws > 0); + dds_subscription_matched_status_t sub_matched; + + dds_return_t ret = dds_waitset_attach (ws, rd, rd); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + while (true) + { + ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(2)); + CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1); + if (exp_count > 0) + CU_ASSERT_EQUAL_FATAL (rd, (dds_entity_t)(intptr_t) triggered); + ret = dds_get_subscription_matched_status (rd, &sub_matched); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + if (sub_matched.total_count >= exp_count) + break; + }; + dds_delete (ws); + CU_ASSERT_EQUAL_FATAL (sub_matched.total_count, exp_count); +} + char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) { ddsrt_pid_t pid = ddsrt_getpid (); @@ -328,10 +353,12 @@ bool reader_wait_for_data (dds_entity_t pp, dds_entity_t rd, dds_duration_t dur) return ret > 0; } -void rd_wr_init( +void rd_wr_init_fail( dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, - const char * topic_name) + const char * topic_name, + bool exp_pubtp_fail, bool exp_wr_fail, + bool exp_subtp_fail, bool exp_rd_fail) { dds_qos_t * qos = dds_create_qos (); CU_ASSERT_FATAL (qos != NULL); @@ -344,19 +371,37 @@ void rd_wr_init( *sub = dds_create_subscriber (pp_rd, NULL, NULL); CU_ASSERT_FATAL (*sub > 0); *pub_tp = dds_create_topic (pp_wr, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); - CU_ASSERT_FATAL (*pub_tp > 0); + CU_ASSERT_EQUAL_FATAL (exp_pubtp_fail, *pub_tp <= 0); *sub_tp = dds_create_topic (pp_rd, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); - CU_ASSERT_FATAL (*sub_tp > 0); - *wr = dds_create_writer (*pub, *pub_tp, qos, NULL); - CU_ASSERT_FATAL (*wr > 0); - dds_set_status_mask (*wr, DDS_PUBLICATION_MATCHED_STATUS); - *rd = dds_create_reader (*sub, *sub_tp, qos, NULL); - CU_ASSERT_FATAL (*rd > 0); - dds_set_status_mask (*rd, DDS_DATA_AVAILABLE_STATUS); - sync_writer_to_readers(pp_wr, *wr, 1); + CU_ASSERT_EQUAL_FATAL (exp_subtp_fail, *sub_tp <= 0); + if (!exp_pubtp_fail) + { + *wr = dds_create_writer (*pub, *pub_tp, qos, NULL); + CU_ASSERT_EQUAL_FATAL (exp_wr_fail, *wr <= 0); + if (exp_wr_fail) + goto fail; + dds_set_status_mask (*wr, DDS_PUBLICATION_MATCHED_STATUS); + } + if (!exp_subtp_fail) + { + *rd = dds_create_reader (*sub, *sub_tp, qos, NULL); + CU_ASSERT_EQUAL_FATAL (exp_rd_fail, *rd <= 0); + if (exp_rd_fail) + goto fail; + dds_set_status_mask (*rd, DDS_SUBSCRIPTION_MATCHED_STATUS); + } +fail: dds_delete_qos (qos); } +void rd_wr_init( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name) +{ + rd_wr_init_fail (pp_wr, pub, pub_tp, wr, pp_rd, sub, sub_tp, rd, topic_name, false, false, false, false); +} + void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail) { SecurityCoreTests_Type1 sample = { 1, 1 }; @@ -367,9 +412,10 @@ void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_du dds_time_t tend = dds_time () + dur; bool write_fail = false, read_fail = false; + dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS); do { - print_test_msg("write\n"); + print_test_msg ("write\n"); if (dds_write (wr, &sample) != DDS_RETCODE_OK) write_fail = true; @@ -399,7 +445,7 @@ void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_du break; dds_sleepfor (DDS_MSECS (100)); } - while (dds_time() < tend); + while (dds_time () < tend); CU_ASSERT_EQUAL_FATAL (write_fail, exp_write_fail); CU_ASSERT_EQUAL_FATAL (read_fail, exp_read_fail); } diff --git a/src/security/core/tests/common/test_utils.h b/src/security/core/tests/common/test_utils.h index b396f60..ac1e8a7 100644 --- a/src/security/core/tests/common/test_utils.h +++ b/src/security/core/tests/common/test_utils.h @@ -56,11 +56,18 @@ void validate_handshake_nofail (dds_domainid_t domain_id); void handshake_list_fini(struct Handshake *hs_list, int nhs); char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size); void sync_writer_to_readers(dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_count); +void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count); bool reader_wait_for_data(dds_entity_t pp, dds_entity_t rd, dds_duration_t dur); void rd_wr_init( dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, - const char *topic_name); + const char * topic_name); +void rd_wr_init_fail( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name, + bool exp_pubtp_fail, bool exp_wr_fail, + bool exp_subtp_fail, bool exp_rd_fail); void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail); #endif /* SECURITY_CORE_TEST_UTILS_H_ */