2014-12-18 18:50:47 +00:00
|
|
|
/*
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2014-12-18 18:50:47 +00:00
|
|
|
* 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
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
2014-10-30 22:03:05 +00:00
|
|
|
#include <fcntl.h>
|
2016-05-17 19:39:11 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#ifndef WIN32
|
2015-06-22 07:54:19 +00:00
|
|
|
#include <glob.h>
|
2015-03-19 03:47:35 +00:00
|
|
|
#include <pwd.h>
|
2016-03-11 08:30:20 +00:00
|
|
|
#include <sys/time.h>
|
2016-05-17 19:39:11 +00:00
|
|
|
#endif
|
2014-10-30 22:03:05 +00:00
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
#include <boost/algorithm/string.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>
|
2015-04-10 23:58:11 +00:00
|
|
|
#include <boost/property_tree/json_parser.hpp>
|
2014-10-01 02:49:38 +00:00
|
|
|
|
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
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
#include "osquery/filesystem/fileops.h"
|
|
|
|
|
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;
|
2015-11-20 21:32:56 +00:00
|
|
|
namespace errc = boost::system::errc;
|
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
|
|
|
|
2015-06-30 18:48:11 +00:00
|
|
|
FLAG(uint64, read_max, 50 * 1024 * 1024, "Maximum file read size");
|
|
|
|
FLAG(uint64, read_user_max, 10 * 1024 * 1024, "Maximum non-su read size");
|
|
|
|
|
2015-12-12 02:04:43 +00:00
|
|
|
/// See reference #1382 for reasons why someone would allow unsafe.
|
2015-07-23 23:05:51 +00:00
|
|
|
HIDDEN_FLAG(bool, allow_unsafe, false, "Allow unsafe executable permissions");
|
|
|
|
|
2015-12-12 02:04:43 +00:00
|
|
|
/// Disable forensics (atime/mtime preserving) file reads.
|
2016-02-03 22:03:44 +00:00
|
|
|
HIDDEN_FLAG(bool, disable_forensic, true, "Disable atime/mtime preservation");
|
2015-12-12 02:04:43 +00:00
|
|
|
|
2015-09-29 00:50:25 +00:00
|
|
|
static const size_t kMaxRecursiveGlobs = 64;
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status writeTextFile(const fs::path& path,
|
2014-11-03 20:08:46 +00:00
|
|
|
const std::string& content,
|
|
|
|
int permissions,
|
|
|
|
bool force_permissions) {
|
2014-10-30 22:03:05 +00:00
|
|
|
// Open the file with the request permissions.
|
2016-06-07 21:08:50 +00:00
|
|
|
PlatformFile output_fd(path.string(), PF_CREATE_ALWAYS | PF_WRITE | PF_APPEND,
|
|
|
|
permissions);
|
|
|
|
if (!output_fd.isValid()) {
|
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.
|
2016-06-07 21:08:50 +00:00
|
|
|
if (!platformChmod(path.string(), permissions)) {
|
2014-10-30 22:03:05 +00:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
ssize_t bytes = output_fd.write(content.c_str(), content.size());
|
2015-10-16 16:04:33 +00:00
|
|
|
if (static_cast<size_t>(bytes) != content.size()) {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
2015-10-24 12:06:58 +00:00
|
|
|
struct OpenReadableFile {
|
|
|
|
public:
|
2016-06-07 21:08:50 +00:00
|
|
|
explicit OpenReadableFile(const fs::path &path) {
|
|
|
|
#ifndef WIN32
|
2015-10-30 00:53:26 +00:00
|
|
|
dropper_ = DropPrivileges::get();
|
|
|
|
if (dropper_->dropToParent(path)) {
|
2016-06-07 21:08:50 +00:00
|
|
|
#endif
|
2015-10-30 00:53:26 +00:00
|
|
|
// Open the file descriptor and allow caller to perform error checking.
|
2016-06-07 21:08:50 +00:00
|
|
|
fd.reset(new PlatformFile(path.string(),
|
|
|
|
PF_OPEN_EXISTING | PF_READ | PF_NONBLOCK));
|
|
|
|
#ifndef WIN32
|
2015-10-24 12:06:58 +00:00
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
#endif
|
2015-10-24 12:06:58 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
~OpenReadableFile() {}
|
2015-07-15 20:47:02 +00:00
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
std::unique_ptr<PlatformFile> fd{nullptr};
|
2015-10-30 00:53:26 +00:00
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
#ifndef WIN32
|
2015-10-30 00:53:26 +00:00
|
|
|
private:
|
|
|
|
DropPrivilegesRef dropper_{nullptr};
|
2016-06-07 21:08:50 +00:00
|
|
|
#endif
|
2015-10-24 12:06:58 +00:00
|
|
|
};
|
|
|
|
|
2015-12-12 02:04:43 +00:00
|
|
|
Status readFile(
|
|
|
|
const fs::path& path,
|
|
|
|
size_t size,
|
|
|
|
size_t block_size,
|
|
|
|
bool dry_run,
|
|
|
|
bool preserve_time,
|
|
|
|
std::function<void(std::string& buffer, size_t size)> predicate) {
|
2016-06-07 21:08:50 +00:00
|
|
|
OpenReadableFile handle(path);
|
|
|
|
if (!handle.fd->isValid()) {
|
2015-10-24 12:06:58 +00:00
|
|
|
return Status(1, "Cannot open file for reading: " + path.string());
|
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
off_t file_size = handle.fd->size();
|
|
|
|
if (handle.fd->isSpecialFile() && size > 0) {
|
2015-10-24 12:06:58 +00:00
|
|
|
file_size = static_cast<off_t>(size);
|
2015-06-30 18:48:11 +00:00
|
|
|
}
|
|
|
|
|
2015-10-28 07:34:07 +00:00
|
|
|
// Apply the max byte-read based on file/link target ownership.
|
2016-06-07 21:08:50 +00:00
|
|
|
off_t read_max = (handle.fd->isOwnerRoot().ok())
|
2015-10-28 07:34:07 +00:00
|
|
|
? FLAGS_read_max
|
|
|
|
: std::min(FLAGS_read_max, FLAGS_read_user_max);
|
2015-10-24 12:06:58 +00:00
|
|
|
if (file_size > read_max) {
|
|
|
|
VLOG(1) << "Cannot read " << path << " size exceeds limit: " << file_size
|
2015-07-16 18:10:58 +00:00
|
|
|
<< " > " << read_max;
|
2015-06-30 18:48:11 +00:00
|
|
|
return Status(1, "File exceeds read limits");
|
|
|
|
}
|
|
|
|
|
2015-07-14 19:50:13 +00:00
|
|
|
if (dry_run) {
|
|
|
|
// The caller is only interested in performing file read checks.
|
|
|
|
boost::system::error_code ec;
|
|
|
|
return Status(0, fs::canonical(path, ec).string());
|
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
PlatformTime times;
|
|
|
|
handle.fd->getFileTimes(times);
|
2015-12-12 02:04:43 +00:00
|
|
|
|
2015-10-28 07:34:07 +00:00
|
|
|
if (file_size == 0) {
|
|
|
|
off_t total_bytes = 0;
|
|
|
|
ssize_t part_bytes = 0;
|
|
|
|
do {
|
|
|
|
auto part = std::string(4096, '\0');
|
2016-06-07 21:08:50 +00:00
|
|
|
part_bytes = handle.fd->read(&part[0], block_size);
|
2015-10-28 07:34:07 +00:00
|
|
|
if (part_bytes > 0) {
|
|
|
|
total_bytes += part_bytes;
|
|
|
|
if (total_bytes >= read_max) {
|
|
|
|
return Status(1, "File exceeds read limits");
|
|
|
|
}
|
2015-12-12 02:04:43 +00:00
|
|
|
// content += part.substr(0, part_bytes);
|
|
|
|
predicate(part, part_bytes);
|
2015-10-28 07:34:07 +00:00
|
|
|
}
|
|
|
|
} while (part_bytes > 0);
|
|
|
|
} else {
|
2015-12-12 02:04:43 +00:00
|
|
|
auto content = std::string(file_size, '\0');
|
2016-06-07 21:08:50 +00:00
|
|
|
handle.fd->read(&content[0], file_size);
|
2015-12-12 02:04:43 +00:00
|
|
|
predicate(content, file_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to restore the atime and mtime before the file read.
|
|
|
|
if (preserve_time && !FLAGS_disable_forensic) {
|
2016-06-07 21:08:50 +00:00
|
|
|
handle.fd->setFileTimes(times);
|
2015-10-28 07:34:07 +00:00
|
|
|
}
|
2015-01-26 08:02:02 +00:00
|
|
|
return Status(0, "OK");
|
2014-08-04 18:06:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-12 02:04:43 +00:00
|
|
|
Status readFile(const fs::path& path,
|
|
|
|
std::string& content,
|
|
|
|
size_t size,
|
|
|
|
bool dry_run,
|
|
|
|
bool preserve_time) {
|
|
|
|
return readFile(path,
|
|
|
|
size,
|
|
|
|
4096,
|
|
|
|
dry_run,
|
|
|
|
preserve_time,
|
|
|
|
([&content](std::string& buffer, size_t size) {
|
|
|
|
if (buffer.size() == size) {
|
|
|
|
content += std::move(buffer);
|
|
|
|
} else {
|
2015-12-14 23:24:55 +00:00
|
|
|
content += buffer.substr(0, size);
|
2015-12-12 02:04:43 +00:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2015-07-14 19:50:13 +00:00
|
|
|
Status readFile(const fs::path& path) {
|
|
|
|
std::string blank;
|
2015-12-12 02:04:43 +00:00
|
|
|
return readFile(path, blank, 0, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status forensicReadFile(const fs::path& path, std::string& content) {
|
|
|
|
return readFile(path, content, 0, false, true);
|
2015-07-14 19:50:13 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status isWritable(const fs::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
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
if (platformAccess(path.string(), W_OK) == 0) {
|
2014-10-27 18:55:28 +00:00
|
|
|
return Status(0, "OK");
|
2014-10-27 01:39:03 +00:00
|
|
|
}
|
2016-06-07 21:08:50 +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
|
|
|
}
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status isReadable(const fs::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
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
if (platformAccess(path.string(), R_OK) == 0) {
|
2014-10-29 09:24:00 +00:00
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status pathExists(const fs::path& path) {
|
2015-11-20 21:32:56 +00:00
|
|
|
boost::system::error_code ec;
|
2014-11-03 20:08:46 +00:00
|
|
|
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
|
2015-11-20 21:32:56 +00:00
|
|
|
if (!fs::exists(path, ec) || ec.value() != errc::success) {
|
|
|
|
return Status(1, ec.message());
|
2014-09-09 17:56:48 +00:00
|
|
|
}
|
|
|
|
return Status(0, "1");
|
|
|
|
}
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status remove(const fs::path& path) {
|
2015-02-04 03:55:16 +00:00
|
|
|
auto status_code = std::remove(path.string().c_str());
|
|
|
|
return Status(status_code, "N/A");
|
|
|
|
}
|
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
static void genGlobs(std::string path,
|
|
|
|
std::vector<std::string>& results,
|
|
|
|
GlobLimits limits) {
|
2015-07-06 03:42:35 +00:00
|
|
|
// Use our helped escape/replace for wildcards.
|
2016-02-17 07:10:08 +00:00
|
|
|
replaceGlobWildcards(path, limits);
|
2015-06-22 07:54:19 +00:00
|
|
|
|
|
|
|
// Generate a glob set and recurse for double star.
|
2015-09-29 00:50:25 +00:00
|
|
|
size_t glob_index = 0;
|
|
|
|
while (++glob_index < kMaxRecursiveGlobs) {
|
2016-06-07 21:08:50 +00:00
|
|
|
auto glob_results = platformGlob(path);
|
|
|
|
|
|
|
|
for (auto const& result_path : glob_results) {
|
|
|
|
results.push_back(result_path);
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
// The end state is a non-recursive ending or empty set of matches.
|
|
|
|
size_t wild = path.rfind("**");
|
|
|
|
// Allow a trailing slash after the double wild indicator.
|
2016-06-07 21:08:50 +00:00
|
|
|
if (glob_results.size() == 0 || wild > path.size() ||
|
|
|
|
wild < path.size() - 3) {
|
2015-06-22 07:54:19 +00:00
|
|
|
break;
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
2015-06-22 07:54:19 +00:00
|
|
|
path += "/**";
|
2015-03-17 18:52:56 +00:00
|
|
|
}
|
2014-08-14 23:27:20 +00:00
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
// Prune results based on settings/requested glob limitations.
|
2016-06-07 21:08:50 +00:00
|
|
|
auto end = std::remove_if(results.begin(), results.end(),
|
|
|
|
[limits](const std::string &found) {
|
|
|
|
return !(((found[found.length() - 1] == '/' ||
|
|
|
|
found[found.length() - 1] == '\\') &&
|
|
|
|
limits & GLOB_FOLDERS) ||
|
|
|
|
((found[found.length() - 1] != '/' &&
|
|
|
|
found[found.length() - 1] != '\\') &&
|
|
|
|
limits & GLOB_FILES));
|
|
|
|
});
|
2015-06-22 07:54:19 +00:00
|
|
|
results.erase(end, results.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
Status resolveFilePattern(const fs::path& fs_path,
|
|
|
|
std::vector<std::string>& results) {
|
|
|
|
return resolveFilePattern(fs_path, results, GLOB_ALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status resolveFilePattern(const fs::path& fs_path,
|
|
|
|
std::vector<std::string>& results,
|
|
|
|
GlobLimits setting) {
|
|
|
|
genGlobs(fs_path.string(), results, setting);
|
2015-03-17 18:52:56 +00:00
|
|
|
return Status(0, "OK");
|
2014-08-14 23:27:20 +00:00
|
|
|
}
|
2014-10-01 02:49:38 +00:00
|
|
|
|
2016-02-17 07:10:08 +00:00
|
|
|
inline void replaceGlobWildcards(std::string& pattern, GlobLimits limits) {
|
2015-07-06 03:42:35 +00:00
|
|
|
// Replace SQL-wildcard '%' with globbing wildcard '*'.
|
|
|
|
if (pattern.find("%") != std::string::npos) {
|
|
|
|
boost::replace_all(pattern, "%", "*");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Relative paths are a bad idea, but we try to accommodate.
|
2016-06-07 21:08:50 +00:00
|
|
|
if ((pattern.size() == 0 || ((pattern[0] != '/' && pattern[0] != '\\') &&
|
|
|
|
(pattern.size() > 3 && pattern[1] != ':' && pattern[2] != '\\' &&
|
|
|
|
pattern[2] != '/'))) &&
|
|
|
|
pattern[0] != '~') {
|
|
|
|
pattern = (fs::initial_path() / pattern).make_preferred().string();
|
2015-07-06 03:42:35 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 21:08:50 +00:00
|
|
|
auto base =
|
|
|
|
fs::path(pattern.substr(0, pattern.find('*'))).make_preferred().string();
|
|
|
|
|
2015-07-06 03:42:35 +00:00
|
|
|
if (base.size() > 0) {
|
|
|
|
boost::system::error_code ec;
|
2016-02-17 07:10:08 +00:00
|
|
|
auto canonicalized = ((limits & GLOB_NO_CANON) == 0)
|
2016-06-07 21:08:50 +00:00
|
|
|
? fs::canonical(base, ec).make_preferred().string()
|
2016-02-17 07:10:08 +00:00
|
|
|
: base;
|
2016-06-07 21:08:50 +00:00
|
|
|
|
2015-07-06 03:42:35 +00:00
|
|
|
if (canonicalized.size() > 0 && canonicalized != base) {
|
|
|
|
if (isDirectory(canonicalized)) {
|
2015-07-15 20:47:02 +00:00
|
|
|
// Canonicalized directory paths will not include a trailing '/'.
|
|
|
|
// However, if the wildcards are applied to files within a directory
|
|
|
|
// then the missing '/' changes the wildcard meaning.
|
2015-07-06 03:42:35 +00:00
|
|
|
canonicalized += '/';
|
|
|
|
}
|
|
|
|
// We are unable to canonicalize the meaning of post-wildcard limiters.
|
2016-06-07 21:08:50 +00:00
|
|
|
pattern = fs::path(canonicalized + pattern.substr(base.size()))
|
|
|
|
.make_preferred()
|
|
|
|
.string();
|
2015-07-06 03:42:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
inline Status listInAbsoluteDirectory(const fs::path& path,
|
|
|
|
std::vector<std::string>& results,
|
|
|
|
GlobLimits limits) {
|
2015-11-20 21:32:56 +00:00
|
|
|
if (path.filename() == "*" && !pathExists(path.parent_path())) {
|
|
|
|
return Status(1, "Directory not found: " + path.parent_path().string());
|
|
|
|
}
|
2015-01-26 18:32:39 +00:00
|
|
|
|
2015-11-20 21:32:56 +00:00
|
|
|
if (path.filename() == "*" && !isDirectory(path.parent_path())) {
|
|
|
|
return Status(1, "Path not a directory: " + path.parent_path().string());
|
2015-03-17 18:52:56 +00:00
|
|
|
}
|
2015-11-20 21:32:56 +00:00
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
genGlobs(path.string(), results, limits);
|
2015-03-17 18:52:56 +00:00
|
|
|
return Status(0, "OK");
|
2015-01-26 18:32:39 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 07:54:19 +00:00
|
|
|
Status listFilesInDirectory(const fs::path& path,
|
|
|
|
std::vector<std::string>& results,
|
2015-10-30 06:18:54 +00:00
|
|
|
bool recursive) {
|
|
|
|
return listInAbsoluteDirectory(
|
|
|
|
(path / ((recursive) ? "**" : "*")), results, GLOB_FILES);
|
2015-06-22 07:54:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status listDirectoriesInDirectory(const fs::path& path,
|
|
|
|
std::vector<std::string>& results,
|
2015-10-30 06:18:54 +00:00
|
|
|
bool recursive) {
|
|
|
|
return listInAbsoluteDirectory(
|
|
|
|
(path / ((recursive) ? "**" : "*")), results, GLOB_FOLDERS);
|
2014-10-06 21:23:26 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 05:34:22 +00:00
|
|
|
Status isDirectory(const fs::path& path) {
|
2015-07-06 03:42:35 +00:00
|
|
|
boost::system::error_code ec;
|
|
|
|
if (fs::is_directory(path, ec)) {
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2015-11-20 21:32:56 +00:00
|
|
|
|
|
|
|
// The success error code is returned for as a failure (undefined error)
|
|
|
|
// We need to flip that into an error, a success would have falling through
|
|
|
|
// in the above conditional.
|
|
|
|
if (ec.value() == errc::success) {
|
2015-03-02 05:15:42 +00:00
|
|
|
return Status(1, "Path is not a directory: " + path.string());
|
2014-10-06 21:23:26 +00:00
|
|
|
}
|
2015-07-06 03:42:35 +00:00
|
|
|
return Status(ec.value(), ec.message());
|
2014-10-06 21:23:26 +00:00
|
|
|
}
|
2015-02-09 00:00:43 +00:00
|
|
|
|
2015-03-02 05:15:42 +00:00
|
|
|
std::set<fs::path> getHomeDirectories() {
|
|
|
|
std::set<fs::path> results;
|
|
|
|
|
|
|
|
auto users = SQL::selectAllFrom("users");
|
|
|
|
for (const auto& user : users) {
|
|
|
|
if (user.at("directory").size() > 0) {
|
|
|
|
results.insert(user.at("directory"));
|
2015-02-09 00:00:43 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-02 05:15:42 +00:00
|
|
|
|
2015-02-09 00:00:43 +00:00
|
|
|
return results;
|
|
|
|
}
|
2015-02-10 05:41:17 +00:00
|
|
|
|
2015-03-13 15:11:08 +00:00
|
|
|
bool safePermissions(const std::string& dir,
|
|
|
|
const std::string& path,
|
|
|
|
bool executable) {
|
2016-06-07 21:08:50 +00:00
|
|
|
if (!platformIsFileAccessible(path).ok()) {
|
2015-03-04 16:45:21 +00:00
|
|
|
// Path was not real, had too may links, or could not be accessed.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-23 23:05:51 +00:00
|
|
|
if (FLAGS_allow_unsafe) {
|
|
|
|
return true;
|
2016-06-07 21:08:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status result = platformIsTmpDir(dir);
|
|
|
|
if (!result.ok() && result.getCode() < 0) {
|
|
|
|
// An error has occurred in stat() on dir, most likely because the file path
|
|
|
|
// does not exist
|
|
|
|
return false;
|
|
|
|
} else if (result.ok()) {
|
2015-03-04 16:45:21 +00:00
|
|
|
// Do not load modules from /tmp-like directories.
|
|
|
|
return false;
|
2016-06-07 21:08:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PlatformFile fd(path, PF_OPEN_EXISTING | PF_READ);
|
|
|
|
if (!fd.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = isDirectory(path);
|
|
|
|
if (!result.ok() && result.getCode() < 0) {
|
|
|
|
// Something went wrong when determining the file's directoriness
|
|
|
|
return false;
|
|
|
|
} else if (result.ok()) {
|
2015-03-04 16:45:21 +00:00
|
|
|
// Only load file-like nodes (not directories).
|
|
|
|
return false;
|
2016-06-07 21:08:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fd.isOwnerCurrentUser().ok() || fd.isOwnerRoot().ok()) {
|
|
|
|
result = fd.isExecutable();
|
|
|
|
|
2015-03-04 16:45:21 +00:00
|
|
|
// Otherwise, require matching or root file ownership.
|
2016-06-07 21:08:50 +00:00
|
|
|
if (executable && (result.getCode() > 0 || !fd.isNonWritable().ok())) {
|
2015-03-13 15:11:08 +00:00
|
|
|
// Require executable, implies by the owner.
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|
2015-03-04 16:45:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|
2015-03-04 16:45:21 +00:00
|
|
|
// Do not load modules not owned by the user.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-19 03:47:35 +00:00
|
|
|
const std::string& osqueryHomeDirectory() {
|
|
|
|
static std::string homedir;
|
2016-05-17 19:39:11 +00:00
|
|
|
|
2015-03-19 03:47:35 +00:00
|
|
|
if (homedir.size() == 0) {
|
2016-06-07 21:08:50 +00:00
|
|
|
// Try to get the caller's home directory
|
|
|
|
auto home_directory = getHomeDirectory();
|
|
|
|
if (home_directory.is_initialized() && isWritable(*home_directory).ok()) {
|
|
|
|
homedir =
|
|
|
|
(fs::path(*home_directory) / ".osquery").make_preferred().string();
|
2015-03-19 03:47:35 +00:00
|
|
|
} else {
|
2015-07-06 03:42:35 +00:00
|
|
|
// Fail over to a temporary directory (used for the shell).
|
2016-06-07 21:08:50 +00:00
|
|
|
homedir = (fs::temp_directory_path() / "osquery").make_preferred().string();
|
2015-03-19 03:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|
2015-03-19 03:47:35 +00:00
|
|
|
return homedir;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2015-04-10 23:58:11 +00:00
|
|
|
|
2015-05-03 20:37:11 +00:00
|
|
|
Status parseJSON(const fs::path& path, pt::ptree& tree) {
|
2015-04-10 23:58:11 +00:00
|
|
|
std::string json_data;
|
|
|
|
if (!readFile(path, json_data).ok()) {
|
|
|
|
return Status(1, "Could not read JSON from file");
|
|
|
|
}
|
|
|
|
|
|
|
|
return parseJSONContent(json_data, tree);
|
|
|
|
}
|
|
|
|
|
2015-05-03 20:37:11 +00:00
|
|
|
Status parseJSONContent(const std::string& content, pt::ptree& tree) {
|
2015-04-10 23:58:11 +00:00
|
|
|
// Read the extensions data into a JSON blob, then property tree.
|
|
|
|
try {
|
2015-05-03 20:37:11 +00:00
|
|
|
std::stringstream json_stream;
|
|
|
|
json_stream << content;
|
2015-04-10 23:58:11 +00:00
|
|
|
pt::read_json(json_stream, tree);
|
|
|
|
} catch (const pt::json_parser::json_parser_error& e) {
|
|
|
|
return Status(1, "Could not parse JSON from file");
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2014-08-15 07:25:30 +00:00
|
|
|
}
|
2016-06-07 21:08:50 +00:00
|
|
|
|