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:
parent
1ef4a7eb9e
commit
e002a481f4
@ -53,6 +53,10 @@
|
||||
using std::string;
|
||||
using simgear::strutils::starts_with;
|
||||
|
||||
// For SGPath::validate()
|
||||
static string_list read_allowed_paths;
|
||||
static string_list write_allowed_paths;
|
||||
|
||||
/**
|
||||
* define directory path separators
|
||||
*/
|
||||
@ -279,6 +283,62 @@ void SGPath::set_cached(bool cached)
|
||||
_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
|
||||
void SGPath::append( const string& p ) {
|
||||
if ( path.empty() ) {
|
||||
@ -993,7 +1053,7 @@ SGPath SGPath::realpath() const
|
||||
char* buf = ::realpath(path.c_str(), NULL);
|
||||
#endif
|
||||
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()) {
|
||||
return simgear::Dir::current().path();
|
||||
|
@ -104,7 +104,39 @@ public:
|
||||
* retrieved each time it is queried. Caching is enabled by default
|
||||
*/
|
||||
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
|
||||
* separator between the existing component and the new component.
|
||||
|
Loading…
Reference in New Issue
Block a user