Import FlightGear's fgValidatePath() as SGPath::validate()
This will allow us to perform access control validation in SimGear. The current implementation of SGPath::validate() is 99% Rebecca Palmer's work (see fgValidatePath() in FlightGear commit 6a30e7086ea2f1a060dd77dab6e7e8a15b43e82d); only the coding style has been slightly modernized here since we can now use, for instance, C++11's range-based for loop.
This commit is contained in:
@@ -53,6 +53,10 @@
|
|||||||
using std::string;
|
using std::string;
|
||||||
using simgear::strutils::starts_with;
|
using simgear::strutils::starts_with;
|
||||||
|
|
||||||
|
// For SGPath::validate()
|
||||||
|
static string_list read_allowed_paths;
|
||||||
|
static string_list write_allowed_paths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* define directory path separators
|
* define directory path separators
|
||||||
*/
|
*/
|
||||||
@@ -279,6 +283,62 @@ void SGPath::set_cached(bool cached)
|
|||||||
_cached = false;
|
_cached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
// * Access permissions for Nasal code *
|
||||||
|
// ***************************************************************************
|
||||||
|
|
||||||
|
// Static member function
|
||||||
|
void SGPath::clearListOfAllowedPaths(bool write)
|
||||||
|
{
|
||||||
|
string_list& allowed_paths(write ? write_allowed_paths : read_allowed_paths);
|
||||||
|
allowed_paths.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static member function
|
||||||
|
void SGPath::addAllowedPathPattern(const string& pattern, bool write)
|
||||||
|
{
|
||||||
|
string_list& allowed_paths(write ? write_allowed_paths : read_allowed_paths);
|
||||||
|
allowed_paths.push_back(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static member function
|
||||||
|
const string_list& SGPath::getListOfAllowedPaths(bool write)
|
||||||
|
{
|
||||||
|
return write ? write_allowed_paths : read_allowed_paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPath SGPath::validate(bool write) const
|
||||||
|
{
|
||||||
|
// Normalize the path (prevents ../../.. or symlink trickery)
|
||||||
|
const string normed_path = realpath().utf8Str();
|
||||||
|
|
||||||
|
const string_list& allowed_paths{
|
||||||
|
write ? write_allowed_paths : read_allowed_paths};
|
||||||
|
string::size_type star_pos;
|
||||||
|
|
||||||
|
// Check against each allowed pattern
|
||||||
|
for (const auto& path: allowed_paths) {
|
||||||
|
star_pos = path.find('*');
|
||||||
|
if (star_pos == string::npos) {
|
||||||
|
if (!(path.compare(normed_path))) {
|
||||||
|
return fromUtf8(normed_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((path.size()-1 <= normed_path.size()) /* long enough to be a potential match */
|
||||||
|
&& !(path.substr(0, star_pos)
|
||||||
|
.compare(normed_path.substr(0, star_pos))) /* before-star parts match */
|
||||||
|
&& !(path.substr(star_pos+1, path.size()-star_pos-1)
|
||||||
|
.compare(normed_path.substr(star_pos+1+normed_path.size()-path.size(),
|
||||||
|
path.size()-star_pos-1))) /* after-star parts match */) {
|
||||||
|
return fromUtf8(normed_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No match found
|
||||||
|
return SGPath();
|
||||||
|
}
|
||||||
|
|
||||||
// append another piece to the existing path
|
// append another piece to the existing path
|
||||||
void SGPath::append( const string& p ) {
|
void SGPath::append( const string& p ) {
|
||||||
if ( path.empty() ) {
|
if ( path.empty() ) {
|
||||||
@@ -993,7 +1053,7 @@ SGPath SGPath::realpath() const
|
|||||||
char* buf = ::realpath(path.c_str(), NULL);
|
char* buf = ::realpath(path.c_str(), NULL);
|
||||||
#endif
|
#endif
|
||||||
if (!buf) // File does not exist: return the realpath it would have if created now
|
if (!buf) // File does not exist: return the realpath it would have if created now
|
||||||
// (needed for fgValidatePath security)
|
// (needed for SGPath::validate() security)
|
||||||
{
|
{
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
return simgear::Dir::current().path();
|
return simgear::Dir::current().path();
|
||||||
|
|||||||
@@ -104,7 +104,39 @@ public:
|
|||||||
* retrieved each time it is queried. Caching is enabled by default
|
* retrieved each time it is queried. Caching is enabled by default
|
||||||
*/
|
*/
|
||||||
void set_cached(bool cached);
|
void set_cached(bool cached);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear a list of allowed paths patterns for access by Nasal and fgcommands.
|
||||||
|
* @param write True for write operations, false for read operations
|
||||||
|
*
|
||||||
|
* There are two lists of patterns: one for read operations and the other
|
||||||
|
* for write operations. The 'write' argument tells which list to act on.
|
||||||
|
* These lists are used by validate(), which determines whether access is
|
||||||
|
* allowed for a given path.
|
||||||
|
*/
|
||||||
|
static void clearListOfAllowedPaths(bool write);
|
||||||
|
/**
|
||||||
|
* Add a path pattern to the specified access control list.
|
||||||
|
* @param write True for write operations, false for read operations
|
||||||
|
*/
|
||||||
|
static void addAllowedPathPattern(const std::string& pattern, bool write);
|
||||||
|
/**
|
||||||
|
* Get a const reference to the specified access control list.
|
||||||
|
* @param write True for write operations, false for read operations
|
||||||
|
*/
|
||||||
|
static const string_list& getListOfAllowedPaths(bool write);
|
||||||
|
/**
|
||||||
|
* File access control, used by Nasal and fgcommands.
|
||||||
|
* @param write True for write operations, false for read operations
|
||||||
|
* @return The validated path on success, or empty if access is denied
|
||||||
|
*
|
||||||
|
* Warning: because this always (not just on Windows) treats both \ and /
|
||||||
|
* as path separators, and accepts relative paths (check-to-use race if
|
||||||
|
* the current directory changes), always use the returned path---not the
|
||||||
|
* original one.
|
||||||
|
*/
|
||||||
|
SGPath validate(bool write) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append another piece to the existing path. Inserts a path
|
* Append another piece to the existing path. Inserts a path
|
||||||
* separator between the existing component and the new component.
|
* separator between the existing component and the new component.
|
||||||
|
|||||||
Reference in New Issue
Block a user