support delayed endpoint matching (#315)

* support delayed endpoint matching

Signed-off-by: Marcel Jordense <marcel.jordense@adlinktech.com>

* Update delayed endpoint matching

Signed-off-by: Marcel Jordense <marcel.jordense@adlinktech.com>
This commit is contained in:
MarcelJordense 2020-01-08 16:19:55 +01:00 committed by eboasson
parent 861f19a2ad
commit b561cb821f
10 changed files with 1282 additions and 19 deletions

View file

@ -20,6 +20,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_mcgroup.c ddsi_mcgroup.c
ddsi_security_omg.c ddsi_security_omg.c
ddsi_portmapping.c ddsi_portmapping.c
ddsi_handshake.c
ddsi_serdata.c ddsi_serdata.c
ddsi_serdata_default.c ddsi_serdata_default.c
ddsi_sertopic.c ddsi_sertopic.c
@ -77,6 +78,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_plist_generic.h ddsi_plist_generic.h
ddsi_security_omg.h ddsi_security_omg.h
ddsi_portmapping.h ddsi_portmapping.h
ddsi_handshake.h
ddsi_serdata.h ddsi_serdata.h
ddsi_sertopic.h ddsi_sertopic.h
ddsi_serdata_default.h ddsi_serdata_default.h

View file

@ -112,6 +112,7 @@ struct entidx_enum_proxy_reader { struct entidx_enum st; };
void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) ddsrt_nonnull_all; void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) ddsrt_nonnull_all;
void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *gh, enum entity_kind kind, const char *topic, struct match_entities_range_key *max) ddsrt_nonnull_all; void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *gh, enum entity_kind kind, const char *topic, struct match_entities_range_key *max) ddsrt_nonnull_all;
void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max) ddsrt_nonnull_all;
void *entidx_enum_next_max (struct entidx_enum *st, const struct match_entities_range_key *max) ddsrt_nonnull_all; void *entidx_enum_next_max (struct entidx_enum *st, const struct match_entities_range_key *max) ddsrt_nonnull_all;
void *entidx_enum_next (struct entidx_enum *st) ddsrt_nonnull_all; void *entidx_enum_next (struct entidx_enum *st) ddsrt_nonnull_all;
void entidx_enum_fini (struct entidx_enum *st) ddsrt_nonnull_all; void entidx_enum_fini (struct entidx_enum *st) ddsrt_nonnull_all;

View file

@ -0,0 +1,197 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#ifndef DDSI_HANDSHAKE_H
#define DDSI_HANDSHAKE_H
#include "q_unused.h"
#include "q_entity.h"
#include "ddsi_security_msg.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct participant;
struct proxy_participant;
struct ddsi_handshake;
struct dssi_hsadmin;
enum ddsi_handshake_state {
STATE_HANDSHAKE_IN_PROGRESS,
STATE_HANDSHAKE_TIMED_OUT,
STATE_HANDSHAKE_FAILED,
STATE_HANDSHAKE_PROCESSED,
STATE_HANDSHAKE_SEND_TOKENS,
STATE_HANDSHAKE_OK
};
/* The handshake will not use the related handshake object after this callback
* was executed. This means that it can be deleted in this callback. */
typedef void (*ddsi_handshake_end_cb_t)(
struct q_globals const * const gv,
struct ddsi_handshake *handshake,
const ddsi_guid_t *lpguid, /* Local participant */
const ddsi_guid_t *ppguid, /* Proxy participant */
enum ddsi_handshake_state result);
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/ddsi/ddsi_security_msg.h"
/**
* @brief Release the handshake.
*
* This function will decrement the refcount associated with the handshake
* and delete the handshake when the refcount becomes 0.
*
* @param[in] handshake The handshake.
*/
void ddsi_handshake_release(struct ddsi_handshake *handshake);
/**
* @brief Handle an authentication handshake message received from the remote participant.
*
* During the authentication phase handshake messages are being exchanged between the local and
* the remote participant. THis function will handle a handshake message received from a remote
* participant.
*
* @param[in] handshake The handshake.
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
* @param[in] msg The handshake message received.
*/
void ddsi_handshake_handle_message(struct ddsi_handshake *handshake, const struct participant *pp, const struct proxy_participant *proxypp, const struct nn_participant_generic_message *msg);
/**
* @brief Notify the handshake that crypto tokens have been received.
*
* The handshake could be finished at one end while the other side has not yet processed the
* final handshake messages. The arrival of crypto tokens signals that the other side has also finished
* processing the handshake. This function is used to signal the handshake that crypto tokens have been
* received.
*
* @param[in] handshake The handshake.
*/
void ddsi_handshake_crypto_tokens_received(struct ddsi_handshake *handshake);
/**
* @brief Get the shared secret handle.
*
* During the handshake a shared secret is established which is used to encrypt
* and decrypt the crypto token exchange messages. This function will return a
* handle to the shared secret which will be passed to the crypto plugin to
* determine the session keys used for the echange of the the crypto tokens.
*
* @param[in] handshake The handshake.
*
* @returns handle to the shared sercet.
*/
int64_t ddsi_handshake_get_shared_secret(const struct ddsi_handshake *handshake);
/**
* @brief Get the handshake handle
*
* This function returns the handshake handle that was returned by the authentication plugin
* when starting the handshake.
*
* @param[in] handshake The handshake.
*
* @returns The handshake handle.
*/
int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake);
/**
* @brief Create and start the handshake for the participants
*
* This function will create a handshake for the specified local
* and remote participants when it does not yet exists. It will start the
* handshake procedure by calling the corresponding functions of the authentication plugin.
* The callback function is called by the handshake when to report events,
* for example to indicate that the handshake has finished or has failed.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
* @param[in] callback The callback function.
*
*/
void ddsi_handshake_register(const struct participant *pp, const struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback);
/**
* @brief Remove the handshake associated with the specified participants.
*
* This function will remove the handshake from the handshake administation and release
* the handshake. When the handshake argument is not specified the handshake is searched
* in the handshake administation.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
* @param[in] handshake The handshake.
*
*/
void ddsi_handshake_remove(const struct participant *pp, const struct proxy_participant *proxypp, struct ddsi_handshake *handshake);
/**
* @brief Searches for the handshake associated with the specified participants
*
* This function will search through the handshake administration to find the handshake
* corresponding the to specified local and remote participant.
*
* @param[in] pp The local participant.
* @param[in] proxypp The remote participant.
*
* @returns The handshake
*/
struct ddsi_handshake * ddsi_handshake_find(const struct participant *pp, const struct proxy_participant *proxypp);
#else /* DDSI_INCLUDE_SECURITY */
#include "dds/ddsi/q_unused.h"
inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline void ddsi_handshake_crypto_tokens_received(UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline int64_t ddsi_handshake_get_shared_secret(UNUSED_ARG(const struct ddsi_handshake *handshake))
{
return 0;
}
inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake *handshake))
{
return 0;
}
inline void ddsi_handshake_register(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback))
{
}
inline void ddsi_handshake_remove(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake))
{
}
inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp))
{
return NULL;
}
#endif /* DDSI_INCLUDE_SECURITY */
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_HANDSHAKE_H */

View file

@ -12,6 +12,8 @@
#ifndef DDSI_SECURITY_MSG_H #ifndef DDSI_SECURITY_MSG_H
#define DDSI_SECURITY_MSG_H #define DDSI_SECURITY_MSG_H
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_plist.h"
#include "dds/ddsi/ddsi_guid.h" #include "dds/ddsi/ddsi_guid.h"
#include "dds/ddsrt/retcode.h" #include "dds/ddsrt/retcode.h"
@ -108,4 +110,6 @@ volatile_secure_data_filter(
} }
#endif #endif
#endif
#endif /* DDSI_SECURITY_MSG_H */ #endif /* DDSI_SECURITY_MSG_H */

View file

@ -57,6 +57,17 @@ bool q_omg_security_enabled(void);
*/ */
bool q_omg_participant_is_secure(const struct participant *pp); bool q_omg_participant_is_secure(const struct participant *pp);
/**
* @brief Check if security is enabled for the proxy participant.
*
* @param[in] proxypp Proxy participant to check if it is secure.
*
* @returns bool
* @retval true Proxy participant is secure
* @retval false Proxy participant is not secure
*/
bool q_omg_proxy_participant_is_secure(const struct proxy_participant *proxypp);
/** /**
* @brief Get the security handle of the given local participant. * @brief Get the security handle of the given local participant.
* *
@ -490,6 +501,195 @@ secure_conn_write(
nn_msg_sec_info_t *sec_info, nn_msg_sec_info_t *sec_info,
ddsi_tran_write_fn_t conn_write_cb); ddsi_tran_write_fn_t conn_write_cb);
/**
* @brief Check if the participant and the proxy participant
* have compatible security info settings.
*
* Associated with a secure participant is the ParticipantSecurityInfo parameter.
* This parameter contains the setting of the security attributes and the associated
* plugin security attributes of the secure participant.
* This function will check if the received ParticipantSecurityInfo parameter is
* compatible with the local ParticipantSecurityInfo parameter.
*
* @param[in] pp The participant.
* @param[in] proxypp The proxy participant.
*
* @returns bool
* @retval true The participant and the proxy participant have compatible
* security info settings.
* @retval false Otherwise.
*/
bool q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Check if the participant allows communication with unauthenticated
* participants
*
* @param[in] pp The participant.
*
* @returns bool
* @retval true The participant allows unauthenticated communication
* @retval false Otherwise.
*/
bool q_omg_participant_allow_unauthenticated(struct participant *pp);
/**
* @brief Register participant with security plugin and check if the
* participant is allowed by security.
*
* This function will register the participant with the authentication
* plugin which will check if the provided security QoS parameters are
* correct, e.g. is the provided certificate valid, etc.
* When that is successful it is checked with access control if the
* participant has the correct permissions and is allowed to be created.
*
* @param[in] pp The participant.
* @param[in] domain_id The domain id.
*
* @returns bool
* @retval true The security check on the participant succeeded.
* @retval false The security check on the participant failed.
*/
bool q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id);
/**
* @brief Initialize the proxy participant security attributes
*
* @param[in] proxypp The proxy participant.
*
*/
void q_omg_security_init_remote_participant(struct proxy_participant *proxypp);
/**
* @brief Check the if the proxy participant is allowed by checking the security permissions.
*
* The access control plugin is ask to verify if the proxy participant is allowed to
* communicate with the local participant. When the proxy participant is allowed the
* function will return a valid permission handle which is provided by the access control plugin.
*
* @param[in] domain_id The domain id
* @param[in] pp The participant
* @param[in] proxypp The proxy participant
*
* @returns permission handle
* @retval !0 The proxy participant is allowed
* @retval 0 The proxy participant is not allowed.
*/
int64_t q_omg_security_check_remote_participant_permissions(uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Registers the matched proxy participant with the crypto plugin
*
* When the proxy participant is authenticated and allowed by access control then the match between the local and
* the remote participant must be registered with the cypto factory provided by the crypto plugin. The
* shared secret handle obtained from the authentication phase and the permission handle returned when validating
* the proxy participant with access control plugin have to be provided.
*
*
* @param[in] pp The participant.
* @param[in] proxypp The proxy participant.
* @param[in] shared_secret The shared_secret handle.
* @param[in] proxy_permissions The permission handle associated with the proxy participant.
*/
void q_omg_security_register_remote_participant(struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret, int64_t proxy_permissions);
/**
* @brief Removes a registered proxy participant from administation of the authentication,
* access control and crypto plugins.
*
* @param[in] proxypp The proxy participant.
*/
void q_omg_security_deregister_remote_participant(struct proxy_participant *proxypp);
/**
* @brief Generate and send the crypto tokens needed for encoding RTPS messages.
*
* When the security settings indicate that RTPS message encoding or signing is
* configured for the participant then this function will ask the cypto echange for
* the corresponding cypto tokens and send these to the proxy participant.
*
* @param[in] pp The participant.
* @param[in] proxypp The proxy participant.
*/
void q_omg_security_participant_send_tokens(struct participant *pp, struct proxy_participant *proxypp);
/**
* @brief Check if the remote writer is allowed to communicate with endpoints of the
* local participant.
*
* This function will check with the access control plugin if the remote writer
* is allowed to communicate with this participant.
*
* @param[in] pwr The remote writer.
* @param[in] domain_id The domain id.
* @param[in] pp The local participant.
*
* @returns bool
* @retval true The remote writer is allowed to communicate.
* @retval false Otherwise.
*/
bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp);
/**
* @brief Check if the remote reader is allowed to communicate with endpoints of the
* local participant.
*
* This function will check with the access control plugin if the remote reader
* is allowed to communicate with this participant.
*
* @param[in] prd The remote reader.
* @param[in] domain_id The domain id.
* @param[in] pp The local participant.
*
* @returns bool
* @retval true The remote reader is allowed to communicate.
* @retval false Otherwise.
*/
bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp);
/**
* @brief Check it the remote writer is allowed to communicate with the local reader.
*
* When a remote writer is allowed by access control it has to be checked if the remote
* writer is allowed to communicate with a particular local reader. This function will
* check if the provided security end-point attributes are compatible, When the security
* attributes are compatible then the function will register the reader and remote writer
* match with the crypto factory and will also ask the crypto exchange to generate the
* crypto tokens associate with the local reader which will be sent to the remote entity.
* Note that the reader crypto tokens are used to encrypt the reader specific submessages
* when submessage encoding or signing is configured.
*
* @param[in] rd The local reader.
* @param[in] pwr The remote writer.
*
* @returns bool
* @retval true The local reader and remote writer are allowed to communicate.
* @retval false Otherwise.
*/
bool q_omg_security_match_remote_writer_enabled(struct reader *rd, struct proxy_writer *pwr);
/**
* @brief Check it the local writer is allowed to communicate with the remote reader.
*
* When a remote reader is allowed by access control it has to be checked if the local
* writer is allowed to communicate with a particular local writer. This function will
* check if the provided security end-point attributes are compatible, When the security
* attributes are compatible then the function will register the writer and remote reader
* match with the crypto factory and will also ask the crypto exchange to generate the
* crypto tokens associate with the local writer which will be sent to the remote entity.
* Note that the writer crypto tokens are used to encrypt the writer specific submessages
* when submessage encoding or signing is configured and also the crypto tokens used
* for encoding the payload of data or datafrag messages.
*
* @param[in] wr The local writer.
* @param[in] prd The remote reader.
*
* @returns bool
* @retval true The local writer and remote reader are allowed to communicate.
* @retval false Otherwise.
*/
bool q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd);
#else /* DDSI_INCLUDE_SECURITY */ #else /* DDSI_INCLUDE_SECURITY */
#include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_unused.h"
@ -507,6 +707,13 @@ q_omg_participant_is_secure(
return false; return false;
} }
inline bool
q_omg_proxy_participant_is_secure(
UNUSED_ARG(const struct proxy_participant *proxypp))
{
return false;
}
inline unsigned inline unsigned
determine_subscription_writer( determine_subscription_writer(
UNUSED_ARG(const struct reader *rd)) UNUSED_ARG(const struct reader *rd))
@ -530,6 +737,65 @@ is_proxy_participant_deletion_allowed(
return true; return true;
} }
inline bool q_omg_is_similar_participant_security_info(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp))
{
return true;
}
inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct participant *pp))
{
return true;
}
inline bool
q_omg_security_check_create_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id))
{
return true;
}
inline void q_omg_security_init_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp))
{
}
inline int64_t q_omg_security_check_remote_participant_permissions(UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp))
{
return 0LL;
}
inline void q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t shared_secret), UNUSED_ARG(int64_t proxy_permissions))
{
}
inline void q_omg_security_deregister_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp))
{
}
inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp))
{
}
inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr))
{
return true;
}
inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd))
{
return true;
}
inline bool
q_omg_security_check_remote_writer_permissions(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp))
{
return true;
}
inline bool
q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp))
{
return true;
}
inline void inline void
set_proxy_participant_security_info( set_proxy_participant_security_info(
UNUSED_ARG(struct proxy_participant *prd), UNUSED_ARG(struct proxy_participant *prd),
@ -551,7 +817,6 @@ set_proxy_writer_security_info(
{ {
} }
inline bool inline bool
decode_Data( decode_Data(
UNUSED_ARG(const struct q_globals *gv), UNUSED_ARG(const struct q_globals *gv),

View file

@ -20,11 +20,13 @@
#include "dds/ddsi/q_rtps.h" #include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_protocol.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_lat_estim.h" #include "dds/ddsi/q_lat_estim.h"
#include "dds/ddsi/q_hbcontrol.h" #include "dds/ddsi/q_hbcontrol.h"
#include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/q_inverse_uint32_set.h" #include "dds/ddsi/q_inverse_uint32_set.h"
#include "dds/ddsi/ddsi_serdata_default.h" #include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/ddsi_handshake.h"
#include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/ddsi_tran.h"
@ -214,6 +216,11 @@ struct participant
int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */ int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */
int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */ int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */
ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */ ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */
#ifdef DDSI_INCLUDE_SECURITY
int64_t local_identity_handle; /* OMG DDS Security related member */
int64_t permissions_handle; /* OMG DDS Security related member */
struct participant_sec_attributes *sec_attr;
#endif
}; };
struct endpoint_common { struct endpoint_common {
@ -356,7 +363,9 @@ struct proxy_participant
unsigned proxypp_have_cm: 1; unsigned proxypp_have_cm: 1;
unsigned owns_lease: 1; unsigned owns_lease: 1;
#ifdef DDSI_INCLUDE_SECURITY #ifdef DDSI_INCLUDE_SECURITY
int64_t remote_identity_handle; /* OMG DDS Security related member */
nn_security_info_t security_info; nn_security_info_t security_info;
struct proxy_participant_sec_attributes *sec_attr;
#endif #endif
}; };
@ -712,6 +721,10 @@ void rebuild_or_clear_writer_addrsets(struct q_globals *gv, int rebuild);
void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok); void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow);
void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow);
struct ddsi_writer_info; struct ddsi_writer_info;
DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos, uint32_t statusinfo); DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos, uint32_t statusinfo);

View file

@ -439,6 +439,18 @@ void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *
st->cur = NULL; st->cur = NULL;
} }
void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max)
{
assert (kind == EK_READER || kind == EK_WRITER || kind == EK_PROXY_READER || kind == EK_PROXY_WRITER);
struct match_entities_range_key min;
match_endpoint_range (kind, topic, &min, max);
min.entity.e.guid.prefix = *prefix;
max->entity.e.guid.prefix = *prefix;
entidx_enum_init_minmax_int (st, ei, &min);
if (st->cur && all_entities_compare (st->cur, &max->entity) > 0)
st->cur = NULL;
}
void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind)
{ {
struct match_entities_range_key min; struct match_entities_range_key min;

View file

@ -0,0 +1,109 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsi/ddsi_handshake.h"
#ifdef DDSI_INCLUDE_SECURITY
#include "dds/security/dds_security_api.h"
#include "dds/ddsrt/hopscotch.h"
struct ddsi_handshake
{
enum ddsi_handshake_state state;
ddsi_guid_t local_pguid; /* the guid of the local participant */
ddsi_guid_t remote_pguid; /* the guid of the remote participant */
ddsi_handshake_end_cb_t end_cb;
struct q_globals *gv;
ddsrt_mutex_t lock;
ddsrt_cond_t cv;
ddsrt_atomic_uint32_t refc;
DDS_Security_IdentityHandle local_identity_handle;
DDS_Security_IdentityHandle remote_identity_handle;
DDS_Security_HandshakeHandle handshake_handle;
DDS_Security_HandshakeMessageToken handshake_message_in_token;
nn_message_identity_t handshake_message_in_id;
DDS_Security_HandshakeMessageToken *handshake_message_out;
DDS_Security_AuthRequestMessageToken local_auth_request_token;
DDS_Security_AuthRequestMessageToken *remote_auth_request_token;
DDS_Security_OctetSeq pdata;
DDS_Security_SharedSecretHandle shared_secret;
int handled_handshake_message;
};
void ddsi_handshake_handle_message(struct ddsi_handshake *handshake, const struct participant *pp, const struct proxy_participant *proxypp, const struct nn_participant_generic_message *msg)
{
DDSRT_UNUSED_ARG(handshake);
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
DDSRT_UNUSED_ARG(msg);
}
void ddsi_handshake_crypto_tokens_received(struct ddsi_handshake *handshake)
{
DDSRT_UNUSED_ARG(handshake);
}
int64_t ddsi_handshake_get_shared_secret(const struct ddsi_handshake *handshake)
{
DDSRT_UNUSED_ARG(handshake);
return 0;
}
int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake)
{
DDSRT_UNUSED_ARG(handshake);
return 0;
}
void ddsi_handshake_register(const struct participant *pp, const struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
DDSRT_UNUSED_ARG(callback);
}
void ddsi_handshake_remove(const struct participant *pp, const struct proxy_participant *proxypp, struct ddsi_handshake *handshake)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
DDSRT_UNUSED_ARG(handshake);
}
struct ddsi_handshake * ddsi_handshake_find(const struct participant *pp, const struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
return NULL;
}
#else
extern inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *handshake));
extern inline void ddsi_handshake_crypto_tokens_received(UNUSED_ARG(struct ddsi_handshake *handshake));
extern inline int64_t ddsi_handshake_get_shared_secret(UNUSED_ARG(const struct ddsi_handshake *handshake));
extern inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake *handshake));
extern inline void ddsi_handshake_register(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback));
extern inline void ddsi_handshake_remove(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake));
extern inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp));
#endif /* DDSI_INCLUDE_DDS_SECURITY */

View file

@ -92,6 +92,15 @@ q_omg_participant_is_secure(
return false; return false;
} }
bool
q_omg_proxy_participant_is_secure(
const struct proxy_participant *proxypp)
{
/* TODO: Register remote participant */
DDSRT_UNUSED_ARG(proxypp);
return false;
}
static bool static bool
q_omg_writer_is_discovery_protected( q_omg_writer_is_discovery_protected(
const struct writer *wr) const struct writer *wr)
@ -147,6 +156,12 @@ q_omg_get_reader_security_info(
return false; return false;
} }
void
q_omg_security_init_remote_participant(struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(proxypp);
}
static bool static bool
q_omg_proxyparticipant_is_authenticated( q_omg_proxyparticipant_is_authenticated(
const struct proxy_participant *proxy_pp) const struct proxy_participant *proxy_pp)
@ -174,6 +189,14 @@ q_omg_security_get_remote_participant_handle(
return 0; return 0;
} }
bool
q_omg_participant_allow_unauthenticated(struct participant *pp)
{
DDSRT_UNUSED_ARG(pp);
return true;
}
unsigned unsigned
determine_subscription_writer( determine_subscription_writer(
const struct reader *rd) const struct reader *rd)
@ -196,6 +219,21 @@ determine_publication_writer(
return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER; return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER;
} }
void
q_omg_security_register_remote_participant(struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret, int64_t proxy_permissions)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
DDSRT_UNUSED_ARG(shared_secret);
DDSRT_UNUSED_ARG(proxy_permissions);
}
void
q_omg_security_deregister_remote_participant(struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(proxypp);
}
bool bool
is_proxy_participant_deletion_allowed( is_proxy_participant_deletion_allowed(
struct q_globals * const gv, struct q_globals * const gv,
@ -225,6 +263,93 @@ is_proxy_participant_deletion_allowed(
return (!q_omg_proxyparticipant_is_authenticated(proxypp)); return (!q_omg_proxyparticipant_is_authenticated(proxypp));
} }
/* ask to access control security plugin for the remote participant permissions */
int64_t
q_omg_security_check_remote_participant_permissions(uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
return 0;
}
bool
q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
return true;
}
bool
q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(domain_id);
return true;
}
void
q_omg_security_participant_send_tokens(struct participant *pp, struct proxy_participant *proxypp)
{
DDSRT_UNUSED_ARG(pp);
DDSRT_UNUSED_ARG(proxypp);
}
bool
q_omg_security_match_remote_writer_enabled(struct reader *rd, struct proxy_writer *pwr)
{
DDSRT_UNUSED_ARG(rd);
DDSRT_UNUSED_ARG(pwr);
assert(rd);
assert(pwr);
return true;
}
bool
q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd)
{
DDSRT_UNUSED_ARG(wr);
DDSRT_UNUSED_ARG(prd);
assert(wr);
assert(prd);
return true;
}
bool
q_omg_security_check_remote_writer_permissions(const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp)
{
DDSRT_UNUSED_ARG(pwr);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(pp);
assert(pwr);
assert(pp);
assert(pwr->c.proxypp);
return true;
}
bool
q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp)
{
DDSRT_UNUSED_ARG(prd);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(pp);
assert(prd);
assert(pp);
assert(prd->c.proxypp);
return true;
}
bool bool
q_omg_security_is_remote_rtps_protected( q_omg_security_is_remote_rtps_protected(
struct proxy_participant *proxy_pp, struct proxy_participant *proxy_pp,
@ -792,7 +917,7 @@ validate_msg_decoding(
* that is expected. */ * that is expected. */
if (q_omg_security_is_remote_rtps_protected(proxypp, e->guid.entityid) && !rst->rtps_encoded) if (q_omg_security_is_remote_rtps_protected(proxypp, e->guid.entityid) && !rst->rtps_encoded)
{ {
return 0; return false;
} }
return true; return true;
@ -1182,6 +1307,9 @@ secure_conn_write(
#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_security_omg.h"
extern inline bool q_omg_participant_is_secure(UNUSED_ARG(const struct participant *pp));
extern inline bool q_omg_proxy_participant_is_secure(const struct proxy_participant *proxypp);
extern inline bool q_omg_security_enabled(void); extern inline bool q_omg_security_enabled(void);
extern inline bool q_omg_participant_is_secure( extern inline bool q_omg_participant_is_secure(
@ -1190,6 +1318,12 @@ extern inline bool q_omg_participant_is_secure(
extern inline unsigned determine_subscription_writer( extern inline unsigned determine_subscription_writer(
UNUSED_ARG(const struct reader *rd)); UNUSED_ARG(const struct reader *rd));
extern inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr));
extern inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd));
extern inline bool q_omg_security_check_remote_writer_permissions(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp));
extern inline bool q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *par));
extern inline unsigned determine_publication_writer( extern inline unsigned determine_publication_writer(
UNUSED_ARG(const struct writer *wr)); UNUSED_ARG(const struct writer *wr));
@ -1198,6 +1332,24 @@ extern inline bool is_proxy_participant_deletion_allowed(
UNUSED_ARG(const struct ddsi_guid *guid), UNUSED_ARG(const struct ddsi_guid *guid),
UNUSED_ARG(const ddsi_entityid_t pwr_entityid)); UNUSED_ARG(const ddsi_entityid_t pwr_entityid));
extern inline bool q_omg_is_similar_participant_security_info(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp));
extern inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct participant *pp));
extern inline bool q_omg_security_check_create_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id));
/* initialize the proxy participant security attributes */
extern inline void q_omg_security_init_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp));
/* ask to access control security plugin for the remote participant permissions */
extern inline int64_t q_omg_security_check_remote_participant_permissions(UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp));
extern inline void q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t shared_secret), UNUSED_ARG(int64_t proxy_permissions));
extern inline void q_omg_security_deregister_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp));
extern inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp));
extern inline void set_proxy_participant_security_info( extern inline void set_proxy_participant_security_info(
UNUSED_ARG(struct proxy_participant *prd), UNUSED_ARG(struct proxy_participant *prd),
UNUSED_ARG(const nn_plist_t *plist)); UNUSED_ARG(const nn_plist_t *plist));

View file

@ -105,10 +105,19 @@ static const unsigned prismtech_builtin_writers_besmask =
NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER |
NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER; NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, 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_cbarg); static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, 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_cbarg);
static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, 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_cbarg); static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, 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_cbarg);
static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
static struct entity_common *entity_common_from_proxy_endpoint_common (const struct proxy_endpoint_common *c);
#ifdef DDSI_INCLUDE_SECURITY
static const unsigned BES_MASK_NON_SECURITY = 0xf000ffff;
static void handshake_end_cb(struct q_globals const * const gv, struct ddsi_handshake *handshake, const struct ddsi_guid *lpguid, const struct ddsi_guid *ppguid, enum ddsi_handshake_state result);
static void downgrade_to_nonsecure(struct proxy_participant *proxypp);
#endif
static int gcreq_participant (struct participant *pp); static int gcreq_participant (struct participant *pp);
static int gcreq_writer (struct writer *wr); static int gcreq_writer (struct writer *wr);
@ -201,6 +210,22 @@ int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid)
return is_builtin_entityid (id, vendorid) && id.u != NN_ENTITYID_PARTICIPANT; return is_builtin_entityid (id, vendorid) && id.u != NN_ENTITYID_PARTICIPANT;
} }
#ifdef DDSI_INCLUDE_SECURITY
static int is_builtin_volatile_endpoint (ddsi_entityid_t id)
{
switch (id.u) {
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER:
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER:
return 1;
default:
break;
}
return 0;
}
#endif
bool is_local_orphan_endpoint (const struct entity_common *e) bool is_local_orphan_endpoint (const struct entity_common *e)
{ {
return (e->guid.prefix.u[0] == 0 && e->guid.prefix.u[1] == 0 && e->guid.prefix.u[2] == 0 && return (e->guid.prefix.u[0] == 0 && e->guid.prefix.u[1] == 0 && e->guid.prefix.u[2] == 0 &&
@ -570,6 +595,47 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t *
} }
#endif #endif
#ifdef DDSI_INCLUDE_SECURITY
static void connect_participant_secure(struct q_globals *gv, struct participant *pp)
{
struct proxy_participant *proxypp;
struct entidx_enum_proxy_participant it;
if (q_omg_participant_is_secure(pp))
{
entidx_enum_proxy_participant_init (&it, gv->entity_index);
while ((proxypp = entidx_enum_proxy_participant_next (&it)) != NULL)
{
/* Do not start handshaking when security info doesn't match. */
if (q_omg_is_similar_participant_security_info(pp, proxypp))
{
ddsi_handshake_register(pp, proxypp, handshake_end_cb);
}
}
entidx_enum_proxy_participant_fini (&it);
}
}
static void disconnect_participant_secure(struct participant *pp)
{
struct proxy_participant *proxypp;
struct entidx_enum_proxy_participant it;
struct q_globals * const gv = pp->e.gv;
if (q_omg_participant_is_secure(pp))
{
entidx_enum_proxy_participant_init (&it, gv->entity_index);
while ((proxypp = entidx_enum_proxy_participant_next (&it)) != NULL)
{
ddsi_handshake_remove(pp, proxypp, NULL);
}
entidx_enum_proxy_participant_fini (&it);
}
}
#endif
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist) dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
{ {
struct participant *pp; struct participant *pp;
@ -660,6 +726,16 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
goto new_pp_err_secprop; goto new_pp_err_secprop;
} }
} }
if (nn_xqos_has_prop (&pp->plist->qos, "dds.sec.", true))
{
if (!q_omg_security_check_create_participant (pp, gv->config.domainId))
{
ret = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
goto not_allowed;
}
}
#endif #endif
if (gv->logconfig.c.mask & DDS_LC_DISCOVERY) if (gv->logconfig.c.mask & DDS_LC_DISCOVERY)
@ -856,9 +932,18 @@ 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);
} }
#ifdef DDSI_INCLUDE_SECURITY
if (q_omg_participant_is_secure(pp))
{
connect_participant_secure (gv, pp);
}
#endif
return ret; return ret;
#ifdef DDSI_INCLUDE_SECURITY #ifdef DDSI_INCLUDE_SECURITY
not_allowed:
new_pp_err_secprop: new_pp_err_secprop:
nn_plist_fini (pp->plist); nn_plist_fini (pp->plist);
ddsrt_free (pp->plist); ddsrt_free (pp->plist);
@ -1099,6 +1184,9 @@ dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *p
return DDS_RETCODE_BAD_PARAMETER; return DDS_RETCODE_BAD_PARAMETER;
builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), false); builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), false);
remember_deleted_participant_guid (gv->deleted_participants, &pp->e.guid); remember_deleted_participant_guid (gv->deleted_participants, &pp->e.guid);
#ifdef DDSI_INCLUDE_SECURITY
disconnect_participant_secure (pp);
#endif
entidx_remove_participant_guid (gv->entity_index, pp); entidx_remove_participant_guid (gv->entity_index, pp);
gcreq_participant (pp); gcreq_participant (pp);
return 0; return 0;
@ -2449,6 +2537,31 @@ static bool topickind_qos_match_p_lock (struct entity_common *rd, const dds_qos_
return ret; return ret;
} }
void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow)
{
DDSRT_UNUSED_ARG(tnow);
proxy_reader_add_connection (prd, wr);
writer_add_connection (wr, prd);
}
void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow)
{
nn_count_t init_count;
struct proxy_writer_alive_state alive_state;
/* Initialize the reader's tracking information for the writer liveliness state to something
sensible, but that may be outdated by the time the reader gets added to the writer's list
of matching readers. */
proxy_writer_get_alive_state (pwr, &alive_state);
reader_add_connection (rd, pwr, &init_count, &alive_state);
proxy_writer_add_connection (pwr, rd, tnow, init_count);
/* Once everything is set up: update with the latest state, any updates to the alive state
happening in parallel will cause this to become a no-op. */
proxy_writer_get_alive_state (pwr, &alive_state);
reader_update_notify_pwr_alive_state (rd, pwr, &alive_state);
}
static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow) static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow)
{ {
const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0);
@ -2464,8 +2577,22 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re
writer_qos_mismatch (wr, reason); writer_qos_mismatch (wr, reason);
return; return;
} }
proxy_reader_add_connection (prd, wr);
writer_add_connection (wr, prd); if (!q_omg_security_check_remote_reader_permissions (prd, wr->e.gv->config.domainId, wr->c.pp))
{
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));
}
else if (!q_omg_security_match_remote_reader_enabled (wr, prd))
{
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));
}
else
{
proxy_reader_add_connection (prd, wr);
writer_add_connection (wr, prd);
}
} }
static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct reader *rd, nn_mtime_t tnow) static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct reader *rd, nn_mtime_t tnow)
@ -2485,17 +2612,30 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
return; return;
} }
/* Initialze the reader's tracking information for the writer liveliness state to something if (!q_omg_security_check_remote_writer_permissions(pwr, rd->e.gv->config.domainId, rd->c.pp))
sensible, but that may be outdated by the time the reader gets added to the writer's list {
of matching readers. */ EELOGDISC (&rd->e, "connect_proxy_writer_with_reader (pwr "PGUIDFMT") with (rd "PGUIDFMT") not allowed by security\n",
proxy_writer_get_alive_state (pwr, &alive_state); PGUID (pwr->e.guid), PGUID (rd->e.guid));
reader_add_connection (rd, pwr, &init_count, &alive_state); }
proxy_writer_add_connection (pwr, rd, tnow, init_count); else if (!q_omg_security_match_remote_writer_enabled(rd, pwr))
{
EELOGDISC (&rd->e, "connect_proxy_writer_with_reader (pwr "PGUIDFMT") with (rd "PGUIDFMT") waiting for approval by security\n",
PGUID (pwr->e.guid), PGUID (rd->e.guid));
}
else
{
/* Initialize the reader's tracking information for the writer liveliness state to something
sensible, but that may be outdated by the time the reader gets added to the writer's list
of matching readers. */
proxy_writer_get_alive_state (pwr, &alive_state);
reader_add_connection (rd, pwr, &init_count, &alive_state);
proxy_writer_add_connection (pwr, rd, tnow, init_count);
/* Once everything is set up: update with the latest state, any updates to the alive state /* Once everything is set up: update with the latest state, any updates to the alive state
happening in parallel will cause this to become a no-op. */ happening in parallel will cause this to become a no-op. */
proxy_writer_get_alive_state (pwr, &alive_state); proxy_writer_get_alive_state (pwr, &alive_state);
reader_update_notify_pwr_alive_state (rd, pwr, &alive_state); reader_update_notify_pwr_alive_state (rd, pwr, &alive_state);
}
} }
static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2) static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
@ -2733,6 +2873,126 @@ static void match_proxy_reader_with_writers (struct proxy_reader *prd, nn_mtime_
generic_do_match(&prd->e, tnow, false); generic_do_match(&prd->e, tnow, false);
} }
#ifdef DDSI_INCLUDE_SECURITY
static void match_volatile_secure_endpoints (struct participant *pp, struct proxy_participant *proxypp)
{
struct reader *rd;
struct writer *wr;
struct proxy_reader *prd;
struct proxy_writer *pwr;
ddsi_guid_t guid;
nn_mtime_t tnow = now_mt ();
EELOGDISC (&pp->e, "match volatile endpoints (pp "PGUIDFMT") with (proxypp "PGUIDFMT")\n",
PGUID(pp->e.guid), PGUID(proxypp->e.guid));
guid = pp->e.guid;
guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER;
rd = entidx_lookup_reader_guid (pp->e.gv->entity_index, &guid);
assert(rd);
guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER;
wr = entidx_lookup_writer_guid (pp->e.gv->entity_index, &guid);
assert(wr);
guid = proxypp->e.guid;
guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER;
prd = entidx_lookup_proxy_reader_guid (pp->e.gv->entity_index, &guid);
assert(rd);
guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER;
pwr = entidx_lookup_proxy_writer_guid (pp->e.gv->entity_index, &guid);
assert(wr);
connect_proxy_writer_with_reader_wrapper(&pwr->e, &rd->e, tnow);
connect_writer_with_proxy_reader_wrapper(&wr->e, &prd->e, tnow);
}
static struct entity_common * get_entity_parent(struct entity_common *e)
{
switch (e->kind)
{
case EK_WRITER:
return &((struct writer *)e)->c.pp->e;
case EK_READER:
return &((struct reader *)e)->c.pp->e;
case EK_PROXY_WRITER:
return &((struct proxy_writer *)e)->c.proxypp->e;
case EK_PROXY_READER:
return &((struct proxy_reader *)e)->c.proxypp->e;
case EK_PARTICIPANT:
case EK_PROXY_PARTICIPANT:
return NULL;
}
return NULL;
}
static void update_proxy_participant_endpoint_matching (struct proxy_participant *proxypp, struct participant *pp)
{
struct entity_index * const entidx = pp->e.gv->entity_index;
struct proxy_endpoint_common *cep;
ddsi_guid_t guid;
ddsi_entityid_t *endpoint_ids;
uint32_t num = 0, i;
nn_mtime_t tnow = now_mt ();
EELOGDISC (&proxypp->e, "update_proxy_participant_endpoint_matching (proxypp "PGUIDFMT" pp "PGUIDFMT")\n",
PGUID (proxypp->e.guid), PGUID (pp->e.guid));
ddsrt_mutex_lock(&proxypp->e.lock);
endpoint_ids = ddsrt_malloc(proxypp->refc * sizeof(ddsi_entityid_t));
for (cep = proxypp->endpoints; cep != NULL; cep = cep->next_ep)
{
struct entity_common *e = entity_common_from_proxy_endpoint_common (cep);
endpoint_ids[num++] = e->guid.entityid;
}
ddsrt_mutex_unlock(&proxypp->e.lock);
guid.prefix = proxypp->e.guid.prefix;
for (i = 0; i < num; i++)
{
struct entity_common *e;
enum entity_kind mkind;
guid.entityid = endpoint_ids[i];
if ((e = entidx_lookup_guid_untyped(proxypp->e.gv->entity_index, &guid)) == NULL)
continue;
mkind = generic_do_match_mkind (e->kind, false);
if (!is_builtin_entityid (e->guid.entityid, NN_VENDORID_ECLIPSE))
{
struct entidx_enum it;
struct entity_common *em;
struct match_entities_range_key max;
const char *tp = entity_topic_name (e);
entidx_enum_init_topic_w_prefix (&it, entidx, mkind, tp, &pp->e.guid.prefix, &max);
while ((em = entidx_enum_next_max (&it, &max)) != NULL)
{
if (&pp->e == get_entity_parent(e))
generic_do_match_connect (e, em, tnow, false);
}
entidx_enum_fini (&it);
}
else
{
const ddsi_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid);
const ddsi_guid_t tgt_guid = { pp->e.guid.prefix, tgt_ent };
if (!is_builtin_volatile_endpoint (tgt_ent))
{
struct entity_common *ep;
if ((ep = entidx_lookup_guid (entidx, &tgt_guid, mkind)) != NULL)
generic_do_match_connect (e, ep, tnow, false);
}
}
}
ddsrt_free(endpoint_ids);
}
#endif
/* ENDPOINT --------------------------------------------------------- */ /* ENDPOINT --------------------------------------------------------- */
static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct ddsi_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos) static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct ddsi_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos)
@ -4048,7 +4308,7 @@ static void add_proxy_builtin_endpoints(
/* Register lease for auto liveliness, but be careful not to accidentally re-register /* Register lease for auto liveliness, but be careful not to accidentally re-register
DDSI2's lease, as we may have become dependent on DDSI2 any time after DDSI2's lease, as we may have become dependent on DDSI2 any time after
ephash_insert_proxy_participant_guid even if privileged_pp_guid was NULL originally */ entidx_insert_proxy_participant_guid even if privileged_pp_guid was NULL originally */
ddsrt_mutex_lock (&proxypp->e.lock); ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->owns_lease) if (proxypp->owns_lease)
@ -4124,6 +4384,142 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant
} }
} }
#ifdef DDSI_INCLUDE_SECURITY
void handshake_end_cb
(
struct q_globals const * const gv,
struct ddsi_handshake *handshake,
const struct ddsi_guid *lpguid,
const struct ddsi_guid *ppguid,
enum ddsi_handshake_state result)
{
struct proxy_participant *proxypp;
struct participant *pp;
int64_t shared_secret;
int64_t permissions_hdl;
assert(handshake);
assert(lpguid);
assert(ppguid);
assert(gv);
proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid);
if (!proxypp)
return;
pp = entidx_lookup_participant_guid (gv->entity_index, lpguid);
if (!pp)
return;
switch(result)
{
case STATE_HANDSHAKE_PROCESSED:
shared_secret = ddsi_handshake_get_shared_secret(handshake);
DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") processed\n", PGUID (*lpguid), PGUID (*ppguid));
permissions_hdl = q_omg_security_check_remote_participant_permissions(gv->config.domainId, pp, proxypp);
if (permissions_hdl != 0) {
q_omg_security_register_remote_participant(pp, proxypp, shared_secret, permissions_hdl);
match_volatile_secure_endpoints(pp, proxypp);
}
break;
case STATE_HANDSHAKE_SEND_TOKENS:
DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") send tokens\n", PGUID (*lpguid), PGUID (*ppguid));
q_omg_security_participant_send_tokens(pp, proxypp);
break;
case STATE_HANDSHAKE_OK:
DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") succeeded\n", PGUID (*lpguid), PGUID (*ppguid));
update_proxy_participant_endpoint_matching(proxypp, pp);
ddsi_handshake_remove(pp, proxypp, handshake);
break;
case STATE_HANDSHAKE_TIMED_OUT:
DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Timed out\n", PGUID (*lpguid), PGUID (*ppguid), (int)result);
if (q_omg_participant_allow_unauthenticated(pp)) {
downgrade_to_nonsecure(proxypp);
update_proxy_participant_endpoint_matching(proxypp, pp);
}
ddsi_handshake_remove(pp, proxypp, handshake);
break;
case STATE_HANDSHAKE_FAILED:
DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Failed\n", PGUID (*lpguid), PGUID (*ppguid), (int)result);
if (q_omg_participant_allow_unauthenticated(pp)) {
downgrade_to_nonsecure(proxypp);
update_proxy_participant_endpoint_matching(proxypp, pp);
}
ddsi_handshake_remove(pp, proxypp, handshake);
break;
default:
DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Unknown failure\n", PGUID (*lpguid), PGUID (*ppguid), (int)result);
ddsi_handshake_remove(pp, proxypp, handshake);
break;
}
}
static int proxy_participant_check_security_info(struct q_globals *gv, struct proxy_participant *proxypp)
{
int r = 0;
struct participant *pp;
struct entidx_enum_participant est;
entidx_enum_participant_init (&est, gv->entity_index);
while (((pp = entidx_enum_participant_next (&est)) != NULL) && (r == 0)) {
if (q_omg_is_similar_participant_security_info(pp, proxypp)) {
r = 1;
break;
}
}
entidx_enum_participant_fini(&est);
return r;
}
static void proxy_participant_create_handshakes(struct q_globals *gv, struct proxy_participant *proxypp)
{
struct participant *pp;
struct entidx_enum_participant est;
entidx_enum_participant_init (&est, gv->entity_index);
while (((pp = entidx_enum_participant_next (&est)) != NULL)) {
if (q_omg_participant_is_secure(pp))
{
ddsi_handshake_register(pp, proxypp, handshake_end_cb);
}
}
entidx_enum_participant_fini(&est);
}
#endif
#ifdef DDSI_INCLUDE_SECURITY
static void free_proxy_participant(struct proxy_participant *proxypp)
{
q_omg_security_deregister_remote_participant(proxypp);
unref_addrset (proxypp->as_default);
unref_addrset (proxypp->as_meta);
nn_plist_fini (proxypp->plist);
ddsrt_free (proxypp->plist);
if (proxypp->owns_lease)
{
struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto);
ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL);
assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid));
lease_unregister (minl_auto);
lease_free (minl_auto);
lease_free (proxypp->lease);
}
entity_common_fini (&proxypp->e);
ddsrt_free (proxypp);
}
#endif
void new_proxy_participant void new_proxy_participant
( (
struct q_globals *gv, struct q_globals *gv,
@ -4145,6 +4541,9 @@ void new_proxy_participant
runs on a single thread, it can't go wrong. FIXME, maybe? The runs on a single thread, it can't go wrong. FIXME, maybe? The
same holds for the other functions for creating entities. */ same holds for the other functions for creating entities. */
struct proxy_participant *proxypp; struct proxy_participant *proxypp;
#ifdef DDSI_INCLUDE_SECURITY
bool secure = false;
#endif
assert (ppguid->entityid.u == NN_ENTITYID_PARTICIPANT); assert (ppguid->entityid.u == NN_ENTITYID_PARTICIPANT);
assert (entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid) == NULL); assert (entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid) == NULL);
@ -4229,7 +4628,17 @@ void new_proxy_participant
nn_xqos_mergein_missing (&proxypp->plist->qos, &gv->default_plist_pp.qos, ~(uint64_t)0); nn_xqos_mergein_missing (&proxypp->plist->qos, &gv->default_plist_pp.qos, ~(uint64_t)0);
ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups); ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups);
#ifdef DDSI_INCLUDE_SECURITY
proxypp->remote_identity_handle = 0;
proxypp->sec_attr = NULL;
secure = ((bes & NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER) != 0);
if (!secure)
{
/* Make sure we don't create any security builtin endpoint when it's considered unsecure. */
proxypp->bes &= BES_MASK_NON_SECURITY;
}
set_proxy_participant_security_info(proxypp, plist); set_proxy_participant_security_info(proxypp, plist);
#endif
if (custom_flags & CF_INC_KERNEL_SEQUENCE_NUMBERS) if (custom_flags & CF_INC_KERNEL_SEQUENCE_NUMBERS)
proxypp->kernel_sequence_numbers = 1; proxypp->kernel_sequence_numbers = 1;
@ -4253,12 +4662,52 @@ void new_proxy_participant
else else
proxypp->proxypp_have_cm = 0; proxypp->proxypp_have_cm = 0;
/* Proxy participant must be in the hash tables for #ifdef DDSI_INCLUDE_SECURITY
new_proxy_{writer,reader} to work */ if (secure)
entidx_insert_proxy_participant_guid (gv->entity_index, proxypp); {
/* Secure participant detected: start handshake. */
if ((plist->present & PP_IDENTITY_TOKEN))
{
/* initialize the security attributes associated with the proxy participant */
q_omg_security_init_remote_participant(proxypp);
/* TODO: Do security checks on the proxy participant. Either add the endpoints or delete the proxy. */ /* check if the proxy participant has a match with a local participant */
if (proxy_participant_check_security_info(gv, proxypp))
{
/* Proxy participant must be in the hash tables for new_proxy_{writer,reader} to work */
entidx_insert_proxy_participant_guid (gv->entity_index, proxypp);
/* Create builtin endpoints, of which a few are used in the handshake. */
add_proxy_builtin_endpoints(gv, ppguid, proxypp, timestamp);
/* create authentication handshakes for each local secure participant */
proxy_participant_create_handshakes(gv, proxypp);
}
else
{
DDS_CWARNING(&gv->logconfig, "Remote secure participant "PGUIDFMT" not allowed\n", PGUID (*ppguid));
free_proxy_participant(proxypp);
}
}
else
{
/* Do not communicate with un-secure participants. */
DDS_CWARNING(&gv->logconfig, "Don't communicate with secure participant "PGUIDFMT" which does not provide an identity token\n", PGUID (*ppguid));
free_proxy_participant(proxypp);
}
}
else
{
/* Remote is un-secure. Try the discovery anyway. Maybe there's a local secure
* participant that allowed communication with remote non-secure ones
*/
entidx_insert_proxy_participant_guid (gv->entity_index, proxypp);
add_proxy_builtin_endpoints(gv, ppguid, proxypp, timestamp);
DDS_CLOG (DDS_LC_INFO, &gv->logconfig, "Un-secure participant "PGUIDFMT" tries to connect.\n", PGUID (*ppguid));
}
#else
/* Proxy participant must be in the hash tables for new_proxy_{writer,reader} to work */
entidx_insert_proxy_participant_guid (gv->entity_index, proxypp);
add_proxy_builtin_endpoints(gv, ppguid, proxypp, timestamp); add_proxy_builtin_endpoints(gv, ppguid, proxypp, timestamp);
#endif
} }
int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp) int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct nn_plist *datap, enum update_proxy_participant_source source, nn_wctime_t timestamp)
@ -4356,6 +4805,10 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
} }
ddsrt_mutex_unlock (&proxypp->e.lock); ddsrt_mutex_unlock (&proxypp->e.lock);
ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid)); ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid));
#ifdef DDSI_INCLUDE_SECURITY
q_omg_security_deregister_remote_participant(proxypp);
#endif
unref_addrset (proxypp->as_default); unref_addrset (proxypp->as_default);
unref_addrset (proxypp->as_meta); unref_addrset (proxypp->as_meta);
nn_plist_fini (proxypp->plist); nn_plist_fini (proxypp->plist);
@ -4478,6 +4931,61 @@ static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp
gcreq_proxy_participant (proxypp); gcreq_proxy_participant (proxypp);
} }
#ifdef DDSI_INCLUDE_SECURITY
struct setab {
enum entity_kind kind;
uint32_t id;
};
static void downgrade_to_nonsecure(struct proxy_participant *proxypp)
{
const nn_wctime_t tnow = now();
struct ddsi_guid guid;
static const struct setab setab[] = {
{EK_PROXY_WRITER, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER},
{EK_PROXY_WRITER, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER},
{EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER},
{EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER},
{EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER},
{EK_PROXY_WRITER, NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER},
{EK_PROXY_READER, NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER}
};
int i;
DDS_CWARNING (&proxypp->e.gv->logconfig, "downgrade participant "PGUIDFMT" to non-secure\n", PGUID (proxypp->e.guid));
guid.prefix = proxypp->e.guid.prefix;
/* Remove security related endpoints. */
for (i = 0; i < (int)(sizeof(setab)/sizeof(*setab)); i++)
{
guid.entityid.u = setab[i].id;
switch (setab[i].kind)
{
case EK_PROXY_READER:
(void)delete_proxy_reader (proxypp->e.gv, &guid, tnow, 0);
break;
case EK_PROXY_WRITER:
(void)delete_proxy_writer (proxypp->e.gv, &guid, tnow, 0);
break;
default:
assert(0);
}
}
/* Cleanup all kinds of related security information. */
q_omg_security_deregister_remote_participant(proxypp);
proxypp->bes &= BES_MASK_NON_SECURITY;
}
#endif
typedef struct proxy_purge_data { typedef struct proxy_purge_data {
struct proxy_participant *proxypp; struct proxy_participant *proxypp;
const nn_locator_t *loc; const nn_locator_t *loc;