// Guide for list of supported commands.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea4-ctrl-socket"
+ "socket-name": "kea4-ctrl-socket"
},
// Addresses will be assigned with a lifetime of 4000 seconds.
// Location of the UNIX domain socket file the DHCPv4 server uses
// to receive control commands from the Kea Control Agent or the
// local server administrator.
- "socket-name": "/tmp/kea4-ctrl-socket",
+ "socket-name": "kea4-ctrl-socket",
// Control socket type used by the Kea DHCPv4 server. The 'unix'
// socket is currently the only supported type.
// Location of the UNIX domain socket file the DHCPv4
// server uses to receive control commands from the
// local server administrator.
- "socket-name": "/tmp/kea4-ctrl-socket"
+ "socket-name": "kea4-ctrl-socket"
},
{
// Control socket type used by the Kea DHCPv4 server.
"control-sockets": [
{
"socket-type": "unix",
- "socket-name": "/tmp/kea4-ctrl-socket",
+ "socket-name": "kea4-ctrl-socket",
"user-context": { "comment": "Indirect comment" }
},
{
// details.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea4-ctrl-socket"
+ "socket-name": "kea4-ctrl-socket"
},
// Hooks libraries that enable configuration backend are loaded.
// The Control Agent is used only to handle user commands.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea4-ctrl-socket"
+ "socket-name": "kea4-ctrl-socket"
},
// Multi-threading parameters.
// The Control Agent is used only to handle user commands.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea4-ctrl-socket"
+ "socket-name": "kea4-ctrl-socket"
},
// Multi-threading parameters.
// Guide for list of supported commands.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea6-ctrl-socket"
+ "socket-name": "kea6-ctrl-socket"
},
// Addresses will be assigned with preferred and valid lifetimes
// Location of the UNIX domain socket file the DHCPv6 server uses
// to receive control commands from the Kea Control Agent or the
// local server administrator.
- "socket-name": "/tmp/kea6-ctrl-socket",
+ "socket-name": "kea6-ctrl-socket",
// Control socket type used by the Kea DHCPv6 server. The 'unix'
// socket is currently the only supported type.
// Location of the UNIX domain socket file the DHCPv6
// server uses to receive control commands from the
// local server administrator.
- "socket-name": "/tmp/kea6-ctrl-socket"
+ "socket-name": "kea6-ctrl-socket"
},
{
// Control socket type used by the Kea DHCPv6 server.
"control-sockets": [
{
"socket-type": "unix",
- "socket-name": "/tmp/kea6-ctrl-socket",
+ "socket-name": "kea6-ctrl-socket",
"user-context": { "comment": "Indirect comment" }
},
{
// details.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea6-ctrl-socket"
+ "socket-name": "kea6-ctrl-socket"
},
// Hooks libraries that enable configuration backend are loaded.
// API between the HA peers.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea6-ctrl-socket"
+ "socket-name": "kea6-ctrl-socket"
},
// Use Memfile lease database backend to store leases in a CSV file.
// API between the HA peers.
"control-socket": {
"socket-type": "unix",
- "socket-name": "/tmp/kea6-ctrl-socket"
+ "socket-name": "kea6-ctrl-socket"
},
// Use Memfile lease database backend to store leases in a CSV file.
#include <testutils/test_to_element.h>
#include <util/chrono_time_utils.h>
#include <util/doubles.h>
+#include <util/filesystem.h>
#include <boost/scoped_ptr.hpp>
using namespace isc::dhcp::test;
using namespace isc::hooks;
using namespace isc::test;
+using namespace isc::util;
using namespace std;
namespace {
" \"control-sockets\": ["
" {"
" \"socket-type\": \"unix\","
- " \"socket-name\": \"/tmp/kea4-ctrl-socket\","
+ " \"socket-name\": \"kea4-ctrl-socket\","
" \"user-context\": { \"comment\": \"Indirect comment\" }"
" },"
" {"
resetConfiguration();
resetHooksPath();
+ resetSocketPath();
}
~Dhcp4ParserTest() {
static_cast<void>(remove(UNLOAD_MARKER_FILE));
resetHooksPath();
+ resetSocketPath();
};
/// @brief Sets the Hooks path from which hooks can be loaded.
HooksLibrariesParser::getHooksPath(true);
}
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the socket path.
+ void setSocketTestPath(const std::string explicit_path = "") {
+ UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+ }
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
+ }
+
// Checks if the result of DHCP server configuration has
// expected code (0 for success, other for failures).
// Also stores result in rcode_ and comment_.
// This test checks comments. Please keep it last.
TEST_F(Dhcp4ParserTest, comments) {
+ setSocketTestPath();
string config = PARSER_CONFIGS[6];
extractConfig(config);
ASSERT_TRUE(socket->get("socket-type"));
EXPECT_EQ("\"unix\"", socket->get("socket-type")->str());
ASSERT_TRUE(socket->get("socket-name"));
- EXPECT_EQ("\"/tmp/kea4-ctrl-socket\"", socket->get("socket-name")->str());
+ EXPECT_EQ("\"kea4-ctrl-socket\"", socket->get("socket-name")->str());
// Check UNIX control socket comment and user context.
ConstElementPtr ctx_socket = socket->get("user-context");
/// Sets socket path to its default value.
CtrlChannelDhcpv4SrvTest() : interfaces_("\"*\"") {
resetLogPath();
- const char* env = getenv("KEA_SOCKET_TEST_DIR");
- if (env) {
- socket_path_ = string(env) + "/kea4.sock";
- } else {
- socket_path_ = sandbox.join("/kea4.sock");
- }
+ setSocketTestPath();
reset();
IfaceMgr::instance().setTestMode(false);
IfaceMgr::instance().setDetectCallback(std::bind(&IfaceMgr::checkDetectIfaces,
/// @brief Destructor
~CtrlChannelDhcpv4SrvTest() {
resetLogPath();
+ resetSocketPath();
if (test_timer_) {
test_timer_->cancel();
getIOService()->stopAndPoll();
LogConfigParser::getLogPath(true);
}
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the socket path.
+ void setSocketTestPath(const std::string explicit_path = "") {
+ UnixCommandConfig::getSocketPath(true,
+ (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+ socket_path_ = path + "/kea4.sock";
+ }
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
+ }
+
+
/// @brief Returns pointer to the server's IO service.
///
/// @return Pointer to the server's IO service or null pointer if the server
void
Dhcpv4SrvTest::checkConfigFiles() {
+ setSocketTestPath();
#if defined (HAVE_MYSQL)
MySqlHostDataSourceInit mysql_init;
#endif
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <cc/command_interpreter.h>
+#include <config/unix_command_config.h>
#include <dhcp4/json_config_parser.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp/libdhcp++.h>
using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::util;
+using namespace isc::config;
using namespace boost::posix_time;
namespace isc {
}
Dhcpv4SrvTest::~Dhcpv4SrvTest() {
+ resetSocketPath();
// Make sure that we revert to default value
CfgMgr::instance().clear();
MultiThreadingMgr::instance().apply(false, 0, 0);
}
+void
+Dhcpv4SrvTest::setSocketTestPath(const std::string explicit_path /* = "" */) {
+ UnixCommandConfig::getSocketPath(true, (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+}
+
+void
+Dhcpv4SrvTest::resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
+}
+
void Dhcpv4SrvTest::addPrlOption(Pkt4Ptr& pkt) {
OptionUint8ArrayPtr option_prl =
/// Removes existing configuration.
virtual ~Dhcpv4SrvTest();
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the socket path.
+ void setSocketTestPath(const std::string explicit_path = "");
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath();
+
/// @brief Add 'Parameter Request List' option to the packet.
///
/// This function adds PRL option comprising the following option codes:
" \"control-sockets\": ["
" {"
" \"socket-type\": \"unix\","
- " \"socket-name\": \"/tmp/kea6-ctrl-socket\","
+ " \"socket-name\": \"kea6-ctrl-socket\","
" \"user-context\": { \"comment\": \"Indirect comment\" }"
" },"
" {"
// This test checks comments. Please keep it last.
TEST_F(Dhcp6ParserTest, comments) {
+ setSocketTestPath();
string config = PARSER_CONFIGS[9];
extractConfig(config);
ASSERT_TRUE(socket->get("socket-type"));
EXPECT_EQ("\"unix\"", socket->get("socket-type")->str());
ASSERT_TRUE(socket->get("socket-name"));
- EXPECT_EQ("\"/tmp/kea6-ctrl-socket\"", socket->get("socket-name")->str());
+ EXPECT_EQ("\"kea6-ctrl-socket\"", socket->get("socket-name")->str());
// Check UNIX control socket comment and user context.
ConstElementPtr ctx_socket = socket->get("user-context");
///
/// Sets socket path to its default value.
CtrlChannelDhcpv6SrvTest() : interfaces_("\"*\"") {
- const char* env = getenv("KEA_SOCKET_TEST_DIR");
- if (env) {
- socket_path_ = string(env) + "/kea6.sock";
- } else {
- socket_path_ = sandbox.join("/kea6.sock");
- }
reset();
IfaceMgr::instance().setTestMode(false);
IfaceMgr::instance().setDetectCallback(std::bind(&IfaceMgr::checkDetectIfaces,
IfaceMgr::instancePtr().get(), ph::_1));
+ setSocketTestPath();
+ socket_path_ = UnixCommandConfig::getSocketPath() + "/kea6.sock";
}
/// @brief Destructor
void
Dhcpv6SrvTest::checkConfigFiles() {
+ setSocketTestPath();
#if defined (HAVE_MYSQL)
MySqlHostDataSourceInit mysql_init;
#endif
#include <config.h>
#include <gtest/gtest.h>
#include <cc/command_interpreter.h>
+#include <config/unix_command_config.h>
#include <dhcp/option6_status_code.h>
#include <dhcp/testutils/pkt_captures.h>
#include <dhcpsrv/cfg_multi_threading.h>
using namespace isc::stats;
using namespace isc::util;
using namespace isc::process;
+using namespace isc::config;
using namespace boost::posix_time;
namespace isc {
original_datadir_ = CfgMgr::instance().getDataDir();
CfgMgr::instance().getDataDir(true, TEST_DATA_BUILDDIR);
resetLogPath();
+ resetSocketPath();
}
BaseServerTest::~BaseServerTest() {
// Revert to unit test logging, in case the test reconfigured it.
isc::log::initLogger();
resetLogPath();
+ resetSocketPath();
}
void
LogConfigParser::getLogPath(true);
}
+void
+BaseServerTest::setSocketTestPath(const std::string explicit_path /* = "" */) {
+ UnixCommandConfig::getSocketPath(true,
+ (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+}
+
+void
+BaseServerTest::resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
+}
+
Dhcpv6SrvTest::Dhcpv6SrvTest()
: NakedDhcpv6SrvTest(), srv_(new NakedDhcpv6Srv(0)), multi_threading_(false) {
subnet_ = Subnet6::create(isc::asiolink::IOAddress("2001:db8:1::"),
/// @brief Resets the log path to TEST_DATA_BUILDDIR.
void resetLogPath();
-private:
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the socket path.
+ void setSocketTestPath(const std::string explicit_path = "");
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath();
+private:
/// @brief Holds the original data directory.
std::string original_datadir_;
};
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES) $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
+control_socket_dir = @runstatedir@/@PACKAGE@
+AM_CPPFLAGS += -DCONTROL_SOCKET_DIR=\"$(control_socket_dir)\"
AM_CXXFLAGS = $(KEA_CXXFLAGS)
build_rpath: BUILD_RPATH,
link_with: LIBS_BUILT_SO_FAR,
version: '81.0.0',
+ cpp_args: [
+ f'-DCONTROL_SOCKET_DIR="@RUNSTATEDIR_INSTALLED@"'
+ ],
)
LIBS_BUILT_SO_FAR = [kea_config_lib] + LIBS_BUILT_SO_FAR
subdir('tests')
#include <http/basic_auth_config.h>
#include <testutils/gtest_utils.h>
#include <testutils/test_to_element.h>
+#include <util/filesystem.h>
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::http;
using namespace isc::test;
+using namespace isc::util;
using namespace std;
namespace {
public:
/// @brief Constructor.
UnixCommandConfigTest() : unix_config_() {
+ setSocketTestPath();
}
/// @brief Destructor.
~UnixCommandConfigTest() {
+ resetSocketPath();
+ }
+
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the hooks path.
+ void setSocketTestPath(const std::string explicit_path = "") {
+ UnixCommandConfig::getSocketPath(true,
+ (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+ }
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
}
/// @brief UNIX control socket configuration.
// This test verifies the default UNIX control socket configuration.
TEST_F(UnixCommandConfigTest, default) {
ElementPtr json = Element::createMap();
- ASSERT_THROW(unix_config_.reset(new UnixCommandConfig(json)), BadSocketInfo);
+ ASSERT_THROW(unix_config_.reset(new UnixCommandConfig(json)), DhcpConfigError);
json->set("socket-name", Element::create("name"));
ASSERT_NO_THROW_LOG(unix_config_.reset(new UnixCommandConfig(json)));
// Check default values.
EXPECT_EQ("unix", unix_config_->getSocketType());
- EXPECT_EQ("name", unix_config_->getSocketName());
+ EXPECT_EQ((UnixCommandConfig::getSocketPath() + "/name"),
+ unix_config_->getSocketName());
- // Check unparse.
- string expected = R"(
- {
- "socket-type": "unix",
- "socket-name": "name"
- }
- )";
- runToElementTest(expected, *unix_config_);
+ std::ostringstream os;
+ os << "{ \"socket-type\": \"unix\", \"socket-name\": \""
+ << UnixCommandConfig::getSocketPath()
+ << "/name\" }";
+ runToElementTest(os.str(), *unix_config_);
}
// This test verifies direct error cases.
R"( { "socket-name": 8000 } )",
"invalid type specified for parameter 'socket-name' "
"(<string>:1:19)"
+ },
+ {
+ "bad socket-name path",
+ R"( { "socket-name": "/tmp/mysocket" } )",
+ "'socket-name' is invalid: invalid path specified: '/tmp',"
+ " supported path is '" + UnixCommandConfig::getSocketPath() + "'"
}
};
for (auto const& s : scenarios) {
#include <cc/dhcp_config_error.h>
#include <config/command_mgr.h>
#include <config/unix_command_mgr.h>
+#include <util/filesystem.h>
#include <string>
using namespace isc::asiolink;
using namespace isc::config;
using namespace isc::data;
using namespace isc::dhcp;
+using namespace isc::util;
using namespace std;
// Test class for Unix Command Manager
/// Default constructor
UnixCommandMgrTest() : io_service_(new IOService()) {
+ resetSocketPath();
UnixCommandMgr::instance().setIOService(io_service_);
UnixCommandMgr::instance().closeCommandSockets();
}
/// Default destructor
virtual ~UnixCommandMgrTest() {
UnixCommandMgr::instance().closeCommandSockets();
+ resetSocketPath();
}
- /// @brief Returns socket path (using either hardcoded path or env variable)
- /// @return path to the unix socket
- std::string getSocketPath() {
- std::string socket_path;
- const char* env = getenv("KEA_SOCKET_TEST_DIR");
- if (env) {
- socket_path = std::string(env) + "/test-socket";
- } else {
- socket_path = sandbox.join("test-socket");
- }
- return (socket_path);
+ /// @brief Sets the path in which the socket can be created.
+ /// @param explicit_path path to use as the hooks path.
+ void setSocketTestPath(const std::string explicit_path = "") {
+ UnixCommandConfig::getSocketPath(true,
+ (!explicit_path.empty() ?
+ explicit_path : TEST_DATA_BUILDDIR));
+
+ auto path = UnixCommandConfig::getSocketPath();
+ UnixCommandConfig::setSocketPathPerms(file::getPermissions(path));
+ }
+
+ /// @brief Resets the socket path to the default.
+ void resetSocketPath() {
+ UnixCommandConfig::getSocketPath(true);
+ UnixCommandConfig::setSocketPathPerms();
}
/// @brief IO service used by these tests.
// This test verifies that a Unix socket can be opened properly and that input
// parameters (socket-type and socket-name) are verified.
TEST_F(UnixCommandMgrTest, unixCreate) {
+ setSocketTestPath();
+
// Null pointer is obviously a bad idea.
EXPECT_THROW(UnixCommandMgr::instance().openCommandSocket(ConstElementPtr()),
BadSocketInfo);
// So is passing no parameters.
ElementPtr socket_info = Element::createMap();
EXPECT_THROW(UnixCommandMgr::instance().openCommandSocket(socket_info),
- BadSocketInfo);
+ DhcpConfigError);
// We don't support ipx sockets
socket_info->set("socket-type", Element::create("ipx"));
socket_info->set("socket-type", Element::create("unix"));
EXPECT_THROW(UnixCommandMgr::instance().openCommandSocket(socket_info),
- BadSocketInfo);
+ DhcpConfigError);
- socket_info->set("socket-name", Element::create(getSocketPath()));
+ socket_info->set("socket-name", Element::create("test_socket"));
EXPECT_NO_THROW(UnixCommandMgr::instance().openCommandSocket(socket_info));
EXPECT_GE(UnixCommandMgr::instance().getControlSocketFD(), 0);
// This test checks that when unix path is too long, the socket cannot be opened.
TEST_F(UnixCommandMgrTest, unixCreateTooLong) {
+ setSocketTestPath();
+
ElementPtr socket_info = Element::fromJSON("{ \"socket-type\": \"unix\","
- "\"socket-name\": \"/tmp/toolongtoolongtoolongtoolongtoolongtoolong"
+ "\"socket-name\": \"toolongtoolongtoolongtoolongtoolongtoolong"
"toolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolong"
"\" }");
// Verifies that a socket cannot be concurrently opened more than once.
// It should be reused instead.
TEST_F(UnixCommandMgrTest, exclusiveOpen) {
+ setSocketTestPath();
+
// Pass in valid parameters.
ElementPtr socket_info = Element::createMap();
socket_info->set("socket-type", Element::create("unix"));
- socket_info->set("socket-name", Element::create(getSocketPath()));
+ socket_info->set("socket-name", Element::create("test_socket"));
EXPECT_NO_THROW(UnixCommandMgr::instance().openCommandSocket(socket_info));
EXPECT_GE(UnixCommandMgr::instance().getControlSocketFD(), 0);
#include <cc/dhcp_config_error.h>
#include <config/command_mgr.h>
#include <config/unix_command_config.h>
+#include <util/filesystem.h>
#include <limits>
using namespace isc;
using namespace isc::config;
using namespace isc::data;
using namespace isc::dhcp;
+using namespace isc::util::file;
using namespace std;
namespace isc {
namespace config {
+namespace {
+ // Singleton PathChecker to set and hold valid legal log path.
+ PathCheckerPtr socket_path_checker_;
+ mode_t socket_path_perms_ = UnixCommandConfig::DEFAULT_SOCKET_PATH_PERMS;
+};
+
UnixCommandConfig::UnixCommandConfig(ConstElementPtr config)
: socket_type_("unix"), socket_name_() {
if (config->getType() != Element::map) {
}
// Get socket name.
ConstElementPtr socket_name = config->get("socket-name");
- if (socket_name) {
- if (socket_name->getType() != Element::string) {
- isc_throw(DhcpConfigError,
- "invalid type specified for parameter 'socket-name' ("
- << socket_name->getPosition() << ")");
- }
- socket_name_ = socket_name->stringValue();
- } else {
- isc_throw(BadSocketInfo, "Mandatory 'socket-name' parameter missing");
+ if (!socket_name) {
+ isc_throw(DhcpConfigError, "Mandatory 'socket-name' parameter missing");
+ }
+
+ if (socket_name->getType() != Element::string) {
+ isc_throw(DhcpConfigError,
+ "invalid type specified for parameter 'socket-name' ("
+ << socket_name->getPosition() << ")");
+ }
+
+ try {
+ socket_name_ = validatePath(socket_name->stringValue());
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, "'socket-name' is invalid: " << ex.what());
}
// Get user context.
return (result);
}
+std::string
+UnixCommandConfig::getSocketPath(bool reset /* = false */,
+ const std::string explicit_path /* = "" */) {
+ if (!socket_path_checker_ || reset) {
+ socket_path_checker_.reset(new PathChecker(CONTROL_SOCKET_DIR,
+ "KEA_CONTROL_SOCKET_DIR"));
+ if (!explicit_path.empty()) {
+ socket_path_checker_->getPath(true, explicit_path);
+ }
+ }
+
+ return (socket_path_checker_->getPath());
+}
+
+std::string
+UnixCommandConfig::validatePath(const std::string socket_path,
+ bool enforce /* = true */) {
+ if (!socket_path_checker_) {
+ getSocketPath();
+ }
+
+ auto valid_path = socket_path_checker_->validatePath(socket_path, enforce);
+ if (enforce && !(socket_path_checker_->pathHasPermissions(socket_path_perms_))) {
+ isc_throw (DhcpConfigError,
+ "socket path:" << socket_path_checker_->getPath()
+ << " does not exist or does not have permssions = "
+ << std::hex << socket_path_perms_);
+ }
+
+ return (valid_path);
+}
+
+mode_t
+UnixCommandConfig::getSocketPathPerms() {
+ return(socket_path_perms_);
+}
+
+void
+UnixCommandConfig::setSocketPathPerms(mode_t perms
+ /* = DEFAULT_SOCKET_PATH_PERMS */) {
+ socket_path_perms_ = perms;
+}
+
} // end of isc::config
} // end of isc
class UnixCommandConfig : public isc::data::UserContext,
public isc::data::CfgToElement {
public:
+ /// @brief Defines the default permissions for unix socket parent directory.
+ static const mode_t DEFAULT_SOCKET_PATH_PERMS = (S_IRWXU | S_IRGRP | S_IWGRP);
+
/// @brief Constructor.
///
/// @param config Pointer to the configuration to parse.
/// @brief Virtual destructor.
~UnixCommandConfig() = default;
+ /// @brief Fetches the supported control socket path.
+ ///
+ /// The first call to this function with no arguments will set the default
+ /// path to either the value of CONTROL_SOCKET_DIR or the environment
+ /// variable KEA_CONTROL_SOCKET_DIR if it is defined. Subsequent calls with
+ /// no arguments will simply return this value.
+ ///
+ /// @param reset recalculate when true, defaults to false.
+ /// @param explicit_path set the default socket path to this value. This is
+ /// for testing purposes only.
+ ///
+ /// @return String containing the default socket path.
+ static std::string getSocketPath(bool reset = false,
+ const std::string explicit_path = "");
+
+ /// @brief Validates a path against the supported path for unix control
+ /// sockets.
+ ///
+ /// @param socket_path path to validate.
+ /// @param enforce enables validation against the supported path and
+ /// permissions.
+ /// If false simply returns the input path.
+ ///
+ /// @return validated path
+ static std::string validatePath(const std::string socket_path,
+ bool enforce = true);
+
+ /// @brief Fetches the required socket path permissions mask
+ ///
+ /// @return permissions mask
+ static mode_t getSocketPathPerms();
+
+ /// @brief Sets the required socket path permissions mask
+ ///
+ /// This is for testing purposes only.
+ /// @param perms permissions mask to use
+ static void setSocketPathPerms(mode_t perms = DEFAULT_SOCKET_PATH_PERMS);
+
/// @brief Returns socket type.
///
/// @return The socket type ("unix").
return (::stat(path.c_str(), &statbuf) == 0);
}
+mode_t
+getPermissions(const std::string path) {
+ struct stat statbuf;
+ if (::stat(path.c_str(), &statbuf) < 0) {
+ return (0);
+ }
+
+ return (statbuf.st_mode & 0x01FF);
+}
+
+bool
+hasPermissions(const std::string path, const mode_t& permissions) {
+ return (getPermissions(path) == permissions);
+}
+
bool
isDir(string const& path) {
struct stat statbuf;
return (path_);
}
+bool
+PathChecker::pathHasPermissions(mode_t permissions) {
+ return(hasPermissions(path_, permissions));
+}
+
} // namespace file
} // namespace util
} // namespace isc
bool
exists(const std::string& path);
+/// @brief Fetches the file permissions mask.
+///
+/// @param path The path being checked.
+/// @return File permissios mask or 0 if the path does not exist.
+mode_t
+getPermissions(const std::string path);
+
+/// @brief Check if there if file or directory has the given permissions.
+///
+/// @param path The path being checked.
+/// @param permissions mask of expected permissions.
+///
+/// @return True if the path points to a file or a directory, false otherwise.
+bool
+hasPermissions(const std::string path, const mode_t& permissions);
+
/// @brief Check if there is a directory at the given path.
///
/// @param path The path being checked.
std::string validateDirectory(const std::string input_path_str,
bool enforce_path = true) const;
+ /// @brief Tests that the supported path has the given permissions.
+ ///
+ /// @param permissions mode_t mask of required permissions.
+ /// @return True if the path's permissions exactly match the permissions
+ /// parameter.
+ bool pathHasPermissions(mode_t permissions);
+
/// @brief Fetches the default path.
std::string getDefaultPath() const {
return (default_path_);
EXPECT_FALSE(isFile(TEST_DATA_BUILDDIR));
}
+/// @brief Check hasPermissions.
+TEST_F(FileUtilTest, hasPermissions) {
+ const std::string path = ABS_SRCDIR "/filesystem_unittests.cc";
+ ASSERT_TRUE(isFile(path));
+ mode_t current_permissions = getPermissions(path);
+ EXPECT_TRUE(hasPermissions(path, current_permissions));
+ current_permissions = ~current_permissions;
+ EXPECT_FALSE(hasPermissions(path, current_permissions));
+}
+
/// @brief Test fixture class for testing operations on umask.
struct UMaskUtilTest : ::testing::Test {
/// @brief Constructor.