2017-12-19 00:04:06 +00:00
|
|
|
/**
|
2017-08-20 02:59:23 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
2017-12-19 00:04:06 +00:00
|
|
|
* This source code is licensed under both the Apache 2.0 license (found in the
|
|
|
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
|
|
|
* in the COPYING file in the root directory of this source tree).
|
|
|
|
* You may select, at your option, one of the above-listed licenses.
|
2017-08-20 02:59:23 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <boost/noncopyable.hpp>
|
|
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
|
|
|
|
#include <osquery/core.h>
|
|
|
|
#include <osquery/filesystem.h>
|
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
/**
|
2018-06-13 13:51:27 +00:00
|
|
|
* @brief multiset based implementation for path search.
|
2017-08-20 02:59:23 +00:00
|
|
|
*
|
|
|
|
* 'multiset' is used because with patterns we can serach for equivalent keys.
|
|
|
|
* Since '/This/Path/is' ~= '/This/Path/%' ~= '/This/Path/%%' (equivalent).
|
|
|
|
*
|
|
|
|
* multiset is protected by lock. It is threadsafe.
|
|
|
|
*
|
|
|
|
* PathSet can take any of the two policies -
|
|
|
|
* 1. patternedPath - Path can contain pattern '%' and '%%'.
|
|
|
|
* Path components containing only '%' and '%%' are supported
|
|
|
|
* e.g. '/This/Path/%'.
|
|
|
|
* Path components containing partial patterns are not
|
|
|
|
* supported e.g. '/This/Path/xyz%' ('xyz%' will not be
|
|
|
|
* treated as pattern).
|
|
|
|
*/
|
|
|
|
template <typename PathType>
|
|
|
|
class PathSet : private boost::noncopyable {
|
|
|
|
public:
|
|
|
|
void insert(const std::string& str) {
|
|
|
|
auto pattern = str;
|
|
|
|
replaceGlobWildcards(pattern);
|
|
|
|
auto vpath = PathType::createVPath(pattern);
|
|
|
|
|
|
|
|
WriteLock lock(mset_lock_);
|
|
|
|
for (auto& path : vpath) {
|
|
|
|
paths_.insert(std::move(path));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool find(const std::string& str) const {
|
|
|
|
auto path = PathType::createPath(str);
|
|
|
|
|
|
|
|
ReadLock lock(mset_lock_);
|
|
|
|
if (paths_.find(path) != paths_.end()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clear() {
|
|
|
|
WriteLock lock(mset_lock_);
|
|
|
|
paths_.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const {
|
|
|
|
ReadLock lock(mset_lock_);
|
|
|
|
return paths_.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
typedef typename PathType::Path Path;
|
|
|
|
typedef typename PathType::Compare Compare;
|
|
|
|
std::multiset<Path, Compare> paths_;
|
|
|
|
mutable Mutex mset_lock_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class patternedPath {
|
|
|
|
public:
|
|
|
|
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
|
|
|
typedef std::vector<std::string> Path;
|
|
|
|
typedef std::vector<Path> VPath;
|
|
|
|
struct Compare {
|
|
|
|
bool operator()(const Path& lhs, const Path& rhs) const {
|
|
|
|
size_t psize = (lhs.size() < rhs.size()) ? lhs.size() : rhs.size();
|
|
|
|
unsigned ndx;
|
|
|
|
for (ndx = 0; ndx < psize; ++ndx) {
|
|
|
|
if (lhs[ndx] == "**" || rhs[ndx] == "**") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lhs[ndx] == "*" || rhs[ndx] == "*") {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rc = lhs[ndx].compare(rhs[ndx]);
|
|
|
|
|
|
|
|
if (rc > 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ndx == rhs.size() && rhs[ndx - 1] == "*") ||
|
|
|
|
(ndx == lhs.size() && lhs[ndx - 1] == "*")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (lhs.size() < rhs.size());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Path createPath(const std::string& str) {
|
|
|
|
boost::char_separator<char> sep{"/"};
|
|
|
|
tokenizer tokens(str, sep);
|
|
|
|
Path path;
|
|
|
|
|
|
|
|
if (str == "/") {
|
|
|
|
path.push_back("");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::string component : tokens) {
|
|
|
|
path.push_back(std::move(component));
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VPath createVPath(const std::string& str) {
|
|
|
|
boost::char_separator<char> sep{"/"};
|
|
|
|
tokenizer tokens(str, sep);
|
|
|
|
VPath vpath;
|
|
|
|
Path path;
|
|
|
|
|
|
|
|
if (str == "/") {
|
|
|
|
path.push_back("");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::string component : tokens) {
|
|
|
|
if (component == "**") {
|
|
|
|
vpath.push_back(path);
|
|
|
|
path.push_back(std::move(component));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
path.push_back(std::move(component));
|
|
|
|
}
|
|
|
|
vpath.push_back(std::move(path));
|
|
|
|
return vpath;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace osquery
|