2014-12-18 18:50:47 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-01-26 18:32:39 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2014-12-18 18:50:47 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2014-08-04 18:06:45 +00:00
|
|
|
|
2014-10-30 22:03:05 +00:00
|
|
|
#include <exception>
|
2014-08-04 18:06:45 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
2014-10-30 22:03:05 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
#include <boost/algorithm/string/join.hpp>
|
2014-11-03 20:08:46 +00:00
|
|
|
#include <boost/filesystem/fstream.hpp>
|
2014-08-04 18:06:45 +00:00
|
|
|
#include <boost/filesystem/operations.hpp>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
2014-10-01 02:49:38 +00:00
|
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <boost/property_tree/xml_parser.hpp>
|
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
#include <osquery/core.h>
|
2014-12-03 23:14:02 +00:00
|
|
|
#include <osquery/filesystem.h>
|
2015-01-21 21:36:55 +00:00
|
|
|
#include <osquery/logger.h>
|
2015-02-09 00:00:43 +00:00
|
|
|
#include <osquery/sql.h>
|
2014-10-27 18:55:28 +00:00
|
|
|
|
2014-10-01 02:49:38 +00:00
|
|
|
namespace pt = boost::property_tree;
|
2014-11-03 20:08:46 +00:00
|
|
|
namespace fs = boost::filesystem;
|
2014-10-01 02:49:38 +00:00
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
namespace osquery {
|
2014-08-04 18:06:45 +00:00
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status writeTextFile(const boost::filesystem::path& path,
|
|
|
|
const std::string& content,
|
|
|
|
int permissions,
|
|
|
|
bool force_permissions) {
|
2014-10-30 22:03:05 +00:00
|
|
|
// Open the file with the request permissions.
|
2014-11-03 18:09:54 +00:00
|
|
|
int output_fd =
|
|
|
|
open(path.c_str(), O_CREAT | O_APPEND | O_WRONLY, permissions);
|
2014-10-30 22:03:05 +00:00
|
|
|
if (output_fd <= 0) {
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Could not create file: " + path.string());
|
2014-10-30 22:03:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the file existed with different permissions before our open
|
|
|
|
// they must be restricted.
|
|
|
|
if (chmod(path.c_str(), permissions) != 0) {
|
|
|
|
// Could not change the file to the requested permissions.
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Failed to change permissions for file: " + path.string());
|
2014-10-30 22:03:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto bytes = write(output_fd, content.c_str(), content.size());
|
|
|
|
if (bytes != content.size()) {
|
|
|
|
close(output_fd);
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Failed to write contents to file: " + path.string());
|
2014-10-30 22:03:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
close(output_fd);
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status readFile(const boost::filesystem::path& path, std::string& content) {
|
2014-10-30 22:03:05 +00:00
|
|
|
auto path_exists = pathExists(path);
|
|
|
|
if (!path_exists.ok()) {
|
|
|
|
return path_exists;
|
2014-08-04 18:06:45 +00:00
|
|
|
}
|
|
|
|
|
2014-11-09 15:57:12 +00:00
|
|
|
std::stringstream buffer;
|
2014-11-03 20:08:46 +00:00
|
|
|
fs::ifstream file_h(path);
|
2014-11-09 15:57:12 +00:00
|
|
|
if (file_h.is_open()) {
|
|
|
|
buffer << file_h.rdbuf();
|
|
|
|
if (file_h.bad()) {
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Error reading file: " + path.string());
|
|
|
|
}
|
|
|
|
content.assign(std::move(buffer.str()));
|
2014-08-04 18:06:45 +00:00
|
|
|
} else {
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Could not open file: " + path.string());
|
2014-08-21 21:35:51 +00:00
|
|
|
}
|
2015-01-26 08:02:02 +00:00
|
|
|
|
|
|
|
return Status(0, "OK");
|
2014-08-04 18:06:45 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status isWritable(const boost::filesystem::path& path) {
|
2014-10-30 22:03:05 +00:00
|
|
|
auto path_exists = pathExists(path);
|
|
|
|
if (!path_exists.ok()) {
|
|
|
|
return path_exists;
|
2014-10-27 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2014-10-27 18:55:28 +00:00
|
|
|
if (access(path.c_str(), W_OK) == 0) {
|
|
|
|
return Status(0, "OK");
|
2014-10-27 01:39:03 +00:00
|
|
|
}
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Path is not writable: " + path.string());
|
2014-10-27 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status isReadable(const boost::filesystem::path& path) {
|
2014-10-30 22:03:05 +00:00
|
|
|
auto path_exists = pathExists(path);
|
|
|
|
if (!path_exists.ok()) {
|
|
|
|
return path_exists;
|
2014-10-29 09:24:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (access(path.c_str(), R_OK) == 0) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Path is not readable: " + path.string());
|
2014-10-29 09:24:00 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status pathExists(const boost::filesystem::path& path) {
|
|
|
|
if (path.empty()) {
|
2014-10-30 22:03:05 +00:00
|
|
|
return Status(1, "-1");
|
2014-09-09 17:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// A tri-state determination of presence
|
2014-11-06 21:20:22 +00:00
|
|
|
try {
|
|
|
|
if (!boost::filesystem::exists(path)) {
|
|
|
|
return Status(1, "0");
|
|
|
|
}
|
2014-11-22 01:08:33 +00:00
|
|
|
} catch (boost::filesystem::filesystem_error e) {
|
2014-11-06 21:20:22 +00:00
|
|
|
return Status(1, e.what());
|
2014-09-09 17:56:48 +00:00
|
|
|
}
|
|
|
|
return Status(0, "1");
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
Status remove(const boost::filesystem::path& path) {
|
|
|
|
auto status_code = std::remove(path.string().c_str());
|
|
|
|
return Status(status_code, "N/A");
|
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status listFilesInDirectory(const boost::filesystem::path& path,
|
2014-08-15 07:25:30 +00:00
|
|
|
std::vector<std::string>& results) {
|
2014-08-14 23:27:20 +00:00
|
|
|
try {
|
|
|
|
if (!boost::filesystem::exists(path)) {
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Directory not found: " + path.string());
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!boost::filesystem::is_directory(path)) {
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Supplied path is not a directory: " + path.string());
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
boost::filesystem::directory_iterator begin_iter(path);
|
|
|
|
boost::filesystem::directory_iterator end_iter;
|
|
|
|
for (; begin_iter != end_iter; begin_iter++) {
|
2015-01-26 18:32:39 +00:00
|
|
|
if (!boost::filesystem::is_directory(begin_iter->path())) {
|
|
|
|
results.push_back(begin_iter->path().string());
|
|
|
|
}
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Status(0, "OK");
|
2014-10-28 00:37:36 +00:00
|
|
|
} catch (const boost::filesystem::filesystem_error& e) {
|
2014-08-14 23:27:20 +00:00
|
|
|
return Status(1, e.what());
|
|
|
|
}
|
|
|
|
}
|
2014-10-01 02:49:38 +00:00
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
Status listDirectoriesInDirectory(const boost::filesystem::path& path,
|
|
|
|
std::vector<std::string>& results) {
|
|
|
|
try {
|
|
|
|
if (!boost::filesystem::exists(path)) {
|
|
|
|
return Status(1, "Directory not found");
|
|
|
|
}
|
|
|
|
|
|
|
|
auto stat = pathExists(path);
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
stat = isDirectory(path);
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::filesystem::directory_iterator begin_iter(path);
|
|
|
|
boost::filesystem::directory_iterator end_iter;
|
|
|
|
for (; begin_iter != end_iter; begin_iter++) {
|
|
|
|
if (boost::filesystem::is_directory(begin_iter->path())) {
|
|
|
|
results.push_back(begin_iter->path().string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status(0, "OK");
|
|
|
|
} catch (const boost::filesystem::filesystem_error& e) {
|
|
|
|
return Status(1, e.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Drill down recursively and list all sub files
|
|
|
|
*
|
|
|
|
* This functions purpose is to take a path with no wildcards
|
|
|
|
* and it will recursively go through all files and and return
|
|
|
|
* them in the results vector.
|
|
|
|
*
|
|
|
|
* @param fs_path The entire resolved path
|
|
|
|
* @param results The vector where results will be returned
|
|
|
|
* @param rec_depth How many recursions deep the current execution is at
|
|
|
|
*
|
|
|
|
* @return An instance of osquery::Status indicating the success of failure of
|
|
|
|
* the operation
|
|
|
|
*/
|
|
|
|
Status doubleStarTraversal(const boost::filesystem::path& fs_path,
|
|
|
|
std::vector<std::string>& results,
|
|
|
|
unsigned int rec_depth) {
|
|
|
|
if (rec_depth >= kMaxDirectoryTraversalDepth) {
|
|
|
|
return Status(2, fs_path.string().c_str());
|
|
|
|
}
|
|
|
|
// List files first
|
|
|
|
Status stat = listFilesInDirectory(fs_path, results);
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
std::vector<std::string> folders;
|
|
|
|
stat = listDirectoriesInDirectory(fs_path, folders);
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& folder : folders) {
|
|
|
|
boost::filesystem::path p(folder);
|
|
|
|
if (boost::filesystem::is_symlink(p)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
stat = doubleStarTraversal(folder, results, rec_depth + 1);
|
|
|
|
if (!stat.ok() && stat.getCode() == 2) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Resolve the last component of a file path
|
|
|
|
*
|
|
|
|
* This function exists because unlike the other parts of of a file
|
|
|
|
* path, which should only resolve to folder, a wildcard at the end
|
|
|
|
* means to list all files in that directory, as does just listing
|
|
|
|
* folder. Also, a double means to drill down recursively into that
|
|
|
|
* that folder and list all sub file.
|
|
|
|
*
|
|
|
|
* @param fs_path The entire resolved path (except last component)
|
|
|
|
* @param results The vector where results will be returned
|
|
|
|
* @param components A path, split by forward slashes
|
|
|
|
* @param rec_depth How many recursions deep the current execution is at
|
|
|
|
*
|
|
|
|
* @return An instance of osquery::Status indicating the success of failure of
|
|
|
|
* the operation
|
|
|
|
*/
|
|
|
|
Status resolveLastPathComponent(const boost::filesystem::path& fs_path,
|
|
|
|
std::vector<std::string>& results,
|
2015-02-21 00:55:13 +00:00
|
|
|
unsigned int setting,
|
2015-01-26 18:32:39 +00:00
|
|
|
const std::vector<std::string>& components,
|
|
|
|
unsigned int rec_depth) {
|
|
|
|
// Is the last component a double star?
|
|
|
|
if (components[components.size() - 1] == kWildcardCharacterRecursive) {
|
2015-02-21 00:55:13 +00:00
|
|
|
if(setting == REC_LIST_FOLDERS){
|
|
|
|
results.push_back(fs_path.parent_path().string());
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
Status stat =
|
|
|
|
doubleStarTraversal(fs_path.parent_path(), results, rec_depth);
|
|
|
|
return stat;
|
|
|
|
}
|
2015-02-05 18:34:42 +00:00
|
|
|
|
|
|
|
// Is the path a file
|
|
|
|
try {
|
2015-02-21 00:55:13 +00:00
|
|
|
if (boost::filesystem::is_regular_file(fs_path) && setting == REC_LIST_FILES) {
|
2015-02-05 18:34:42 +00:00
|
|
|
results.push_back(fs_path.string());
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
} catch (const boost::filesystem::filesystem_error& e) {
|
|
|
|
// This should catch permission problems
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> files;
|
|
|
|
Status stat = listFilesInDirectory(fs_path.parent_path(), files);
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
// Is the last component a wildcard?
|
|
|
|
if (components[components.size() - 1] == kWildcardCharacter) {
|
2015-02-21 00:55:13 +00:00
|
|
|
if(setting == REC_LIST_FOLDERS){
|
|
|
|
results.push_back(fs_path.parent_path().string());
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-02-05 18:34:42 +00:00
|
|
|
for (const auto& file : files) {
|
|
|
|
results.push_back(file);
|
2015-01-26 18:32:39 +00:00
|
|
|
}
|
2015-02-05 18:34:42 +00:00
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string processed_path =
|
|
|
|
"/" +
|
|
|
|
boost::algorithm::join(
|
|
|
|
std::vector<std::string>(components.begin(), components.end() - 1),
|
|
|
|
"/");
|
|
|
|
|
|
|
|
// Is this a .*% type file match
|
|
|
|
if (components[components.size() - 1].find(kWildcardCharacter, 1) !=
|
|
|
|
std::string::npos &&
|
|
|
|
components[components.size() - 1][0] != kWildcardCharacter[0]) {
|
|
|
|
|
|
|
|
std::string prefix =
|
|
|
|
processed_path + "/" +
|
|
|
|
components[components.size() - 1].substr(
|
|
|
|
0, components[components.size() - 1].find(kWildcardCharacter, 1));
|
2015-01-26 18:32:39 +00:00
|
|
|
for (const auto& file : files) {
|
2015-02-05 18:34:42 +00:00
|
|
|
if (file.find(prefix, 0) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
results.push_back(file);
|
|
|
|
}
|
2015-02-21 00:55:13 +00:00
|
|
|
//Should be a return here?
|
|
|
|
return Status(0, "OK");
|
2015-02-05 18:34:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Is this a %(.*) type file match
|
|
|
|
if (components[components.size() - 1][0] == kWildcardCharacter[0]) {
|
|
|
|
std::string suffix = components[components.size() - 1].substr(1);
|
|
|
|
|
|
|
|
for (const auto& file : files) {
|
|
|
|
boost::filesystem::path p(file);
|
|
|
|
std::string file_name = p.filename().string();
|
|
|
|
size_t pos = file_name.find(suffix);
|
|
|
|
if (pos != std::string::npos &&
|
|
|
|
pos + suffix.length() == file_name.length()) {
|
|
|
|
results.push_back(file);
|
|
|
|
}
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Back out if this path doesn't exist due to invalid path
|
|
|
|
if (!(pathExists(fs_path).ok())) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is the path a directory
|
|
|
|
if (boost::filesystem::is_directory(fs_path)) {
|
2015-02-21 00:55:13 +00:00
|
|
|
if(setting == REC_LIST_FOLDERS){
|
|
|
|
results.push_back(fs_path.string());
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
for (auto& file : files) {
|
|
|
|
results.push_back(file);
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status(1, "UNKNOWN FILE TYPE");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief List all files in a directory recursively
|
|
|
|
*
|
|
|
|
* This is an overloaded version of the exported `resolveFilePattern`. This
|
|
|
|
* version is used internally to facilitate the tracking of the recursion
|
|
|
|
* depth.
|
|
|
|
*
|
|
|
|
* @param results The vector where results will be returned
|
|
|
|
* @param components A path, split by forward slashes
|
|
|
|
* @param processed_index What index of components has been resolved so far
|
|
|
|
* @param rec_depth How many recursions deep the current execution is at
|
|
|
|
*
|
|
|
|
* @return An instance of osquery::Status indicating the success of failure of
|
|
|
|
* the operation
|
|
|
|
*/
|
|
|
|
Status resolveFilePattern(std::vector<std::string> components,
|
|
|
|
std::vector<std::string>& results,
|
2015-02-21 00:55:13 +00:00
|
|
|
unsigned int setting = REC_LIST_FILES,
|
2015-01-26 18:32:39 +00:00
|
|
|
unsigned int processed_index = 0,
|
|
|
|
unsigned int rec_depth = 0) {
|
2015-02-05 18:34:42 +00:00
|
|
|
|
|
|
|
// Stop recursing here if we've reached out max depth
|
|
|
|
if (rec_depth >= kMaxDirectoryTraversalDepth) {
|
|
|
|
return Status(2, "MAX_DEPTH");
|
|
|
|
}
|
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
// Handle all parts of the path except last because then we want to get files,
|
|
|
|
// not directories
|
|
|
|
for (auto i = processed_index; i < components.size() - 1; i++) {
|
2015-02-05 18:34:42 +00:00
|
|
|
|
|
|
|
// If we encounter a full recursion, that is invalid because it is not
|
|
|
|
// the last component. So return.
|
|
|
|
if (components[i] == kWildcardCharacterRecursive) {
|
|
|
|
return Status(1, kWildcardCharacterRecursive + " NOT LAST COMPONENT");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a vector to hold all the folders in the current folder
|
|
|
|
// Build the path we're at out of components
|
|
|
|
std::vector<std::string> folders;
|
|
|
|
|
|
|
|
std::string processed_path =
|
|
|
|
"/" +
|
|
|
|
boost::algorithm::join(std::vector<std::string>(components.begin(),
|
|
|
|
components.begin() + i),
|
|
|
|
"/");
|
|
|
|
Status stat = listDirectoriesInDirectory(processed_path, folders);
|
|
|
|
// If we couldn't list the directories it's probably because
|
|
|
|
// the path is invalid (or we don't have permission). Return
|
|
|
|
// here because this branch is no good. This is not an error
|
|
|
|
if (!stat.ok()) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
// If we just have a wildcard character then we will recurse though
|
|
|
|
// all folders we find
|
2015-01-26 18:32:39 +00:00
|
|
|
if (components[i] == kWildcardCharacter) {
|
2015-02-05 18:34:42 +00:00
|
|
|
for (const auto& dir : folders) {
|
|
|
|
boost::filesystem::path p(dir);
|
|
|
|
components[i] = p.filename().string();
|
|
|
|
Status stat =
|
2015-02-21 00:55:13 +00:00
|
|
|
resolveFilePattern(components, results, setting, i + 1, rec_depth + 1);
|
2015-02-05 18:34:42 +00:00
|
|
|
if (!stat.ok() && stat.getCode() == 2) {
|
|
|
|
return stat;
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
}
|
2015-02-05 18:34:42 +00:00
|
|
|
// Our subcalls that handle processing are now complete, return
|
|
|
|
return Status(0, "OK");
|
2015-01-26 18:32:39 +00:00
|
|
|
|
2015-02-05 18:34:42 +00:00
|
|
|
// The case of (.*)%
|
|
|
|
} else if (components[i].find(kWildcardCharacter, 1) != std::string::npos &&
|
|
|
|
components[i][0] != kWildcardCharacter[0]) {
|
|
|
|
std::string prefix =
|
|
|
|
processed_path + "/" +
|
|
|
|
components[i].substr(0, components[i].find(kWildcardCharacter, 1));
|
2015-01-26 18:32:39 +00:00
|
|
|
for (const auto& dir : folders) {
|
2015-02-05 18:34:42 +00:00
|
|
|
if (dir.find(prefix, 0) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
boost::filesystem::path p(dir);
|
|
|
|
components[i] = p.filename().string();
|
|
|
|
Status stat =
|
2015-02-21 00:55:13 +00:00
|
|
|
resolveFilePattern(components, results, setting, i + 1, rec_depth + 1);
|
2015-01-26 18:32:39 +00:00
|
|
|
if (!stat.ok() && stat.getCode() == 2) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
2015-02-05 18:34:42 +00:00
|
|
|
// The case of %(.*)
|
|
|
|
} else if (components[i][0] == kWildcardCharacter[0]) {
|
|
|
|
std::string suffix = components[i].substr(1);
|
|
|
|
for (const auto& dir : folders) {
|
|
|
|
boost::filesystem::path p(dir);
|
|
|
|
std::string folder_name = p.filename().string();
|
|
|
|
size_t pos = folder_name.find(suffix);
|
|
|
|
if (pos != std::string::npos &&
|
|
|
|
pos + suffix.length() == folder_name.length()) {
|
|
|
|
components[i] = p.filename().string();
|
|
|
|
Status stat =
|
2015-02-21 00:55:13 +00:00
|
|
|
resolveFilePattern(components, results, setting, i + 1, rec_depth + 1);
|
2015-02-05 18:34:42 +00:00
|
|
|
if (!stat.ok() && stat.getCode() == 2) {
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
2015-01-26 18:32:39 +00:00
|
|
|
} else {
|
|
|
|
}
|
|
|
|
}
|
2015-02-05 18:34:42 +00:00
|
|
|
|
2015-01-26 18:32:39 +00:00
|
|
|
// At this point, all of our call paths have been resolved, so know we want to
|
|
|
|
// list the files at this point or do our ** traversal
|
|
|
|
return resolveLastPathComponent("/" + boost::algorithm::join(components, "/"),
|
|
|
|
results,
|
2015-02-21 00:55:13 +00:00
|
|
|
setting,
|
2015-01-26 18:32:39 +00:00
|
|
|
components,
|
|
|
|
rec_depth);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status resolveFilePattern(const boost::filesystem::path& fs_path,
|
|
|
|
std::vector<std::string>& results) {
|
2015-02-05 18:34:42 +00:00
|
|
|
return resolveFilePattern(split(fs_path.string(), "/"), results);
|
2015-01-26 18:32:39 +00:00
|
|
|
}
|
|
|
|
|
2015-02-21 00:55:13 +00:00
|
|
|
Status resolveFilePattern(const boost::filesystem::path& fs_path,
|
|
|
|
std::vector<std::string>& results,
|
|
|
|
unsigned int setting) {
|
|
|
|
return resolveFilePattern(split(fs_path.string(), "/"), results, setting);
|
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status getDirectory(const boost::filesystem::path& path,
|
|
|
|
boost::filesystem::path& dirpath) {
|
2014-10-07 18:20:47 +00:00
|
|
|
if (!isDirectory(path).ok()) {
|
2014-10-06 21:23:26 +00:00
|
|
|
dirpath = boost::filesystem::path(path).parent_path().string();
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
dirpath = path;
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Path is a directory: " + path.string());
|
2014-10-06 21:23:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-03 20:08:46 +00:00
|
|
|
Status isDirectory(const boost::filesystem::path& path) {
|
2014-10-06 21:23:26 +00:00
|
|
|
if (boost::filesystem::is_directory(path)) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(1, "Path is not a directory: " + path.string());
|
2014-10-06 21:23:26 +00:00
|
|
|
}
|
2015-02-09 00:00:43 +00:00
|
|
|
|
|
|
|
std::vector<fs::path> getHomeDirectories() {
|
|
|
|
auto sql = SQL(
|
|
|
|
"SELECT DISTINCT directory FROM users WHERE directory != '/var/empty';");
|
|
|
|
std::vector<fs::path> results;
|
|
|
|
if (sql.ok()) {
|
|
|
|
for (const auto& row : sql.rows()) {
|
|
|
|
results.push_back(row.at("directory"));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LOG(ERROR)
|
|
|
|
<< "Error executing query to return users: " << sql.getMessageString();
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
}
|
2015-02-10 05:41:17 +00:00
|
|
|
|
|
|
|
std::string lsperms(int mode) {
|
|
|
|
static const char rwx[] = {'0', '1', '2', '3', '4', '5', '6', '7'};
|
|
|
|
std::string bits;
|
|
|
|
|
|
|
|
bits += rwx[(mode >> 9) & 7];
|
|
|
|
bits += rwx[(mode >> 6) & 7];
|
|
|
|
bits += rwx[(mode >> 3) & 7];
|
|
|
|
bits += rwx[(mode >> 0) & 7];
|
|
|
|
return bits;
|
|
|
|
}
|
2014-08-15 07:25:30 +00:00
|
|
|
}
|