}
}
+.. note::
+
+ As of Kea 2.7.9, the config file file may only be written to the same
+ directory as the config file used when starting Kea (passed as a ``-c``
+ argument).
+
.. isccmd:: leases-reclaim
.. _command-leases-reclaim:
// filename parameter was not specified, so let's use whatever we remember
// from the command-line
filename = getConfigFile();
- }
-
- if (filename.empty()) {
- return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
- "Please specify filename explicitly."));
+ if (filename.empty()) {
+ return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
+ "Please specify filename explicitly."));
+ }
+ } else {
+ try {
+ checkWriteConfigFile(filename);
+ } catch (const isc::Exception& ex) {
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ string("not allowed to write config into ") +
+ filename));
+ }
}
// Ok, it's time to write the file.
/// current configuration to disk. This command takes one optional
/// parameter called filename. If specified, the current configuration
/// will be written to that file. If not specified, the file used during
- /// Kea start-up will be used. To avoid any exploits, the path is
- /// always relative and .. is not allowed in the filename. This is
- /// a security measure against exploiting file writes remotely.
+ /// Kea start-up will be used. To avoid any exploits, the target
+ /// directory must be the same as a security measure against
+ /// exploiting file writes remotely.
///
/// @param command (ignored)
/// @param args may contain optional string argument filename
// filename parameter was not specified, so let's use whatever we remember
// from the command-line
filename = getConfigFile();
- }
-
- if (filename.empty()) {
- return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
- "Please specify filename explicitly."));
+ if (filename.empty()) {
+ return (createAnswer(CONTROL_RESULT_ERROR, "Unable to determine filename."
+ "Please specify filename explicitly."));
+ }
+ } else {
+ try {
+ checkWriteConfigFile(filename);
+ } catch (const isc::Exception& ex) {
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ string("not allowed to write config into ") +
+ filename));
+ }
}
// Ok, it's time to write the file.
/// current configuration to disk. This command takes one optional
/// parameter called filename. If specified, the current configuration
/// will be written to that file. If not specified, the file used during
- /// Kea start-up will be used. To avoid any exploits, the path is
- /// always relative and .. is not allowed in the filename. This is
- /// a security measure against exploiting file writes remotely.
+ /// Kea start-up will be used. To avoid any exploits, the target
+ /// directory must be the same as a security measure against
+ /// exploiting file writes remotely.
///
/// @param command (ignored)
/// @param args may contain optional string argument filename
"Unable to determine filename."
"Please specify filename explicitly."));
}
+ } else {
+ try {
+ checkWriteConfigFile(filename);
+ } catch (const isc::Exception& ex) {
+ return (createAnswer(CONTROL_RESULT_ERROR,
+ std::string("not allowed to write config into ") +
+ filename));
+ }
}
// Ok, it's time to write the file.
size_t size = 0;
- ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
try {
+ ElementPtr cfg = process_->getCfgMgr()->getContext()->toElement();
size = writeConfigFile(filename, cfg);
} catch (const isc::Exception& ex) {
return (createAnswer(CONTROL_RESULT_ERROR,
/// current configuration to disk. This command takes one optional
/// parameter called filename. If specified, the current configuration
/// will be written to that file. If not specified, the file used during
- /// Kea start-up will be used. To avoid any exploits, the path is
- /// always relative and .. is not allowed in the filename. This is
- /// a security measure against exploiting file writes remotely.
+ /// Kea start-up will be used. To avoid any exploits, the target
+ /// directory must be the same as a security measure against
+ /// exploiting file writes remotely.
///
/// @param command (ignored)
/// @param args may contain optional string argument filename
}
}
+void
+Daemon::checkWriteConfigFile(std::string& file) {
+ Path path(file);
+ // from checkConfigFile().
+ if (path.stem().empty()) {
+ isc_throw(isc::BadValue, "config file:" << file
+ << " is missing file name");
+ }
+ Path current(config_file_);
+ if (current.parentPath() == path.parentPath()) {
+ // Same paths!
+ return;
+ }
+ if (path.parentPath().empty()) {
+ // Note the current path can't be empty here.
+ file = current.parentPath() + "/" + file;
+ return;
+ }
+ isc_throw(isc::BadValue, "file " << file << " must be in the same "
+ << "directory as the config file (" << config_file_ << "'");
+}
+
std::string
Daemon::getProcName() {
return (proc_name_);
/// @throw BadValue when the configuration file name is bad.
void checkConfigFile() const;
+ /// @brief Checks the to-be-written configuration file name.
+ ///
+ /// @note As a side effect prepend the current config file path
+ /// when the name does not contain a slash.
+ ///
+ /// @param[in][out] file Reference to the TBW configuration file name.
+ /// @throw BadValue when not in the same directory.
+ void checkWriteConfigFile(std::string& file);
+
/// @brief Writes current configuration to specified file
///
/// This method writes the current configuration to specified file.