Rewrote resolvePath so that inaccessible paths return a failure instead.
This commit is contained in:
@@ -42,7 +42,7 @@ public:
|
|||||||
virtual file_data setCWD(std::string _cwd) = 0;
|
virtual file_data setCWD(std::string _cwd) = 0;
|
||||||
virtual std::filesystem::path getRoot() = 0;
|
virtual std::filesystem::path getRoot() = 0;
|
||||||
virtual std::filesystem::path getCWD() = 0;
|
virtual std::filesystem::path getCWD() = 0;
|
||||||
virtual std::filesystem::path resolvePath(const std::string& path) = 0;
|
virtual bool resolvePath(const std::string& path, std::filesystem::path* target) = 0;
|
||||||
virtual void setTransferMode(char type) {
|
virtual void setTransferMode(char type) {
|
||||||
this->transfer_mode = type;
|
this->transfer_mode = type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,46 +73,48 @@ public:
|
|||||||
return this->cwd;
|
return this->cwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path resolvePath(const std::string& path) {
|
bool resolvePath(const std::string& path, fs::path* target) {
|
||||||
try {
|
try {
|
||||||
if (path.empty() || path == ".") {
|
if (path.empty() || path == ".") {
|
||||||
return root / cwd.relative_path();
|
*target = root / cwd.relative_path();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path target_path;
|
|
||||||
if (path[0] == '/') {
|
if (path[0] == '/') {
|
||||||
// Absolute path relative to FTP root
|
// Absolute path relative to FTP root
|
||||||
target_path = root / path.substr(1);
|
*target = root / path.substr(1);
|
||||||
} else {
|
} else {
|
||||||
// Relative to current directory
|
// Relative to current directory
|
||||||
target_path = root / cwd.relative_path() / path;
|
*target = root / cwd.relative_path() / path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove .. and . components
|
// Remove .. and . components
|
||||||
target_path = fs::weakly_canonical(target_path);
|
*target = fs::weakly_canonical(*target);
|
||||||
|
|
||||||
// Make sure we haven't escaped the root
|
// Make sure we haven't escaped the root
|
||||||
if (!target_path.string().starts_with(root.string())) {
|
if (!(*target).string().starts_with(root.string()))
|
||||||
return root / cwd.relative_path();
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return target_path;
|
return true;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
logger->print(LOGLEVEL_ERROR, "Path resolution error: %s", e.what());
|
logger->print(LOGLEVEL_ERROR, "Path resolution error: %s", e.what());
|
||||||
return root / cwd.relative_path();
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file_data traverse(std::string dir) {
|
file_data traverse(std::string dir) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
// Handle special cases
|
fs::path requested_path;
|
||||||
|
if (!resolvePath(dir, &requested_path)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
if (dir.empty() || dir == ".") {
|
if (dir.empty() || dir == ".") {
|
||||||
fd.path = resolvePath(".").string().c_str();
|
fd.path = requested_path.c_str();
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path requested_path = resolvePath(dir);
|
|
||||||
|
|
||||||
// Verify the requested path exists and is within root
|
// Verify the requested path exists and is within root
|
||||||
if (!fs::exists(requested_path)) {
|
if (!fs::exists(requested_path)) {
|
||||||
@@ -146,7 +148,12 @@ public:
|
|||||||
file_data createDirectory(std::string dir) {
|
file_data createDirectory(std::string dir) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(dir);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(dir, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
if (fs::exists(resolved)) {
|
if (fs::exists(resolved)) {
|
||||||
@@ -165,7 +172,11 @@ public:
|
|||||||
file_data fileSize(std::string name) {
|
file_data fileSize(std::string name) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(name);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(name, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
if (!fs::exists(resolved)) {
|
if (!fs::exists(resolved)) {
|
||||||
@@ -194,7 +205,11 @@ public:
|
|||||||
file_data deleteFile(std::string name) {
|
file_data deleteFile(std::string name) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(name);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(name, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
if (!fs::exists(resolved)) {
|
if (!fs::exists(resolved)) {
|
||||||
@@ -220,7 +235,11 @@ public:
|
|||||||
file_data readFile(std::string name) {
|
file_data readFile(std::string name) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(name);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(name, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
if (!fs::exists(resolved)) {
|
if (!fs::exists(resolved)) {
|
||||||
@@ -253,7 +272,11 @@ public:
|
|||||||
file_data writeFile(std::string name, unsigned char* data, int size, bool append = false) {
|
file_data writeFile(std::string name, unsigned char* data, int size, bool append = false) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(name);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(name, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
std::ios_base::openmode omode = std::ios::out|std::ios::binary;
|
std::ios_base::openmode omode = std::ios::out|std::ios::binary;
|
||||||
@@ -276,8 +299,16 @@ public:
|
|||||||
|
|
||||||
struct file_data renameFile(const std::string& from, const std::string& to) {
|
struct file_data renameFile(const std::string& from, const std::string& to) {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
std::filesystem::path src_path = resolvePath(from);
|
fs::path src_path;
|
||||||
std::filesystem::path dst_path = resolvePath(to);
|
if (!resolvePath(from, &src_path)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Source Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
fs::path dst_path;
|
||||||
|
if (!resolvePath(to, &dst_path)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Destination Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if destination already exists
|
// Check if destination already exists
|
||||||
@@ -300,7 +331,11 @@ public:
|
|||||||
file_data list(std::string path = ".") {
|
file_data list(std::string path = ".") {
|
||||||
struct file_data fd;
|
struct file_data fd;
|
||||||
try {
|
try {
|
||||||
fs::path resolved = resolvePath(path);
|
fs::path resolved;
|
||||||
|
if (!resolvePath(path, &resolved)) {
|
||||||
|
fd.error = file_error{FilerStatusCodes::NoPermission, "Invalid Permissions"};
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
fd.path = resolved.string().c_str();
|
fd.path = resolved.string().c_str();
|
||||||
|
|
||||||
if (!fs::exists(resolved)) {
|
if (!fs::exists(resolved)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user