AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/run_script -I$(top_srcdir)/src/hooks/dhcp/run_script
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DLIBRUN_SCRIPT_SO=\"$(abs_top_builddir)/src/hooks/dhcp/run_script/.libs/libdhcp_run_script.so\"
+AM_CPPFLAGS += -DRUN_SCRIPT_TEST_SH=\"$(abs_top_builddir)/src/hooks/dhcp/run_script/tests/run_script_test.sh\"
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
AM_CXXFLAGS = $(KEA_CXXFLAGS)
TEST_F(LibLoadTest, validLoad) {
// Prepare parameters for the callout parameters library.
ElementPtr params = Element::createMap();
- ElementPtr name = Element::create("test_script.sh");
+ ElementPtr name = Element::create(RUN_SCRIPT_TEST_SH);
params->set("name", name);
ElementPtr sync = Element::create(false);
params->set("sync", sync);
params->set("name", name);
EXPECT_FALSE(loadLibs());
- // Use valid name parameter type but use invalid sync parameter type.
+ // Use invalid name parameter.
name = Element::create("script_name.sh");
params->set("name", name);
+ EXPECT_FALSE(loadLibs());
+
+ // Use valid name parameter type but use invalid sync parameter type.
+ name = Element::create(RUN_SCRIPT_TEST_SH);
+ params->set("name", name);
ElementPtr sync = Element::create("data");
params->set("sync", sync);
-
EXPECT_FALSE(loadLibs());
}
if (name->getType() != Element::string) {
isc_throw(InvalidParameter, "The 'name' parameter must be a string");
}
+ IOServicePtr io_service(new asiolink::IOService());
+ try {
+ ProcessSpawn process(io_service, name->stringValue());
+ if (!process.checkPermissions()) {
+ isc_throw(InvalidParameter, "The 'name' parameter must point to an executable");
+ }
+ } catch (const isc::Exception& ex) {
+ isc_throw(InvalidParameter, "Invalid 'name' parameter: " << ex.what());
+ }
setName(name->stringValue());
ConstElementPtr sync = handle.getParameter("sync");
if (sync) {
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
+#include <sys/stat.h>
#include <sys/wait.h>
using namespace std;
/// @param pid A process pid.
void clearState(const pid_t pid);
+ /// @brief Check executable permissions.
+ ///
+ /// @return true if file has executable permissions, false otherwise.
+ /// @throw ProcessSpawnError if file does not exist.
+ bool checkPermissions() const;
+
private:
/// @brief Copies the argument specified as a C++ string to the new
: impl_(new ProcessSpawnImpl(io_service, executable, args, vars)) {
}
+bool
+ProcessSpawnImpl::checkPermissions() const {
+ struct stat st;
+ if (stat(executable_.c_str(), &st)) {
+ isc_throw(ProcessSpawnError, "File not found: " << executable_);
+ }
+ if (st.st_mode & S_IEXEC) {
+ return (true);
+ }
+ return (false);
+}
+
std::string
ProcessSpawn::getCommandLine() const {
return (impl_->getCommandLine());
return (impl_->clearState(pid));
}
+bool
+ProcessSpawn::checkPermissions() const {
+ return (impl_->checkPermissions());
+}
+
} // namespace asiolink
} // namespace isc
/// @param pid A process pid.
void clearState(const pid_t pid);
+ /// @brief Check executable permissions.
+ ///
+ /// @return true if file has executable permissions, false otherwise.
+ /// @throw ProcessSpawnError if file does not exist.
+ bool checkPermissions() const;
+
private:
/// @brief A smart pointer to the implementation of this class.
#include <sys/types.h>
#include <unistd.h>
+#include <testutils/gtest_utils.h>
+
namespace {
using namespace isc;
ASSERT_EQ(SIGCHLD, processed_signals_[0]);
}
+// This test verifies that the checkPermissions function throws if the file does
+// not exist and returns true or false if the file is or it is not executable.
+TEST_F(ProcessSpawnTest, checkPermissions) {
+ ProcessSpawn no_process(io_service_, "no-file");
+ EXPECT_THROW_MSG(no_process.checkPermissions(), ProcessSpawnError,
+ "File not found: no-file");
+
+ std::string name = TEST_SCRIPT_SH;
+ name += ".in";
+ ProcessSpawn invalid_process(io_service_, name);
+ ASSERT_FALSE(invalid_process.checkPermissions());
+ ProcessSpawn process(io_service_, TEST_SCRIPT_SH);
+ ASSERT_TRUE(process.checkPermissions());
+}
+
} // end of anonymous namespace