From 4e4d49a0d6ed178765f3c31d1307e819a3956ab8 Mon Sep 17 00:00:00 2001 From: Pablo Garrido Date: Tue, 26 Nov 2019 15:09:20 +0100 Subject: [PATCH 1/2] Removed security directory --- rcl/CMakeLists.txt | 1 - rcl/include/rcl/security_directory.h | 67 ------- rcl/src/rcl/node.c | 2 +- rcl/src/rcl/security_directory.c | 264 --------------------------- 4 files changed, 1 insertion(+), 333 deletions(-) delete mode 100644 rcl/include/rcl/security_directory.h delete mode 100644 rcl/src/rcl/security_directory.c diff --git a/rcl/CMakeLists.txt b/rcl/CMakeLists.txt index c9779c41b..10649ba08 100644 --- a/rcl/CMakeLists.txt +++ b/rcl/CMakeLists.txt @@ -56,7 +56,6 @@ set(${PROJECT_NAME}_sources src/rcl/timer.c src/rcl/validate_topic_name.c src/rcl/wait.c - src/rcl/security_directory.c ) add_library(${PROJECT_NAME} ${${PROJECT_NAME}_sources}) diff --git a/rcl/include/rcl/security_directory.h b/rcl/include/rcl/security_directory.h deleted file mode 100644 index e3d8b52f7..000000000 --- a/rcl/include/rcl/security_directory.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef RCL__SECURITY_DIRECTORY_H_ -#define RCL__SECURITY_DIRECTORY_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "rcl/allocator.h" -#include "rcl/visibility_control.h" - -#ifndef ROS_SECURITY_NODE_DIRECTORY_VAR_NAME - #define ROS_SECURITY_NODE_DIRECTORY_VAR_NAME "ROS_SECURITY_NODE_DIRECTORY" -#endif - -#ifndef ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME - #define ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME "ROS_SECURITY_ROOT_DIRECTORY" -#endif - -#ifndef ROS_SECURITY_LOOKUP_TYPE_VAR_NAME - #define ROS_SECURITY_LOOKUP_TYPE_VAR_NAME "ROS_SECURITY_LOOKUP_TYPE" -#endif - -/// Return the secure root directory associated with a node given its validated name and namespace. -/** - * E.g. for a node named "c" in namespace "/a/b", the secure root path will be - * "a/b/c", where the delimiter "/" is native for target file system (e.g. "\\" for _WIN32). - * If no exact match is found for the node name, a best match would be used instead - * (by performing longest-prefix matching). - * - * However, this expansion can be overridden by setting the secure node directory environment - * variable, allowing users to explicitly specify the exact secure root directory to be utilized. - * Such an override is useful for where the FQN of a node is non-deterministic before runtime, - * or when testing and using additional tools that may not otherwise be easily provisioned. - * - * \param[in] node_name validated node name (a single token) - * \param[in] node_namespace validated, absolute namespace (starting with "/") - * \param[in] allocator the allocator to use for allocation - * \returns machine specific (absolute) node secure root path or NULL on failure - * returned pointer must be deallocated by the caller of this function - */ -RCL_PUBLIC -char * rcl_get_secure_root( - const char * node_name, - const char * node_namespace, - const rcl_allocator_t * allocator -); - -#ifdef __cplusplus -} -#endif - -#endif // RCL__SECURITY_DIRECTORY_H_ diff --git a/rcl/src/rcl/node.c b/rcl/src/rcl/node.c index 2a31abe33..443a076d5 100644 --- a/rcl/src/rcl/node.c +++ b/rcl/src/rcl/node.c @@ -29,7 +29,7 @@ extern "C" #include "rcl/logging_rosout.h" #include "rcl/rcl.h" #include "rcl/remap.h" -#include "rcl/security_directory.h" +#include "rcutils/security_directory.h" #include "rcutils/filesystem.h" #include "rcutils/find.h" #include "rcutils/format_string.h" diff --git a/rcl/src/rcl/security_directory.c b/rcl/src/rcl/security_directory.c deleted file mode 100644 index 6e7d9f54e..000000000 --- a/rcl/src/rcl/security_directory.c +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2018 Open Source Robotics Foundation, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "rcl/security_directory.h" - -#include "rcl/error_handling.h" -#include "rcutils/filesystem.h" -#include "rcutils/get_env.h" -#include "rcutils/format_string.h" - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wembedded-directive" -#endif -#include "tinydir/tinydir.h" -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -/** - * A security lookup function takes in the node's name, namespace, a security root directory and an allocator; - * It returns the relevant information required to load the security credentials, - * which is currently a path to a directory on the filesystem containing DDS Security permission files. - */ -typedef char * (* security_lookup_fn_t) ( - const char * node_name, - const char * node_namespace, - const char * ros_secure_root_env, - const rcl_allocator_t * allocator -); - -char * exact_match_lookup( - const char * node_name, - const char * node_namespace, - const char * ros_secure_root_env, - const rcl_allocator_t * allocator -); - -char * prefix_match_lookup( - const char * node_name, - const char * node_namespace, - const char * ros_secure_root_env, - const rcl_allocator_t * allocator -); - -security_lookup_fn_t g_security_lookup_fns[] = { - NULL, - exact_match_lookup, - prefix_match_lookup, -}; - -typedef enum ros_security_lookup_type_e -{ - ROS_SECURITY_LOOKUP_NODE_OVERRIDE = 0, - ROS_SECURITY_LOOKUP_MATCH_EXACT = 1, - ROS_SECURITY_LOOKUP_MATCH_PREFIX = 2, -} ros_security_lookup_type_t; - -char * g_security_lookup_type_strings[] = { - "NODE_OVERRIDE", - "MATCH_EXACT", - "MATCH_PREFIX" -}; - -/// Return the directory whose name most closely matches node_name (longest-prefix match), -/// scanning under base_dir. -/** - * By using a prefix match, a node named e.g. "my_node_123" will be able to load and use the - * directory "my_node" if no better match exists. - * \param[in] base_dir - * \param[in] node_name - * \param[out] matched_name must be a valid memory address allocated with at least - * _TINYDIR_FILENAME_MAX characters. - * \return true if a match was found - */ -static bool get_best_matching_directory( - const char * base_dir, - const char * node_name, - char * matched_name) -{ - size_t max_match_length = 0; - tinydir_dir dir; - if (NULL == base_dir || NULL == node_name || NULL == matched_name) { - return false; - } - if (-1 == tinydir_open(&dir, base_dir)) { - return false; - } - while (dir.has_next) { - tinydir_file file; - if (-1 == tinydir_readfile(&dir, &file)) { - goto cleanup; - } - if (file.is_dir) { - size_t matched_name_length = strnlen(file.name, sizeof(file.name) - 1); - if (0 == - strncmp(file.name, node_name, - matched_name_length) && matched_name_length > max_match_length) - { - max_match_length = matched_name_length; - memcpy(matched_name, file.name, max_match_length); - } - } - if (-1 == tinydir_next(&dir)) { - goto cleanup; - } - } -cleanup: - tinydir_close(&dir); - return max_match_length > 0; -} - -char * exact_match_lookup( - const char * node_name, - const char * node_namespace, - const char * ros_secure_root_env, - const rcl_allocator_t * allocator) -{ - // Perform an exact match for the node's name in directory /. - char * node_secure_root = NULL; - // "/" case when root namespace is explicitly passed in - if (1 == strlen(node_namespace)) { - node_secure_root = rcutils_join_path(ros_secure_root_env, node_name, *allocator); - } else { - char * node_fqn = NULL; - char * node_root_path = NULL; - // Combine node namespace with node name - // TODO(ros2team): remove the hard-coded value of the root namespace - node_fqn = rcutils_format_string(*allocator, "%s%s%s", node_namespace, "/", node_name); - // Get native path, ignore the leading forward slash - // TODO(ros2team): remove the hard-coded length, use the length of the root namespace instead - node_root_path = rcutils_to_native_path(node_fqn + 1, *allocator); - node_secure_root = rcutils_join_path(ros_secure_root_env, node_root_path, *allocator); - allocator->deallocate(node_fqn, allocator->state); - allocator->deallocate(node_root_path, allocator->state); - } - return node_secure_root; -} - -char * prefix_match_lookup( - const char * node_name, - const char * node_namespace, - const char * ros_secure_root_env, - const rcl_allocator_t * allocator) -{ - // Perform longest prefix match for the node's name in directory /. - char * node_secure_root = NULL; - char matched_dir[_TINYDIR_FILENAME_MAX] = {0}; - char * base_lookup_dir = NULL; - if (strlen(node_namespace) == 1) { - base_lookup_dir = (char *) ros_secure_root_env; - } else { - // TODO(ros2team): remove the hard-coded length, use the length of the root namespace instead. - base_lookup_dir = rcutils_join_path(ros_secure_root_env, node_namespace + 1, *allocator); - } - if (get_best_matching_directory(base_lookup_dir, node_name, matched_dir)) { - node_secure_root = rcutils_join_path(base_lookup_dir, matched_dir, *allocator); - } - if (base_lookup_dir != ros_secure_root_env && NULL != base_lookup_dir) { - allocator->deallocate(base_lookup_dir, allocator->state); - } - return node_secure_root; -} - -char * rcl_get_secure_root( - const char * node_name, - const char * node_namespace, - const rcl_allocator_t * allocator) -{ - bool ros_secure_node_override = true; - - // find out if either of the configuration environment variables are set - const char * env_buf = NULL; - if (NULL == node_name) { - return NULL; - } - if (rcutils_get_env(ROS_SECURITY_NODE_DIRECTORY_VAR_NAME, &env_buf)) { - return NULL; - } - if (!env_buf) { - return NULL; - } - size_t ros_secure_root_size = strlen(env_buf); - if (!ros_secure_root_size) { - // check root directory if node directory environment variable is empty - if (rcutils_get_env(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME, &env_buf)) { - return NULL; - } - if (!env_buf) { - return NULL; - } - ros_secure_root_size = strlen(env_buf); - if (!ros_secure_root_size) { - return NULL; // environment variable was empty - } else { - ros_secure_node_override = false; - } - } - - // found a usable environment variable, copy into our memory before overwriting with next lookup - char * ros_secure_root_env = - (char *)allocator->allocate(ros_secure_root_size + 1, allocator->state); - memcpy(ros_secure_root_env, env_buf, ros_secure_root_size + 1); - // TODO(ros2team): This make an assumption on the value and length of the root namespace. - // This should likely come from another (rcl/rmw?) function for reuse. - // If the namespace is the root namespace ("/"), the secure root is just the node name. - - char * lookup_strategy = NULL; - char * node_secure_root = NULL; - if (ros_secure_node_override) { - node_secure_root = (char *)allocator->allocate(ros_secure_root_size + 1, allocator->state); - memcpy(node_secure_root, ros_secure_root_env, ros_secure_root_size + 1); - lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_NODE_OVERRIDE]; - - } else { - // Check which lookup method to use and invoke the relevant function. - const char * ros_security_lookup_type = NULL; - if (rcutils_get_env(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME, &ros_security_lookup_type)) { - allocator->deallocate(ros_secure_root_env, allocator->state); - return NULL; - } - if (0 == strcmp(ros_security_lookup_type, - g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_PREFIX])) - { - node_secure_root = g_security_lookup_fns[ROS_SECURITY_LOOKUP_MATCH_PREFIX] - (node_name, node_namespace, ros_secure_root_env, allocator); - lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_PREFIX]; - } else { /* Default is MATCH_EXACT */ - node_secure_root = g_security_lookup_fns[ROS_SECURITY_LOOKUP_MATCH_EXACT] - (node_name, node_namespace, ros_secure_root_env, allocator); - lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_EXACT]; - } - } - - if (NULL == node_secure_root || !rcutils_is_directory(node_secure_root)) { - // Check node_secure_root is not NULL before checking directory - if (NULL == node_secure_root) { - RCL_SET_ERROR_MSG_WITH_FORMAT_STRING( - "SECURITY ERROR: unable to find a folder matching the node name in %s%s." - "Lookup strategy: %s", - ros_secure_root_env, node_namespace, lookup_strategy); - } else { - RCL_SET_ERROR_MSG_WITH_FORMAT_STRING( - "SECURITY ERROR: directory %s does not exist. Lookup strategy: %s", - node_secure_root, lookup_strategy); - } - allocator->deallocate(ros_secure_root_env, allocator->state); - allocator->deallocate(node_secure_root, allocator->state); - return NULL; - } - allocator->deallocate(ros_secure_root_env, allocator->state); - return node_secure_root; -} From 6c404c84af367a1935556a06b20af6a7c2c53601 Mon Sep 17 00:00:00 2001 From: Pablo Garrido Date: Tue, 26 Nov 2019 16:08:01 +0100 Subject: [PATCH 2/2] Updated security directory --- rcl/CMakeLists.txt | 2 -- rcl/package.xml | 2 -- rcl/src/rcl/node.c | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/rcl/CMakeLists.txt b/rcl/CMakeLists.txt index 10649ba08..364d69eef 100644 --- a/rcl/CMakeLists.txt +++ b/rcl/CMakeLists.txt @@ -9,7 +9,6 @@ find_package(rcutils REQUIRED) find_package(rmw REQUIRED) find_package(rmw_implementation REQUIRED) find_package(rosidl_generator_c REQUIRED) -find_package(tinydir_vendor REQUIRED) include_directories(include) include(cmake/rcl_set_symbol_visibility_hidden.cmake) @@ -67,7 +66,6 @@ ament_target_dependencies(${PROJECT_NAME} "rcutils" "rosidl_generator_c" ${RCL_LOGGING_IMPL} - "tinydir_vendor" ) # Causes the visibility macros to use dllexport rather than dllimport, diff --git a/rcl/package.xml b/rcl/package.xml index 3fb04d7d8..aa86d5f75 100644 --- a/rcl/package.xml +++ b/rcl/package.xml @@ -16,12 +16,10 @@ rcl_interfaces rcutils rosidl_generator_c - tinydir_vendor rcl_interfaces rcutils rosidl_generator_c - tinydir_vendor rcl_interfaces ament_cmake diff --git a/rcl/src/rcl/node.c b/rcl/src/rcl/node.c index 443a076d5..7a0bf52ca 100644 --- a/rcl/src/rcl/node.c +++ b/rcl/src/rcl/node.c @@ -307,7 +307,7 @@ rcl_node_init( node_security_options.enforce_security = RMW_SECURITY_ENFORCEMENT_PERMISSIVE; } else { // if use_security // File discovery magic here - node_secure_root = rcl_get_secure_root(name, local_namespace_, allocator); + node_secure_root = rcutils_get_secure_root(name, local_namespace_, allocator); if (node_secure_root) { RCUTILS_LOG_INFO_NAMED(ROS_PACKAGE_NAME, "Found security directory: %s", node_secure_root); node_security_options.security_root_path = node_secure_root;