Add PropertyPolicy to QoS API for Security settings (#278)

* Add PropertyPolicy to QoS API for Security settings

This commit adds the public API for PropertyQosPolicy including
tests. This policy can be used to set the parameters for the DDS security
implementation, as an alternative for using the xml configuration.
Tests are also inlcuded for setting security properties and conflict
resolving when both security configuration and qos properties are present.
Finally, the pubsub tool is updated so that is handles this qos correctly.

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Init binary_value.props to fix failing qos merge and moved init code in qset_prop functions

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Add additional test and some validation improvements based on review comments

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Refactoring of qos property

Refactored the qos property handling based on review comments. Setting
and unsettings functions are simplified and now use helper functions
for lookup, property initialisation is simplified. Added an additional
check for required security properties when creating participant using
security settings from qos, and added a test-case for this code.

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Check for qos flag before getting property index from qos

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Participant creation should fail on inconsistent security qos properties, and some minor code improvements in property qos api functions

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Update log message in test security_config_qos

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Fixed unused label compiler error in q_entity.c when security is disabled

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>

* Refactored qprop functions with macros to avoid code duplicate code

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>
This commit is contained in:
dennis-adlink 2019-10-29 16:56:12 +01:00 committed by eboasson
parent 5399e5103c
commit 7f59a46ff8
11 changed files with 927 additions and 47 deletions

View file

@ -379,6 +379,72 @@ dds_qset_ignorelocal (
dds_qos_t * __restrict qos, dds_qos_t * __restrict qos,
dds_ignorelocal_kind_t ignore); dds_ignorelocal_kind_t ignore);
/**
* @brief Stores a property with the provided name and string value in a qos structure.
*
* In the case a property with the provided name already exists in the qos structure,
* the value for this entry is overwritten with the provided string value. If more than
* one property with the provided name exists, only the value of the first of these
* properties is updated.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property
* @param[in] name - Pointer to name of the property
* @param[in] value - Pointer to a (null-terminated) string that will be stored
*/
DDS_EXPORT void
dds_qset_prop (
dds_qos_t * __restrict qos,
const char * name,
const char * value);
/**
* @brief Removes the property with the provided name from a qos structure.
*
* In case more than one property exists with this name, only the first property
* is removed.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the property
*/
DDS_EXPORT void
dds_qunset_prop (
dds_qos_t * __restrict qos,
const char * name);
/**
* @brief Stores the provided binary data as a property in a qos structure
*
* In the case a property with the provided name already exists in the qos structure,
* the value for this entry is overwritten with the provided data. If more than one
* property with the provided name exists, only the value of the first of these
* properties is updated.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property
* @param[in] name - Pointer to name of the property
* @param[in] value - Pointer to data to be stored in the property
* @param[in] sz - Size of the data
*/
DDS_EXPORT void
dds_qset_bprop (
dds_qos_t * __restrict qos,
const char * name,
const void * value,
const size_t sz);
/**
* @brief Removes the binary property with the provided name from a qos structure.
*
* In case more than one binary property exists with this name, only the first binary
* property is removed.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the binary property
* @param[in] name - Pointer to name of the property
*/
DDS_EXPORT void
dds_qunset_bprop (
dds_qos_t * __restrict qos,
const char * name);
/** /**
* @brief Get the userdata from a qos structure * @brief Get the userdata from a qos structure
* *
@ -680,6 +746,74 @@ dds_qget_ignorelocal (
const dds_qos_t * __restrict qos, const dds_qos_t * __restrict qos,
dds_ignorelocal_kind_t *ignore); dds_ignorelocal_kind_t *ignore);
/**
* @brief Gets the names of the properties from a qos structure.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains properties
* @param[in,out] n - Pointer to number of property names that are returned (optional)
* @param[in,out] names - Pointer that will store the string(s) containing property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid or the qos is not present in the qos object
*/
DDS_EXPORT bool
dds_qget_propnames (
const dds_qos_t * __restrict qos,
uint32_t * n,
char *** names);
/**
* @brief Get the value of the property with the provided name from a qos structure.
*
* In case more than one property exists with this name, the value for the first
* property with this name will be returned.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the property
* @param[in,out] value - Pointer to a string that will store the value of the property. The memory for storing the string value will be allocated by this function and the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no property found with the provided name
*/
DDS_EXPORT bool
dds_qget_prop (
const dds_qos_t * __restrict qos,
const char * name,
char ** value);
/**
* @brief Gets the names of the binary properties from a qos structure.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains binary properties
* @param[in,out] n - Pointer to number of binary property names that are returned (optional)
* @param[in,out] names - Pointer that will store the string(s) containing binary property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory
*
* @returns - false iff any of the arguments is invalid or the qos is not present in the qos object
*/
DDS_EXPORT bool
dds_qget_bpropnames (
const dds_qos_t * __restrict qos,
uint32_t * n,
char *** names);
/**
* @brief Get the value of the binary property with the provided name from a qos structure.
*
* In case more than one binary property exists with this name, the value for the first
* binary property with this name will be returned.
*
* @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property
* @param[in] name - Pointer to name of the binary property
* @param[in,out] value - Pointer to a buffer that will store the value of the property. If sz = 0 then a NULL pointer. The memory for storing the value will be allocated by this function and the caller gets ownership of the allocated memory
* @param[in,out] sz - Pointer that will store the size of the returned buffer.
*
* @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no binary property found with the provided name
*/
DDS_EXPORT bool
dds_qget_bprop (
const dds_qos_t * __restrict qos,
const char * name,
void ** value,
size_t * sz);
#if defined (__cplusplus) #if defined (__cplusplus)
} }
#endif #endif

View file

@ -50,7 +50,8 @@ typedef enum dds_qos_policy_id {
DDS_GROUPDATA_QOS_POLICY_ID, DDS_GROUPDATA_QOS_POLICY_ID,
DDS_TRANSPORTPRIORITY_QOS_POLICY_ID, DDS_TRANSPORTPRIORITY_QOS_POLICY_ID,
DDS_LIFESPAN_QOS_POLICY_ID, DDS_LIFESPAN_QOS_POLICY_ID,
DDS_DURABILITYSERVICE_QOS_POLICY_ID DDS_DURABILITYSERVICE_QOS_POLICY_ID,
DDS_PROPERTY_QOS_POLICY_ID,
} dds_qos_policy_id_t; } dds_qos_policy_id_t;
/* QoS structure is opaque */ /* QoS structure is opaque */

View file

@ -25,7 +25,8 @@ extern "C" {
QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS) QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS)
#define DDS_PARTICIPANT_QOS_MASK \ #define DDS_PARTICIPANT_QOS_MASK \
(QP_USER_DATA | QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) (QP_USER_DATA | QP_PRISMTECH_ENTITY_FACTORY | \
QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#define DDS_PUBLISHER_QOS_MASK \ #define DDS_PUBLISHER_QOS_MASK \
(QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \
@ -36,7 +37,7 @@ extern "C" {
QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \ QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \
QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \
QP_RESOURCE_LIMITS | QP_PRISMTECH_READER_DATA_LIFECYCLE | \ QP_RESOURCE_LIMITS | QP_PRISMTECH_READER_DATA_LIFECYCLE | \
QP_CYCLONE_IGNORELOCAL) QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#define DDS_SUBSCRIBER_QOS_MASK \ #define DDS_SUBSCRIBER_QOS_MASK \
(QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \
@ -48,7 +49,7 @@ extern "C" {
QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \ QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \
QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \
QP_RESOURCE_LIMITS | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | \ QP_RESOURCE_LIMITS | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | \
QP_CYCLONE_IGNORELOCAL) QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST)
#if defined (__cplusplus) #if defined (__cplusplus)
} }

View file

@ -335,6 +335,110 @@ void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ig
qos->present |= QP_CYCLONE_IGNORELOCAL; qos->present |= QP_CYCLONE_IGNORELOCAL;
} }
static void dds_qprop_init (dds_qos_t * qos)
{
if (!(qos->present & QP_PROPERTY_LIST))
{
qos->property.value.n = 0;
qos->property.value.props = NULL;
qos->property.binary_value.n = 0;
qos->property.binary_value.props = NULL;
qos->present |= QP_PROPERTY_LIST;
}
}
#define DDS_QPROP_GET_INDEX(prop_type_, prop_field_) \
static bool dds_q##prop_type_##_get_index (const dds_qos_t * qos, const char * name, uint32_t * index) \
{ \
if (qos == NULL || name == NULL || index == NULL || !(qos->present & QP_PROPERTY_LIST)) \
return false; \
for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \
{ \
if (strcmp (qos->property.prop_field_.props[i].name, name) == 0) \
{ \
*index = i; \
return true; \
} \
} \
return false; \
}
DDS_QPROP_GET_INDEX (prop, value)
DDS_QPROP_GET_INDEX (bprop, binary_value)
#define DDS_QUNSET_PROP(prop_type_, prop_field_, value_field_) \
void dds_qunset_##prop_type_ (dds_qos_t * __restrict qos, const char * name) \
{ \
uint32_t i; \
if (qos == NULL || !(qos->present & QP_PROPERTY_LIST) || qos->property.prop_field_.n == 0 || name == NULL) \
return; \
if (dds_q##prop_type_##_get_index (qos, name, &i)) \
{ \
dds_free (qos->property.prop_field_.props[i].name); \
dds_free (qos->property.prop_field_.props[i].value_field_); \
if (qos->property.prop_field_.n > 1) \
{ \
if (i < (qos->property.prop_field_.n - 1)) \
memmove (qos->property.prop_field_.props + i, qos->property.prop_field_.props + i + 1, \
(qos->property.prop_field_.n - i - 1) * sizeof (*qos->property.prop_field_.props)); \
qos->property.prop_field_.props = dds_realloc (qos->property.prop_field_.props, \
(qos->property.prop_field_.n - 1) * sizeof (*qos->property.prop_field_.props)); \
} \
else \
{ \
dds_free (qos->property.prop_field_.props); \
qos->property.prop_field_.props = NULL; \
} \
qos->property.prop_field_.n--; \
} \
}
DDS_QUNSET_PROP (prop, value, value)
DDS_QUNSET_PROP (bprop, binary_value, value.value)
void dds_qset_prop (dds_qos_t * __restrict qos, const char * name, const char * value)
{
uint32_t i;
if (qos == NULL || name == NULL || value == NULL)
return;
dds_qprop_init (qos);
if (dds_qprop_get_index (qos, name, &i))
{
dds_free (qos->property.value.props[i].value);
qos->property.value.props[i].value = dds_string_dup (value);
}
else
{
qos->property.value.props = dds_realloc (qos->property.value.props,
(qos->property.value.n + 1) * sizeof (*qos->property.value.props));
qos->property.value.props[qos->property.value.n].propagate = 0;
qos->property.value.props[qos->property.value.n].name = dds_string_dup (name);
qos->property.value.props[qos->property.value.n].value = dds_string_dup (value);
qos->property.value.n++;
}
}
void dds_qset_bprop (dds_qos_t * __restrict qos, const char * name, const void * value, const size_t sz)
{
uint32_t i;
if (qos == NULL || name == NULL || (value == NULL && sz > 0))
return;
dds_qprop_init (qos);
if (dds_qbprop_get_index (qos, name, &i))
{
dds_qos_data_copy_in (&qos->property.binary_value.props[i].value, value, sz, true);
}
else
{
qos->property.binary_value.props = dds_realloc (qos->property.binary_value.props,
(qos->property.binary_value.n + 1) * sizeof (*qos->property.binary_value.props));
qos->property.binary_value.props[qos->property.binary_value.n].propagate = 0;
qos->property.binary_value.props[qos->property.binary_value.n].name = dds_string_dup (name);
dds_qos_data_copy_in (&qos->property.binary_value.props[qos->property.binary_value.n].value, value, sz, false);
qos->property.binary_value.n++;
}
}
bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz)
{ {
if (qos == NULL || !(qos->present & QP_USER_DATA)) if (qos == NULL || !(qos->present & QP_USER_DATA))
@ -565,3 +669,66 @@ bool dds_qget_ignorelocal (const dds_qos_t * __restrict qos, dds_ignorelocal_kin
*ignore = qos->ignorelocal.value; *ignore = qos->ignorelocal.value;
return true; return true;
} }
#define DDS_QGET_PROPNAMES(prop_type_, prop_field_) \
bool dds_qget_##prop_type_##names (const dds_qos_t * __restrict qos, uint32_t * n, char *** names) \
{ \
bool props; \
if (qos == NULL || (n == NULL && names == NULL)) \
return false; \
props = (qos->present & QP_PROPERTY_LIST) && qos->property.prop_field_.n > 0; \
if (n != NULL) \
*n = props ? qos->property.prop_field_.n : 0; \
if (names != NULL) \
{ \
if (!props) \
*names = NULL; \
else \
{ \
*names = dds_alloc (sizeof (char *) * qos->property.prop_field_.n); \
for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \
(*names)[i] = dds_string_dup (qos->property.prop_field_.props[i].name); \
} \
} \
return props; \
}
DDS_QGET_PROPNAMES (prop, value)
DDS_QGET_PROPNAMES (bprop, binary_value)
bool dds_qget_prop (const dds_qos_t * __restrict qos, const char * name, char ** value)
{
uint32_t i;
bool found;
if (qos == NULL || name == NULL)
return false;
found = dds_qprop_get_index (qos, name, &i);
if (value != NULL)
*value = found ? dds_string_dup (qos->property.value.props[i].value) : NULL;
return found;
}
bool dds_qget_bprop (const dds_qos_t * __restrict qos, const char * name, void ** value, size_t * sz)
{
uint32_t i;
bool found;
if (qos == NULL || name == NULL || (sz == NULL && value != NULL))
return false;
found = dds_qbprop_get_index (qos, name, &i);
if (found)
{
if (value != NULL || sz != NULL)
dds_qos_data_copy_out (&qos->property.binary_value.props[i].value, value, sz);
}
else
{
if (value != NULL)
*value = NULL;
if (sz != NULL)
*sz = 0;
}
return found;
}

View file

@ -20,6 +20,7 @@
#include "dds/ddsrt/environ.h" #include "dds/ddsrt/environ.h"
#include "dds/ddsrt/heap.h" #include "dds/ddsrt/heap.h"
#include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_misc.h"
#include "dds/ddsi/q_xqos.h"
#define FORCE_ENV #define FORCE_ENV
@ -500,3 +501,326 @@ CU_Test(ddsc_config, security_deprecated, .init = ddsrt_init, .fini = ddsrt_fini
CU_ASSERT_FATAL(found == 0x1fffff); CU_ASSERT_FATAL(found == 0x1fffff);
#endif #endif
} }
CU_Test(ddsc_config, security_qos, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expected traces when creating participant with the security elements. */
const char *log_expected[] = {
#ifdef DDSI_INCLUDE_SECURITY
/* The config should have been parsed into the participant QoS. */
"PARTICIPANT * QOS={*property_list={value={"
"{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0},"
"{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0},"
"{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0},"
"{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0},"
"{dds.sec.access.governance,file:Governance.p7s,0},"
"{dds.sec.access.permissions,file:Permissions.p7s,0},"
"{dds.sec.auth.password,testtext_Password_testtext,0},"
"{dds.sec.auth.trusted_ca_dir,file:/test/dir,0}"
"}binary_value={}}*}*",
#endif
NULL
};
dds_entity_t participant;
dds_qos_t * qos;
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create the qos */
CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL);
dds_qset_prop (qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext");
dds_qset_prop (qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext");
dds_qset_prop (qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext");
dds_qset_prop (qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem");
dds_qset_prop (qos, "dds.sec.access.governance", "file:Governance.p7s");
dds_qset_prop (qos, "dds.sec.access.permissions", "file:Permissions.p7s");
dds_qset_prop (qos, "dds.sec.auth.password", "testtext_Password_testtext");
dds_qset_prop (qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir");
/* Create participant with security config in qos. */
found = 0;
ddsrt_setenv(URI_VARIABLE, "<Tracing><Verbosity>finest</></>");
CU_ASSERT_FATAL ((participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL)) > 0);
ddsrt_setenv(URI_VARIABLE, "");
dds_delete(participant);
dds_delete_qos(qos);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0);
#else
CU_ASSERT_FATAL(found == 0x1);
#endif
}
CU_Test(ddsc_config, security_qos_props, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expected traces when creating participant with the security elements. */
const char *log_expected[] = {
#ifdef DDSI_INCLUDE_SECURITY
/* The config should have been parsed into the participant QoS. */
"PARTICIPANT * QOS={*property_list={value={"
"{test.prop1,testtext_value1_testtext,0},"
"{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0},"
"{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0},"
"{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0},"
"{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0},"
"{dds.sec.access.governance,file:Governance.p7s,0},"
"{dds.sec.access.permissions,file:Permissions.p7s,0},"
"{dds.sec.auth.password,testtext_Password_testtext,0},"
"{dds.sec.auth.trusted_ca_dir,file:/test/dir,0},"
"{test.prop2,testtext_value2_testtext,0}}"
"binary_value={{test.bprop1,(3,*),0}}}*}*",
#endif
NULL
};
dds_entity_t participant;
dds_qos_t * qos;
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create the qos */
unsigned char bvalue[3] = { 0x01, 0x02, 0x03 };
CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL);
dds_qset_prop (qos, "test.prop1", "testtext_value1_testtext");
dds_qset_prop (qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext");
dds_qset_prop (qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext");
dds_qset_prop (qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext");
dds_qset_prop (qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem");
dds_qset_prop (qos, "dds.sec.access.governance", "file:Governance.p7s");
dds_qset_prop (qos, "dds.sec.access.permissions", "file:Permissions.p7s");
dds_qset_prop (qos, "dds.sec.auth.password", "testtext_Password_testtext");
dds_qset_prop (qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir");
dds_qset_prop (qos, "test.prop2", "testtext_value2_testtext");
dds_qset_bprop (qos, "test.bprop1", bvalue, 3);
/* Create participant with security config in qos. */
found = 0;
ddsrt_setenv(URI_VARIABLE, "<Tracing><Verbosity>finest</></>");
CU_ASSERT_FATAL ((participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL)) > 0);
ddsrt_setenv(URI_VARIABLE, "");
dds_delete(participant);
dds_delete_qos(qos);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0);
#else
CU_ASSERT_FATAL(found == 0x1);
#endif
}
CU_Test(ddsc_config, security_config_qos, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expect qos settings used when creating participant with config security elements and qos. */
const char *log_expected[] = {
#ifndef DDSI_INCLUDE_SECURITY
"config: //CycloneDDS/Domain: DDSSecurity: unknown element*",
#else
/* The security settings from qos properties should have been parsed into the participant QoS. */
"new_participant(*): using security settings from QoS, ignoring security configuration*",
"PARTICIPANT * QOS={*property_list={value={"
"{dds.sec.auth.identity_ca,testtext_QOS_IdentityCA_testtext,0},"
"{dds.sec.auth.private_key,testtext_QOS_PrivateKey_testtext,0},"
"{dds.sec.auth.identity_certificate,testtext_QOS_IdentityCertificate_testtext,0},"
"{dds.sec.access.permissions_ca,file:QOS_Permissions_CA.pem,0},"
"{dds.sec.access.governance,file:QOS_Governance.p7s,0},"
"{dds.sec.access.permissions,file:QOS_Permissions.p7s,0}"
"}binary_value={}}*}*",
#endif
NULL
};
const char *sec_config =
"<Tracing><Verbosity>finest</></>"
"<DDSSecurity>"
"<Authentication>"
"<IdentityCertificate>testtext_IdentityCertificate_testtext</IdentityCertificate>"
"<IdentityCA>testtext_IdentityCA_testtext</IdentityCA>"
"<PrivateKey>testtext_PrivateKey_testtext</PrivateKey>"
"</Authentication>"
"<AccessControl>"
"<Governance>file:Governance.p7s</Governance>"
"<PermissionsCA>file:Permissions_CA.pem</PermissionsCA>"
"<Permissions>file:Permissions.p7s</Permissions>"
"</AccessControl>"
"</DDSSecurity>";
dds_entity_t participant;
dds_qos_t * qos;
CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL);
dds_qset_prop (qos, "dds.sec.auth.identity_ca", "testtext_QOS_IdentityCA_testtext");
dds_qset_prop (qos, "dds.sec.auth.private_key", "testtext_QOS_PrivateKey_testtext");
dds_qset_prop (qos, "dds.sec.auth.identity_certificate", "testtext_QOS_IdentityCertificate_testtext");
dds_qset_prop (qos, "dds.sec.access.permissions_ca", "file:QOS_Permissions_CA.pem");
dds_qset_prop (qos, "dds.sec.access.governance", "file:QOS_Governance.p7s");
dds_qset_prop (qos, "dds.sec.access.permissions", "file:QOS_Permissions.p7s");
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create participant with security elements. */
found = 0;
ddsrt_setenv(URI_VARIABLE, sec_config);
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL);
ddsrt_setenv(URI_VARIABLE, "");
dds_delete(participant);
dds_delete_qos(qos);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0x1);
#else
CU_ASSERT_FATAL(found == 0x3);
#endif
}
CU_Test(ddsc_config, security_other_prop, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expect config used when creating participant with config security elements and
* qos containing only non-security properties. */
const char *log_expected[] = {
#ifndef DDSI_INCLUDE_SECURITY
"config: //CycloneDDS/Domain: DDSSecurity: unknown element*",
#else
/* The security settings from config should have been parsed into the participant QoS. */
"PARTICIPANT * QOS={*property_list={value={"
"{test.dds.sec.prop1,testtext_value1_testtext,0},"
"{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0},"
"{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0},"
"{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0},"
"{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0},"
"{dds.sec.access.governance,file:Governance.p7s,0},"
"{dds.sec.access.permissions,file:Permissions.p7s,0}"
"}binary_value={}}*}*",
#endif
NULL
};
const char *sec_config =
"<Tracing><Verbosity>finest</></>"
"<DDSSecurity>"
"<Authentication>"
"<IdentityCertificate>testtext_IdentityCertificate_testtext</IdentityCertificate>"
"<IdentityCA>testtext_IdentityCA_testtext</IdentityCA>"
"<PrivateKey>testtext_PrivateKey_testtext</PrivateKey>"
"</Authentication>"
"<AccessControl>"
"<Governance>file:Governance.p7s</Governance>"
"<PermissionsCA>file:Permissions_CA.pem</PermissionsCA>"
"<Permissions>file:Permissions.p7s</Permissions>"
"</AccessControl>"
"</DDSSecurity>";
dds_entity_t participant;
dds_qos_t * qos;
CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL);
dds_qset_prop (qos, "test.dds.sec.prop1", "testtext_value1_testtext");
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create participant with security elements. */
found = 0;
ddsrt_setenv(URI_VARIABLE, sec_config);
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL);
ddsrt_setenv(URI_VARIABLE, "");
dds_delete(participant);
dds_delete_qos(qos);
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0x1);
#else
CU_ASSERT_FATAL(found == 0x1);
#endif
}
CU_Test(ddsc_config, security_qos_invalid, .init = ddsrt_init, .fini = ddsrt_fini)
{
/* Expected traces when creating participant with the security elements. */
const char *log_expected[] = {
#ifndef DDSI_INCLUDE_SECURITY
"config: //CycloneDDS/Domain: DDSSecurity: unknown element*",
#else
/* The config should have been parsed into the participant QoS. */
"PARTICIPANT * QOS={*property_list={value={"
"{dds.sec.auth.identity_ca,testtext_IdentityCA_testtext,0},"
"{dds.sec.auth.private_key,testtext_PrivateKey_testtext,0},"
"{dds.sec.auth.identity_certificate,testtext_IdentityCertificate_testtext,0},"
"{dds.sec.access.permissions_ca,file:Permissions_CA.pem,0},"
"{dds.sec.access.governance,file:Governance.p7s,0},"
"{dds.sec.access.permissions,file:Permissions.p7s,0}"
"}binary_value={}}*}*",
"new_participant(*): required security property "DDS_SEC_PROP_AUTH_IDENTITY_CA" missing in Property QoS*",
"new_participant(*): required security property "DDS_SEC_PROP_AUTH_PRIV_KEY" missing in Property QoS*",
"new_participant(*): required security property "DDS_SEC_PROP_AUTH_IDENTITY_CERT" missing in Property QoS*",
"new_participant(*): required security property "DDS_SEC_PROP_ACCESS_PERMISSIONS_CA" missing in Property QoS*",
"new_participant(*): required security property "DDS_SEC_PROP_ACCESS_GOVERNANCE" missing in Property QoS*",
"new_participant(*): required security property "DDS_SEC_PROP_ACCESS_PERMISSIONS" missing in Property QoS*",
#endif
NULL
};
const char *sec_config =
"<Tracing><Verbosity>finest</></>"
"<DDSSecurity>"
"<Authentication>"
"<IdentityCertificate>testtext_IdentityCertificate_testtext</IdentityCertificate>"
"<IdentityCA>testtext_IdentityCA_testtext</IdentityCA>"
"<PrivateKey>testtext_PrivateKey_testtext</PrivateKey>"
"</Authentication>"
"<AccessControl>"
"<Governance>file:Governance.p7s</Governance>"
"<PermissionsCA>file:Permissions_CA.pem</PermissionsCA>"
"<Permissions>file:Permissions.p7s</Permissions>"
"</AccessControl>"
"</DDSSecurity>";
dds_entity_t participant;
dds_qos_t * qos;
/* Set up the trace sinks to detect the config parsing. */
dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG);
dds_set_log_sink(&logger, (void*)log_expected);
dds_set_trace_sink(&logger, (void*)log_expected);
/* Create the qos */
CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL);
dds_qset_prop (qos, "dds.sec.dummy", "testtext_dummy_testtext");
/* Create participant with security config in qos. */
found = 0;
ddsrt_setenv(URI_VARIABLE, sec_config);
participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL);
dds_delete_qos(qos);
#ifdef DDSI_INCLUDE_SECURITY
CU_ASSERT_EQUAL_FATAL (participant, DDS_RETCODE_ERROR);
#else
dds_delete(participant);
#endif
ddsrt_setenv(URI_VARIABLE, "");
/* All traces should have been provided. */
#ifndef DDSI_INCLUDE_SECURITY
CU_ASSERT_FATAL(found == 0x01);
#else
CU_ASSERT_FATAL(found == 0x7e);
#endif
dds_set_log_sink(NULL, NULL);
dds_set_trace_sink(NULL, NULL);
}

View file

@ -146,7 +146,10 @@ static const char* c_userdata = "user_key";
static const char* c_topicdata = "topic_key"; static const char* c_topicdata = "topic_key";
static const char* c_groupdata = "group_key"; static const char* c_groupdata = "group_key";
static const char* c_partitions[] = {"Partition1", "Partition2"}; static const char* c_partitions[] = {"Partition1", "Partition2"};
static const char* c_property_names[] = {"prop1", "prop2", "prop3"};
static const char* c_property_values[] = {"val1", "val2", "val3"};
static const char* c_bproperty_names[] = {"bprop1", "bprop2", "bprop3"};
static const unsigned char c_bproperty_values[3][3] = {{0x0, 0x1, 0x2}, {0x2, 0x3, 0x4}, {0x5, 0x6, 0x7}};
/**************************************************************************** /****************************************************************************
@ -646,3 +649,186 @@ CU_Test(ddsc_qos, durability_service, .init=qos_init, .fini=qos_fini)
CU_ASSERT_EQUAL_FATAL(p.max_samples_per_instance, g_pol_durability_service.max_samples_per_instance); CU_ASSERT_EQUAL_FATAL(p.max_samples_per_instance, g_pol_durability_service.max_samples_per_instance);
} }
CU_Test(ddsc_qos, property, .init=qos_init, .fini=qos_fini)
{
char * value = NULL;
char ** names = NULL;
uint32_t cnt = 0;
/* NULLs shouldn't crash and be a noops. */
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], NULL));
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, &value));
CU_ASSERT_FATAL (!dds_qget_prop (NULL, c_property_names[0], &value));
dds_qset_prop (g_qos, NULL, NULL);
dds_qset_prop (g_qos, NULL, c_property_values[0]);
dds_qset_prop (NULL, c_property_names[0], c_property_values[0]);
/* Set null value should not succeed, setting empty string should */
dds_qset_prop (g_qos, c_property_names[0], NULL);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value));
dds_qset_prop (g_qos, c_property_names[0], "");
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, "");
dds_free (value);
/* Getting after setting, should yield the original input. */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
/* Overwrite value for existing property (and reset value) */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[1]);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[1]);
dds_free (value);
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
/* Set 2nd prop and get length */
dds_qset_prop (g_qos, c_property_names[1], c_property_values[1]);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
/* Set another property and get list of property names */
dds_qset_prop (g_qos, c_property_names[2], c_property_values[2]);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, &names));
CU_ASSERT_EQUAL_FATAL (cnt, 3);
for (uint32_t i = 0; i < cnt; i++)
{
CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_property_names[i]);
dds_free (names[i]);
}
dds_free (names);
/* Unset a property and check if removed */
dds_qunset_prop (g_qos, c_property_names[1]);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[1], &value));
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
CU_ASSERT_FATAL(dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[2], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[2]);
dds_free (value);
dds_qunset_prop (g_qos, c_property_names[0]);
dds_qunset_prop (g_qos, c_property_names[2]);
CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL));
}
CU_Test(ddsc_qos, bproperty, .init=qos_init, .fini=qos_fini)
{
void * bvalue = NULL;
size_t size = 0;
char ** names = NULL;
uint32_t cnt = 0;
/* NULLs shouldn't crash and be a noops. */
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[0], NULL, NULL));
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, &bvalue, &size));
CU_ASSERT_FATAL (!dds_qget_bprop (NULL, c_bproperty_names[0], &bvalue, &size));
dds_qset_bprop (g_qos, NULL, NULL, 0);
dds_qset_bprop (g_qos, NULL, &c_bproperty_values[0], 0);
dds_qset_bprop (NULL, c_bproperty_names[0], c_bproperty_values[0], 0);
/* Set null value should succeed */
dds_qset_bprop (g_qos, c_bproperty_names[0], NULL, 0);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_EQUAL_FATAL (bvalue, NULL);
CU_ASSERT_EQUAL_FATAL (size, 0);
/* Getting after setting, should yield the original input. */
dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[0], 3);
CU_ASSERT_FATAL(dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
/* Overwrite value for existing binary property (and reset value) */
dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[1], 3);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[1], size), 0);
dds_free (bvalue);
dds_qset_bprop (g_qos, c_bproperty_names[0], &c_bproperty_values[0], 3);
/* Set 2nd binary prop and get length */
dds_qset_bprop (g_qos, c_bproperty_names[1], &c_bproperty_values[1], 3);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
/* Set another binary property and get list of property names */
dds_qset_bprop (g_qos, c_bproperty_names[2], &c_bproperty_values[2], 3);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, &names));
CU_ASSERT_EQUAL_FATAL (cnt, 3);
for (uint32_t i = 0; i < cnt; i++)
{
CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_bproperty_names[i]);
dds_free (names[i]);
}
dds_free (names);
/* Unset a binary property and check if removed */
dds_qunset_bprop (g_qos, c_bproperty_names[1]);
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[1], &bvalue, &size));
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 2);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[2], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[2], size), 0);
dds_free (bvalue);
dds_qunset_bprop (g_qos, c_bproperty_names[0]);
dds_qunset_bprop (g_qos, c_bproperty_names[2]);
CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL));
}
CU_Test(ddsc_qos, property_mixed, .init=qos_init, .fini=qos_fini)
{
char * value = NULL;
void * bvalue = NULL;
size_t size = 0;
uint32_t cnt = 0;
/* Set property and binary property with same name */
dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]);
dds_qset_bprop (g_qos, c_property_names[0], c_bproperty_values[0], 3);
/* Check property values and count */
CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size));
CU_ASSERT_FATAL (bvalue != NULL);
CU_ASSERT_EQUAL_FATAL (size, 3);
CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0);
dds_free (bvalue);
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 1);
CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL));
CU_ASSERT_EQUAL_FATAL (cnt, 1);
/* Unset and check */
dds_qunset_bprop (g_qos, c_property_names[0]);
CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size));
CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]);
dds_free (value);
dds_qunset_prop (g_qos, c_property_names[0]);
CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value));
CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL));
CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL));
}

View file

@ -321,9 +321,21 @@ DDS_EXPORT uint64_t nn_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint6
DDS_EXPORT void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted); DDS_EXPORT void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted);
DDS_EXPORT void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); DDS_EXPORT void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos);
DDS_EXPORT dds_qos_t *nn_xqos_dup (const dds_qos_t *src); DDS_EXPORT dds_qos_t *nn_xqos_dup (const dds_qos_t *src);
DDS_EXPORT bool nn_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith);
#ifdef DDSI_INCLUDE_SECURITY #ifdef DDSI_INCLUDE_SECURITY
#define DDS_SEC_PROP_AUTH_IDENTITY_CA "dds.sec.auth.identity_ca"
#define DDS_SEC_PROP_AUTH_PRIV_KEY "dds.sec.auth.private_key"
#define DDS_SEC_PROP_AUTH_IDENTITY_CERT "dds.sec.auth.identity_certificate"
#define DDS_SEC_PROP_AUTH_PASSWORD "dds.sec.auth.password"
#define DDS_SEC_PROP_ACCESS_PERMISSIONS_CA "dds.sec.access.permissions_ca"
#define DDS_SEC_PROP_ACCESS_GOVERNANCE "dds.sec.access.governance"
#define DDS_SEC_PROP_ACCESS_PERMISSIONS "dds.sec.access.permissions"
#define DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR "dds.sec.auth.trusted_ca_dir"
struct omg_security_configuration_type; struct omg_security_configuration_type;
DDS_EXPORT void nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg); DDS_EXPORT bool nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg);
#endif #endif
#if defined (__cplusplus) #if defined (__cplusplus)

View file

@ -465,6 +465,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
{ {
struct participant *pp; struct participant *pp;
ddsi_guid_t subguid, group_guid; ddsi_guid_t subguid, group_guid;
dds_return_t ret = DDS_RETCODE_OK;
/* no reserved bits may be set */ /* no reserved bits may be set */
assert ((flags & ~(RTPS_PF_NO_BUILTIN_READERS | RTPS_PF_NO_BUILTIN_WRITERS | RTPS_PF_PRIVILEGED_PP | RTPS_PF_IS_DDSI2_PP | RTPS_PF_ONLY_LOCAL)) == 0); assert ((flags & ~(RTPS_PF_NO_BUILTIN_READERS | RTPS_PF_NO_BUILTIN_WRITERS | RTPS_PF_PRIVILEGED_PP | RTPS_PF_IS_DDSI2_PP | RTPS_PF_ONLY_LOCAL)) == 0);
@ -499,7 +500,8 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
{ {
ddsrt_mutex_unlock (&gv->participant_set_lock); ddsrt_mutex_unlock (&gv->participant_set_lock);
GVERROR ("new_participant("PGUIDFMT", %x) failed: max participants reached\n", PGUID (*ppguid), flags); GVERROR ("new_participant("PGUIDFMT", %x) failed: max participants reached\n", PGUID (*ppguid), flags);
return DDS_RETCODE_OUT_OF_RESOURCES; ret = DDS_RETCODE_OUT_OF_RESOURCES;
goto new_pp_err;
} }
} }
@ -524,7 +526,29 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
{ {
/* For security, configuration can be provided through the configuration. /* For security, configuration can be provided through the configuration.
* However, the specification (and the plugins) expect it to be in the QoS. */ * However, the specification (and the plugins) expect it to be in the QoS. */
nn_xqos_mergein_security_config(&(pp->plist->qos), &(gv->config.omg_security_configuration->cfg)); if (!nn_xqos_mergein_security_config(&pp->plist->qos, &gv->config.omg_security_configuration->cfg))
{
char *req[] = { DDS_SEC_PROP_AUTH_IDENTITY_CA,
DDS_SEC_PROP_AUTH_PRIV_KEY,
DDS_SEC_PROP_AUTH_IDENTITY_CERT,
DDS_SEC_PROP_ACCESS_PERMISSIONS_CA,
DDS_SEC_PROP_ACCESS_GOVERNANCE,
DDS_SEC_PROP_ACCESS_PERMISSIONS };
GVLOGDISC ("new_participant("PGUIDFMT"): using security settings from QoS, ignoring security configuration\n", PGUID (*ppguid));
/* check if all required security properties exist in qos */
for (size_t i = 0; i < sizeof(req) / sizeof(req[0]); i++)
{
if (!nn_xqos_has_prop (&pp->plist->qos, req[i], false))
{
GVERROR ("new_participant("PGUIDFMT"): required security property %s missing in Property QoS\n", PGUID (*ppguid), req[i]);
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
}
}
if (ret != DDS_RETCODE_OK)
goto new_pp_err_secprop;
}
} }
#endif #endif
@ -723,7 +747,22 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
tsched.v = (pp->lease_duration == T_NEVER) ? T_NEVER : 0; tsched.v = (pp->lease_duration == T_NEVER) ? T_NEVER : 0;
pp->pmd_update_xevent = qxev_pmd_update (gv->xevents, tsched, &pp->e.guid); pp->pmd_update_xevent = qxev_pmd_update (gv->xevents, tsched, &pp->e.guid);
} }
return 0; return ret;
#ifdef DDSI_INCLUDE_SECURITY
new_pp_err_secprop:
nn_plist_fini (pp->plist);
ddsrt_free (pp->plist);
inverse_uint32_set_fini (&pp->avail_entityids.x);
ddsrt_mutex_destroy (&pp->refc_lock);
entity_common_fini (&pp->e);
ddsrt_free (pp);
ddsrt_mutex_lock (&gv->participant_set_lock);
gv->nparticipants--;
ddsrt_mutex_unlock (&gv->participant_set_lock);
#endif
new_pp_err:
return ret;
} }
dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)

View file

@ -27,6 +27,7 @@
#include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_time.h" #include "dds/ddsi/q_time.h"
#include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/ddsi_vendor.h" #include "dds/ddsi/ddsi_vendor.h"
#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */ #include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */
@ -2887,6 +2888,21 @@ dds_qos_t * nn_xqos_dup (const dds_qos_t *src)
return dst; return dst;
} }
bool nn_xqos_has_prop (const dds_qos_t *xqos, const char *pname, bool startswith)
{
if (!(xqos->present & QP_PROPERTY_LIST))
return false;
for (uint32_t i = 0; i < xqos->property.value.n; i++)
{
if (startswith && (strncmp (xqos->property.value.props[i].name, pname, strlen (pname)) == 0))
return true;
else if (!startswith && (strcmp (xqos->property.value.props[i].name, pname) == 0))
return true;
}
return false;
}
#ifdef DDSI_INCLUDE_SECURITY #ifdef DDSI_INCLUDE_SECURITY
static void fill_property(dds_property_t *prop, const char *name, const char *value) static void fill_property(dds_property_t *prop, const char *name, const char *value)
{ {
@ -2895,44 +2911,42 @@ static void fill_property(dds_property_t *prop, const char *name, const char *va
prop->propagate = false; prop->propagate = false;
} }
void nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg) /**
* Add DDS Security configuration to the QoS as a Property policy used by the security
* plugins to get their proper settings. If security properties are already present in
* the QoS, the settings from configuration are ignored.
*/
bool nn_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg)
{ {
if (cfg) assert(cfg != NULL);
if (!(xqos->present & QP_PROPERTY_LIST))
{ {
/* Add DDS Security configuration to the QoS as a Property policy, xqos->property.value.n = 0;
* used by the security plugins to get their proper settings. */ xqos->property.value.props = NULL;
dds_property_t *properties;
uint32_t idx = 0;
/* No property should be present yet. */
assert(!(xqos->present & QP_PROPERTY_LIST));
/* Prepare properties. */
properties = ddsrt_malloc(8 /* max */ * sizeof (dds_property_t));
/* Fill properties. */
fill_property(&(properties[idx++]), "dds.sec.auth.identity_ca", cfg->authentication_properties.identity_ca);
fill_property(&(properties[idx++]), "dds.sec.auth.private_key", cfg->authentication_properties.private_key);
fill_property(&(properties[idx++]), "dds.sec.auth.identity_certificate", cfg->authentication_properties.identity_certificate);
fill_property(&(properties[idx++]), "dds.sec.access.permissions_ca", cfg->access_control_properties.permissions_ca);
fill_property(&(properties[idx++]), "dds.sec.access.governance", cfg->access_control_properties.governance);
fill_property(&(properties[idx++]), "dds.sec.access.permissions", cfg->access_control_properties.permissions);
if (cfg->authentication_properties.password && (strlen(cfg->authentication_properties.password) != 0))
{
fill_property(&(properties[idx++]), "dds.sec.auth.password", cfg->authentication_properties.password);
}
if (cfg->authentication_properties.trusted_ca_dir && (strlen(cfg->authentication_properties.trusted_ca_dir) != 0))
{
fill_property(&(properties[idx++]), "dds.sec.auth.trusted_ca_dir", cfg->authentication_properties.trusted_ca_dir);
}
/* Add properties. */
xqos->present |= QP_PROPERTY_LIST;
xqos->property.value.n = idx;
xqos->property.value.props = properties;
xqos->property.binary_value.n = 0; xqos->property.binary_value.n = 0;
xqos->property.binary_value.props = NULL; xqos->property.binary_value.props = NULL;
xqos->present |= QP_PROPERTY_LIST;
} }
/* check for existing security properties (name starts with dds.sec. conform DDS Security spec 7.2.4.1)
* and return if any is found */
if (nn_xqos_has_prop (xqos, "dds.sec.", true))
return false;
/* no security properties exist in qos: fill QoS properties with values from configuration */
xqos->property.value.props = ddsrt_realloc (xqos->property.value.props, xqos->property.value.n + 8 /* max */ * sizeof (dds_property_t));
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_IDENTITY_CA, cfg->authentication_properties.identity_ca);
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_PRIV_KEY, cfg->authentication_properties.private_key);
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_IDENTITY_CERT, cfg->authentication_properties.identity_certificate);
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, cfg->access_control_properties.permissions_ca);
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_GOVERNANCE, cfg->access_control_properties.governance);
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_PERMISSIONS, cfg->access_control_properties.permissions);
if (cfg->authentication_properties.password && (strlen(cfg->authentication_properties.password) != 0))
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_PASSWORD, cfg->authentication_properties.password);
if (cfg->authentication_properties.trusted_ca_dir && (strlen(cfg->authentication_properties.trusted_ca_dir) != 0))
fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, cfg->authentication_properties.trusted_ca_dir);
return true;
} }
#endif /* DDSI_INCLUDE_SECURITY */ #endif /* DDSI_INCLUDE_SECURITY */

View file

@ -42,12 +42,13 @@
#define DDS_READERLIFESPAN_QOS_POLICY_NAME "ReaderLifespan" #define DDS_READERLIFESPAN_QOS_POLICY_NAME "ReaderLifespan"
#define DDS_SHARE_QOS_POLICY_NAME "Share" #define DDS_SHARE_QOS_POLICY_NAME "Share"
#define DDS_SCHEDULING_QOS_POLICY_NAME "Scheduling" #define DDS_SCHEDULING_QOS_POLICY_NAME "Scheduling"
#define DDS_PROPERTY_QOS_POLICY_NAME "Property"
#define DDS_SUBSCRIPTIONKEY_QOS_POLICY_ID 23 #define DDS_SUBSCRIPTIONKEY_QOS_POLICY_ID 24
#define DDS_VIEWKEY_QOS_POLICY_ID 24 #define DDS_VIEWKEY_QOS_POLICY_ID 25
#define DDS_READERLIFESPAN_QOS_POLICY_ID 25 #define DDS_READERLIFESPAN_QOS_POLICY_ID 26
#define DDS_SHARE_QOS_POLICY_ID 26 #define DDS_SHARE_QOS_POLICY_ID 27
#define DDS_SCHEDULING_QOS_POLICY_ID 27 #define DDS_SCHEDULING_QOS_POLICY_ID 28
extern dds_entity_t dp; extern dds_entity_t dp;
extern const dds_topic_descriptor_t *ts_KeyedSeq; extern const dds_topic_descriptor_t *ts_KeyedSeq;

View file

@ -1051,6 +1051,7 @@ static const char *policystr(uint32_t id) {
case DDS_READERLIFESPAN_QOS_POLICY_ID: return DDS_READERLIFESPAN_QOS_POLICY_NAME; case DDS_READERLIFESPAN_QOS_POLICY_ID: return DDS_READERLIFESPAN_QOS_POLICY_NAME;
case DDS_SHARE_QOS_POLICY_ID: return DDS_SHARE_QOS_POLICY_NAME; case DDS_SHARE_QOS_POLICY_ID: return DDS_SHARE_QOS_POLICY_NAME;
case DDS_SCHEDULING_QOS_POLICY_ID: return DDS_SCHEDULING_QOS_POLICY_NAME; case DDS_SCHEDULING_QOS_POLICY_ID: return DDS_SCHEDULING_QOS_POLICY_NAME;
case DDS_PROPERTY_QOS_POLICY_ID: return DDS_PROPERTY_QOS_POLICY_NAME;
default: return "?"; default: return "?";
} }
} }