# See the License for the specific language governing permissions and
# limitations under the License
-ADD_OSQUERY_LIBRARY(osquery_core flags.cpp
- tables.cpp
+ADD_OSQUERY_LIBRARY(osquery_core tables.cpp
init.cpp
query.cpp
system.cpp
+++ /dev/null
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed in accordance with the terms specified in
- * the LICENSE file found in the root directory of this source tree.
- */
-
-#include <osquery/flagalias.h>
-#include <osquery/flags.h>
-#include <osquery/registry.h>
-#include <osquery/utils/conversions/tryto.h>
-
-namespace boost {
-template <>
-bool lexical_cast<bool, std::string>(const std::string& arg) {
- std::istringstream ss(arg);
- bool b;
- ss >> std::boolalpha >> b;
- return b;
-}
-
-template <>
-std::string lexical_cast<std::string, bool>(const bool& b) {
- std::ostringstream ss;
- ss << std::boolalpha << b;
- return ss.str();
-}
-}
-
-namespace flags = GFLAGS_NAMESPACE;
-
-namespace osquery {
-
-Flag& Flag::instance() {
- static Flag f;
- return f;
-}
-
-int Flag::create(const std::string& name, const FlagDetail& flag) {
- instance().flags_.insert(std::make_pair(name, flag));
- return 0;
-}
-
-int Flag::createAlias(const std::string& alias, const FlagDetail& flag) {
- instance().aliases_.insert(std::make_pair(alias, flag));
- return 0;
-}
-
-Status Flag::getDefaultValue(const std::string& name, std::string& value) {
- flags::CommandLineFlagInfo info;
- if (!flags::GetCommandLineFlagInfo(name.c_str(), &info)) {
- return Status(1, "Flags name not found.");
- }
-
- value = info.default_value;
- return Status::success();
-}
-
-bool Flag::isDefault(const std::string& name) {
- flags::CommandLineFlagInfo info;
- if (!flags::GetCommandLineFlagInfo(name.c_str(), &info)) {
- return false;
- }
-
- return info.is_default;
-}
-
-std::string Flag::getValue(const std::string& name) {
- const auto& custom = instance().custom_;
- auto custom_flag = custom.find(name);
- if (custom_flag != custom.end()) {
- return custom_flag->second;
- }
-
- std::string current_value;
- auto found = flags::GetCommandLineOption(name.c_str(), ¤t_value);
-
- return current_value;
-}
-
-long int Flag::getInt32Value(const std::string& name) {
- return tryTo<long int>(Flag::getValue(name), 10).takeOr(0l);
-}
-
-std::string Flag::getType(const std::string& name) {
- flags::CommandLineFlagInfo info;
- if (!flags::GetCommandLineFlagInfo(name.c_str(), &info)) {
- return "";
- }
- return info.type;
-}
-
-std::string Flag::getDescription(const std::string& name) {
- if (instance().flags_.count(name)) {
- return instance().flags_.at(name).description;
- }
-
- if (instance().aliases_.count(name)) {
- return getDescription(instance().aliases_.at(name).description);
- }
- return "";
-}
-
-Status Flag::updateValue(const std::string& name, const std::string& value) {
- if (instance().flags_.count(name) > 0) {
- flags::SetCommandLineOption(name.c_str(), value.c_str());
- return Status::success();
- } else if (instance().aliases_.count(name) > 0) {
- // Updating a flag by an alias name.
- auto& real_name = instance().aliases_.at(name).description;
- flags::SetCommandLineOption(real_name.c_str(), value.c_str());
- return Status::success();
- } else if (name.find("custom_") == 0) {
- instance().custom_[name] = value;
- }
- return Status(1, "Flag not found");
-}
-
-std::map<std::string, FlagInfo> Flag::flags() {
- std::vector<flags::CommandLineFlagInfo> info;
- flags::GetAllFlags(&info);
-
- std::map<std::string, FlagInfo> flags;
- for (const auto& flag : info) {
- if (instance().flags_.count(flag.name) == 0) {
- // This flag info was not defined within osquery.
- continue;
- }
-
- // Set the flag info from the internal info kept by Gflags, except for
- // the stored description. Gflag keeps an "unknown" value if the flag
- // was declared without a definition.
- flags[flag.name] = {flag.type,
- instance().flags_.at(flag.name).description,
- flag.default_value,
- flag.current_value,
- instance().flags_.at(flag.name)};
- }
- for (const auto& flag : instance().custom_) {
- flags[flag.first] = {"string", "", "", flag.second, {}};
- }
- return flags;
-}
-
-void Flag::printFlags(bool shell, bool external, bool cli) {
- std::vector<flags::CommandLineFlagInfo> info;
- flags::GetAllFlags(&info);
- auto& details = instance().flags_;
-
- std::map<std::string, const flags::CommandLineFlagInfo*> ordered_info;
- for (const auto& flag : info) {
- ordered_info[flag.name] = &flag;
- }
-
- // Determine max indent needed for all flag names.
- size_t max = 0;
- for (const auto& flag : details) {
- max = (max > flag.first.size()) ? max : flag.first.size();
- }
- // Additional index for flag values.
- max += 6;
-
- // Show the Gflags-specific 'flagfile'.
- if (!shell && cli) {
- fprintf(stdout, " --flagfile PATH");
- fprintf(stdout, "%s", std::string(max - 8 - 5, ' ').c_str());
- fprintf(stdout, " Line-delimited file of additional flags\n");
- }
-
- auto& aliases = instance().aliases_;
- for (const auto& flag : ordered_info) {
- if (details.count(flag.second->name) > 0) {
- const auto& detail = details.at(flag.second->name);
- if ((shell && !detail.shell) || (!shell && detail.shell) ||
- (external && !detail.external) || (!external && detail.external) ||
- (cli && !detail.cli) || (!cli && detail.cli) || detail.hidden) {
- continue;
- }
- } else if (aliases.count(flag.second->name) > 0) {
- const auto& alias = aliases.at(flag.second->name);
- // Aliases are only printed if this is an external tool and the alias
- // is external.
- if (!alias.external || !external) {
- continue;
- }
- } else {
- // This flag was not defined as an osquery flag or flag alias.
- continue;
- }
-
- fprintf(stdout, " --%s", flag.second->name.c_str());
-
- int pad = static_cast<int>(max);
- if (flag.second->type != "bool") {
- fprintf(stdout, " VALUE");
- pad -= 6;
- }
- pad -= static_cast<int>(flag.second->name.size());
-
- if (pad > 0 && pad < 80) {
- // Never pad more than 80 characters.
- fprintf(stdout, "%s", std::string(pad, ' ').c_str());
- }
- fprintf(stdout, " %s\n", getDescription(flag.second->name).c_str());
- }
-}
-}
#include <osquery/core.h>
#include <osquery/data_logger.h>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/registry.h>
#include <osquery/utils/info/version.h>
#include <osquery/utils/system/time.h>
#define OPTIONS_CLI "osquery%s command line flags:\n\n"
#define USAGE "Usage: %s [OPTION]... %s\n\n"
-namespace osquery {
-CLI_FLAG(uint64, alarm_timeout, 4, "Seconds to wait for a graceful shutdown");
-CLI_FLAG(bool,
- enable_signal_handler,
- false,
- "Enable custom osquery signals handler instead of default one");
-}
-
namespace {
extern "C" {
static inline bool hasWorkerVariable() {
if (num == SIGTERM || num == SIGINT || num == SIGABRT ||
num == SIGUSR1) {
-#ifndef WIN32
- // Time to stop, set an upper bound time constraint on how long threads
- // have to terminate (join). Publishers may be in 20ms or similar sleeps.
- alarm(osquery::FLAGS_alarm_timeout);
-
- // Allow the OS to auto-reap our child processes.
- std::signal(SIGCHLD, SIG_IGN);
-#endif
-
// Restore the default signal handler.
std::signal(num, SIG_DFL);
}
}
-
-#ifndef WIN32
- if (num == SIGALRM) {
- // Restore the default signal handler for SIGALRM.
- std::signal(SIGALRM, SIG_DFL);
-
- // Took too long to stop.
- VLOG(1) << "Cannot stop event publisher threads or services";
- raise((kHandledSignal != 0) ? kHandledSignal : SIGALRM);
- }
-#endif
-
}
}
}
namespace fs = boost::filesystem;
-DECLARE_string(flagfile);
-
namespace osquery {
-DECLARE_string(logger_plugin);
-DECLARE_bool(config_check);
-DECLARE_bool(config_dump);
-DECLARE_bool(disable_logging);
-
-CLI_FLAG(bool, S, false, "Run as a shell process");
-CLI_FLAG(bool, D, false, "Run as a daemon process");
-CLI_FLAG(bool, daemonize, false, "Attempt to daemonize (POSIX only)");
-
ToolType kToolType{ToolType::UNKNOWN};
/// The saved exit code from a thread's request to stop the process.
/// Legacy thread ID to ensure that the windows service waits before exiting
unsigned long kLegacyThreadId;
-/// When no flagfile is provided via CLI, attempt to read flag 'defaults'.
-const std::string kBackupDefaultFlagfile{OSQUERY_HOME "osquery.flags.default"};
-
std::function<void()> Initializer::shutdown_{nullptr};
RecursiveMutex Initializer::shutdown_mutex_;
fprintf(stdout, USAGE, binary.c_str(), "");
}
- fprintf(stdout, OPTIONS_CLI, "");
- Flag::printFlags(false, false, true);
- fprintf(stdout, OPTIONS);
- Flag::printFlags();
-
- if (tool == ToolType::SHELL) {
- // Print shell flags.
- fprintf(stdout, OPTIONS_SHELL);
- Flag::printFlags(true);
- }
-
fprintf(stdout, EPILOG);
}
// The 'main' thread is that which executes the initializer.
kMainThreadId = std::this_thread::get_id();
-#ifndef WIN32
- // Set the max number of open files.
- struct rlimit nofiles;
- if (getrlimit(RLIMIT_NOFILE, &nofiles) == 0) {
- if (nofiles.rlim_cur < 1024 || nofiles.rlim_max < 1024) {
- nofiles.rlim_cur = (nofiles.rlim_cur < 1024) ? 1024 : nofiles.rlim_cur;
- nofiles.rlim_max = (nofiles.rlim_max < 1024) ? 1024 : nofiles.rlim_max;
- setrlimit(RLIMIT_NOFILE, &nofiles);
- }
- }
-#endif
-
- Flag::create("logtostderr",
- {"Log messages to stderr in addition to the logger plugin(s)",
- false,
- false,
- true,
- false});
- Flag::create("stderrthreshold",
- {"Stderr log level threshold", false, false, true, false});
-
- // osquery implements a custom help/usage output.
- bool default_flags = true;
- for (int i = 1; i < *argc_; i++) {
- auto help = std::string((*argv_)[i]);
- if (help == "-S" || help == "--S") {
- kToolType = ToolType::SHELL;
- binary_ = "osqueryi";
- } else if (help == "-D" || help == "--D") {
- kToolType = ToolType::DAEMON;
- binary_ = "osqueryd";
- } else if ((help == "--help" || help == "-help" || help == "--h" ||
- help == "-h") &&
- tool != ToolType::TEST) {
- printUsage(binary_, kToolType);
- shutdown();
- }
- if (help.find("--flagfile") == 0) {
- default_flags = false;
- }
- }
-
- if (isShell()) {
- // The shell is transient, rewrite config-loaded paths.
- FLAGS_disable_logging = true;
- // The shell never will not fork a worker.
- }
-
- if (default_flags && isReadable(kBackupDefaultFlagfile)) {
- // No flagfile was set (daemons and services always set a flagfile).
- FLAGS_flagfile = kBackupDefaultFlagfile;
- } else {
- // No flagfile was set, but no default flags exist.
- default_flags = false;
- }
-
- // Set version string from CMake build
- GFLAGS_NAMESPACE::SetVersionString(kVersion.c_str());
-
- // Let gflags parse the non-help options/flags.
- GFLAGS_NAMESPACE::ParseCommandLineFlags(argc_, argv_, isShell());
-
- // Initialize registries and plugins
- registryAndPluginInit();
-
- if (isShell()) {
- // Initialize the shell after setting modified defaults and parsing flags.
- initShell();
- }
-
- if (FLAGS_enable_signal_handler) {
- std::signal(SIGABRT, signalHandler);
- std::signal(SIGUSR1, signalHandler);
-
- // All tools handle the same set of signals.
- // If a daemon process is a watchdog the signal is passed to the worker,
- // unless the worker has not yet started.
- if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
- std::signal(SIGTERM, signalHandler);
- std::signal(SIGINT, signalHandler);
- std::signal(SIGHUP, signalHandler);
- std::signal(SIGALRM, signalHandler);
- }
- }
-
// Initialize the COM libs
platformSetup();
}
return;
}
-#if !defined(__APPLE__) && !defined(WIN32)
- // OS X uses launchd to daemonize.
- if (osquery::FLAGS_daemonize) {
- if (daemon(0, 0) == -1) {
- shutdown(EXIT_FAILURE);
- }
- }
-#endif
-
// Print the version to the OS system log.
systemLog(binary_ + " started [version=" + kVersion + "]");
}
void Initializer::initShell() const {
- // Get the caller's home dir for temporary storage/state management.
- auto homedir = osqueryHomeDirectory();
- if (Flag::isDefault("hash_delay")) {
- // The hash_delay is designed for daemons only.
- Flag::updateValue("hash_delay", "0");
- }
}
void Initializer::initWorker(const std::string& name) const {
void Initializer::start() const {
// Run the setup for all lazy registries (tables, SQL).
Registry::setUp();
-
- // Initialize the status and result plugin logger.
- if (!FLAGS_disable_logging) {
- initActivePlugin("logger", FLAGS_logger_plugin);
- initLogger(binary_);
- }
}
void Initializer::waitForShutdown() {
}
}
- // Hopefully release memory used by global string constructors in gflags.
- GFLAGS_NAMESPACE::ShutDownCommandLineFlags();
-
auto excode = (kExitCode != 0) ? kExitCode : EXIT_SUCCESS;
exit(excode);
}
if (kExitCode == 0) {
kExitCode = retcode;
}
-
- // Stop thrift services/clients/and their thread pools.
- if (std::this_thread::get_id() != kMainThreadId &&
- FLAGS_enable_signal_handler) {
- raise(SIGUSR1);
- } else {
- // The main thread is requesting a shutdown, meaning in almost every case
- // it is NOT waiting for a shutdown.
- // Exceptions include: tight request / wait in an exception handler or
- // custom signal handling.
- waitForShutdown();
- }
}
void Initializer::requestShutdown(int retcode, const std::string& system_log) {
#include <string>
#include <vector>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/query.h>
namespace osquery {
-/// Log numeric values as numbers (in JSON syntax)
-FLAG(bool,
- log_numerics_as_numbers,
- false,
- "Use numeric JSON syntax for numeric values");
-
uint64_t Query::getPreviousEpoch() const {
return 0;
}
doc.add("epoch", static_cast<size_t>(item.epoch), obj);
doc.add("counter", static_cast<size_t>(item.counter), obj);
- // Apply field indicatiting if numerics are serialized as numbers
- doc.add("logNumericsAsNumbers", FLAGS_log_numerics_as_numbers, obj);
-
// Append the decorations.
if (!item.decorations.empty()) {
auto dec_obj = doc.getObject();
if (item.results.added.size() > 0 || item.results.removed.size() > 0) {
auto obj = doc.getObject();
auto status = serializeDiffResults(
- item.results, doc, obj, FLAGS_log_numerics_as_numbers);
+ item.results, doc, obj, 0);
if (!status.ok()) {
return status;
}
} else {
auto arr = doc.getArray();
auto status = serializeQueryData(
- item.snapshot_results, doc, arr, FLAGS_log_numerics_as_numbers);
+ item.snapshot_results, doc, arr, 0);
if (!status.ok()) {
return status;
}
auto temp_doc = JSON::newObject();
if (!item.results.added.empty() || !item.results.removed.empty()) {
auto status = serializeDiffResults(
- item.results, temp_doc, temp_doc.doc(), FLAGS_log_numerics_as_numbers);
+ item.results, temp_doc, temp_doc.doc(), 0);
if (!status.ok()) {
return status;
}
} else if (!item.snapshot_results.empty()) {
auto arr = doc.getArray();
auto status = serializeQueryData(
- item.snapshot_results, temp_doc, arr, FLAGS_log_numerics_as_numbers);
+ item.snapshot_results, temp_doc, arr, 0);
if (!status.ok()) {
return status;
}
#include <osquery/core.h>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/system.h>
namespace osquery {
-DECLARE_uint64(alarm_timeout);
-
-/// The path to the pidfile for osqueryd
-CLI_FLAG(string,
- pidfile,
- OSQUERY_PIDFILE "osqueryd.pidfile",
- "Path to the daemon pidfile mutex");
-
-/// Should the daemon force unload previously-running osqueryd daemons.
-CLI_FLAG(bool,
- force,
- false,
- "Force osqueryd to kill previously-running daemons");
-
-FLAG(string,
- host_identifier,
- "hostname",
- "Field used to identify the host running osquery (hostname, uuid, "
- "instance, ephemeral, specified)");
-
-// Only used when host_identifier=specified
-FLAG(string,
- specified_identifier,
- "",
- "Field used to specify the host_identifier when set to \"specified\"");
-
-FLAG(bool, utc, true, "Convert all UNIX times to UTC");
-
const std::vector<std::string> kPlaceholderHardwareUUIDList{
"00000000-0000-0000-0000-000000000000",
"03000200-0400-0500-0006-000700080009",
}
Status getSpecifiedUUID(std::string& ident) {
- if (FLAGS_specified_identifier.empty()) {
- return Status(1, "No specified identifier for host");
- }
- ident = FLAGS_specified_identifier;
return Status::success();
}
Status result(2);
if (ident.size() == 0) {
// The identifier has not been set yet.
- if (FLAGS_host_identifier == "uuid") {
- result = getHostUUID(ident);
- } else if (FLAGS_host_identifier == "instance") {
- result = getInstanceUUID(ident);
- } else if (FLAGS_host_identifier == "ephemeral") {
- result = getEphemeralUUID(ident);
- } else if (FLAGS_host_identifier == "specified") {
- result = getSpecifiedUUID(ident);
- }
if (!result.ok()) {
// assuming the default of "hostname" as the machine identifier
if (q.rows().size() > 0) {
// If the process really is osqueryd, return an "error" status.
- if (FLAGS_force) {
- return Status(1, "Tried to force remove the existing osqueryd");
- }
return Status(1, "osqueryd (" + content + ") is already running");
} else {
return Status::success();
}
-Status createPidFile() {
- // check if pidfile exists
- auto pidfile_path = fs::path(FLAGS_pidfile).make_preferred();
-
- if (pathExists(pidfile_path).ok()) {
- // if it exists, check if that pid is running.
- std::string content;
- auto read_status = readFile(pidfile_path, content, true);
- if (!read_status.ok()) {
- return Status(1, "Could not read pidfile: " + read_status.toString());
- }
-
- auto stale_status = checkStalePid(content);
- if (!stale_status.ok()) {
- return stale_status;
- }
- }
-
- // Now the pidfile is either the wrong pid or the pid is not running.
- if (!removePath(pidfile_path)) {
- // Unable to remove old pidfile.
- LOG(WARNING) << "Unable to remove the osqueryd pidfile";
- }
-
- return Status(-1, "failed");
-}
-
#ifndef WIN32
static inline bool ownerFromResult(const Row& row, long& uid, long& gid) {
#include <osquery/utils/json/json.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/tables.h>
namespace osquery {
-FLAG(bool, disable_caching, false, "Disable scheduled query caching");
-
CREATE_LAZY_REGISTRY(TablePlugin, "table");
size_t TablePlugin::kCacheInterval = 0;
}
bool TablePlugin::isCached(size_t step, const QueryContext& ctx) const {
- if (FLAGS_disable_caching) {
- return false;
- }
-
// Perform the step comparison first, because it's easy.
return (step < last_cached_ + last_interval_ && cacheAllowed(columns(), ctx));
}
+++ /dev/null
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed in accordance with the terms specified in
- * the LICENSE file found in the root directory of this source tree.
- */
-
-#ifdef WIN32
-/// Suppress a C4244 warning in gtest-printers.h (double -> BiggestInt
-/// conversion)
-#pragma warning(push, 3)
-#pragma warning(disable : 4244)
-#endif
-
-#include <gtest/gtest.h>
-
-#ifdef WIN32
-#pragma warning(pop)
-#endif
-
-#include <osquery/core.h>
-#include <osquery/flags.h>
-#include <osquery/logger.h>
-#include <osquery/utils/info/platform_type.h>
-
-#include "osquery/flagalias.h"
-
-namespace osquery {
-
-DECLARE_string(test_string_flag);
-
-class FlagsTests : public testing::Test {
- public:
- FlagsTests() {}
-
- void SetUp() {}
-};
-
-FLAG(string, test_string_flag, "TEST STRING", "TEST DESCRIPTION");
-
-TEST_F(FlagsTests, test_set_get) {
- // Test the core gflags functionality.
- EXPECT_EQ(FLAGS_test_string_flag, "TEST STRING");
-
- // Check that the gflags flag name was recorded in the osquery flag tracker.
- auto all_flags = Flag::flags();
- EXPECT_EQ(all_flags.count("test_string_flag"), 1U);
-
- // Update the value of the flag, and access through the osquery wrapper.
- FLAGS_test_string_flag = "NEW TEST STRING";
- EXPECT_EQ(Flag::getValue("test_string_flag"), "NEW TEST STRING");
-}
-
-TEST_F(FlagsTests, test_defaults) {
- // Make sure the flag value was not reset.
- EXPECT_EQ(FLAGS_test_string_flag, "NEW TEST STRING");
-
- // Now test that the default value is tracked.
- EXPECT_FALSE(Flag::isDefault("test_string_flag"));
-
- // Check the default value accessor.
- std::string default_value;
- auto status = Flag::getDefaultValue("test_mistake", default_value);
- EXPECT_FALSE(status.ok());
- status = Flag::getDefaultValue("test_string_flag", default_value);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(default_value, "TEST STRING");
-}
-
-TEST_F(FlagsTests, test_details) {
- // Make sure flag details are tracked correctly.
- auto all_flags = Flag::flags();
- auto flag_info = all_flags["test_string_flag"];
-
- EXPECT_EQ(flag_info.type, "string");
- EXPECT_EQ(flag_info.description, "TEST DESCRIPTION");
- EXPECT_EQ(flag_info.default_value, "TEST STRING");
- EXPECT_EQ(flag_info.value, "NEW TEST STRING");
- EXPECT_EQ(flag_info.detail.shell, false);
- EXPECT_EQ(flag_info.detail.external, false);
-}
-
-SHELL_FLAG(bool, shell_only, true, "TEST SHELL DESCRIPTION");
-
-TEST_F(FlagsTests, test_flag_detail_types) {
- EXPECT_TRUE(FLAGS_shell_only);
-
- auto all_flags = Flag::flags();
- EXPECT_TRUE(all_flags["shell_only"].detail.shell);
-}
-
-FLAG_ALIAS(bool, shell_only_alias, shell_only);
-
-TEST_F(FlagsTests, test_aliases) {
- EXPECT_TRUE(FLAGS_shell_only_alias);
- FLAGS_shell_only = false;
- EXPECT_FALSE(FLAGS_shell_only);
- EXPECT_FALSE(FLAGS_shell_only_alias);
-}
-
-FLAG(int32, test_int32, 1, "none");
-FLAG_ALIAS(google::int32, test_int32_alias, test_int32);
-
-FLAG(int64, test_int64, (int64_t)1 << 34, "none");
-FLAG_ALIAS(google::int64, test_int64_alias, test_int64);
-
-FLAG(double, test_double, 4.2, "none");
-FLAG_ALIAS(double, test_double_alias, test_double);
-
-FLAG(string, test_string, "test", "none");
-FLAG_ALIAS(std::string, test_string_alias, test_string);
-
-TEST_F(FlagsTests, test_alias_types) {
- // Test int32 lexical casting both ways.
- EXPECT_EQ(FLAGS_test_int32_alias, 1);
- FLAGS_test_int32_alias = 2;
- EXPECT_EQ(FLAGS_test_int32, 2);
- FLAGS_test_int32 = 3;
- EXPECT_EQ(FLAGS_test_int32_alias, 3);
- EXPECT_TRUE(FLAGS_test_int32_alias > 0);
-
- EXPECT_EQ(FLAGS_test_int64_alias, (int64_t)1 << 34);
- FLAGS_test_int64_alias = (int64_t)1 << 35;
- EXPECT_EQ(FLAGS_test_int64, (int64_t)1 << 35);
- FLAGS_test_int64 = (int64_t)1 << 36;
- EXPECT_EQ(FLAGS_test_int64_alias, (int64_t)1 << 36);
- EXPECT_TRUE(FLAGS_test_int64_alias > 0);
-
- EXPECT_EQ(FLAGS_test_double_alias, 4.2);
- FLAGS_test_double_alias = 2.4;
- EXPECT_EQ(FLAGS_test_double, 2.4);
- FLAGS_test_double = 22.44;
- EXPECT_EQ(FLAGS_test_double_alias, 22.44);
- EXPECT_TRUE(FLAGS_test_double_alias > 0);
-
- // Compile-time type checking will not compare typename T to const char*
- std::string value = FLAGS_test_string_alias;
- EXPECT_EQ(value, "test");
- FLAGS_test_string_alias = "test2";
- EXPECT_EQ(FLAGS_test_string, "test2");
- FLAGS_test_string = "test3";
-
- // Test both the copy and assignment constructor aliases.
- value = FLAGS_test_string_alias;
- auto value2 = (std::string)FLAGS_test_string_alias;
- EXPECT_EQ(value, "test3");
-}
-
-TEST_F(FlagsTests, test_platform) {
- PlatformType mPlatformType = PlatformType::TYPE_POSIX;
- EXPECT_TRUE(isPlatform(PlatformType::TYPE_POSIX, mPlatformType));
-
- mPlatformType = PlatformType::TYPE_OSX | PlatformType::TYPE_POSIX;
- EXPECT_TRUE(isPlatform(PlatformType::TYPE_POSIX, mPlatformType));
- EXPECT_TRUE(isPlatform(PlatformType::TYPE_OSX, mPlatformType));
-
- // Now set and check a valid casting.
- mPlatformType = static_cast<PlatformType>(8);
- EXPECT_EQ(PlatformType::TYPE_LINUX, mPlatformType);
-
- // Set something that doesn't make sense
- mPlatformType = PlatformType::TYPE_WINDOWS | PlatformType::TYPE_BSD;
- EXPECT_FALSE(isPlatform(PlatformType::TYPE_LINUX, mPlatformType));
- EXPECT_FALSE(isPlatform(PlatformType::TYPE_OSX, mPlatformType));
-}
-}
#include <osquery/core.h>
#include <osquery/devtools/devtools.h>
-#include <osquery/flags.h>
#include <osquery/utils/chars.h>
#include <osquery/utils/map_take.h>
#include <osquery/utils/system/env.h>
namespace osquery {
-DECLARE_string(nullvalue);
-
static std::vector<char> kOffset = {0, 0};
static std::string kToken = "|";
// Print a terminator for the previous value or lhs, followed by spaces.
out += kToken + ' ';
if (r.count(column) == 0 || lengths.count(column) == 0) {
- size = column.size() - utf8StringSize(FLAGS_nullvalue);
- out += FLAGS_nullvalue;
+ size = column.size() - utf8StringSize("");
+ out += "";
} else {
int buffer_size =
static_cast<int>(lengths.at(column) - utf8StringSize(r.at(column)));
#include <osquery/devtools/devtools.h>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/packs.h>
#include <osquery/registry_factory.h>
#include <osquery/sql/virtual_table.h>
namespace fs = boost::filesystem;
-DECLARE_string(flagfile);
-
-namespace osquery {
-
-/// Define flags used by the shell. They are parsed by the drop-in shell.
-SHELL_FLAG(bool, csv, false, "Set output mode to 'csv'");
-SHELL_FLAG(bool, json, false, "Set output mode to 'json'");
-SHELL_FLAG(bool, line, false, "Set output mode to 'line'");
-SHELL_FLAG(bool, list, false, "Set output mode to 'list'");
-SHELL_FLAG(string, separator, "|", "Set output field separator, default '|'");
-SHELL_FLAG(bool, header, true, "Toggle column headers true/false");
-SHELL_FLAG(string, pack, "", "Run all queries in a pack");
-
-/// Define short-hand shell switches.
-SHELL_FLAG(bool, L, false, "List all table names");
-SHELL_FLAG(string, A, "", "Select all from a table");
-
-DECLARE_string(nullvalue);
-DECLARE_string(logger_plugin);
-DECLARE_string(logger_path);
-} // namespace osquery
-
static char zHelp[] =
"Welcome to the osquery shell. Please explore your OS!\n"
"You are connected to a transient 'in-memory' virtual database.\n"
for (i = 0; i < nArg; ++i) {
if (azCol[i] != nullptr) {
r[std::string(azCol[i])] = (azArg[i] == nullptr)
- ? osquery::FLAGS_nullvalue
+ ? ""
: std::string(azArg[i]);
}
}
static void pretty_print_if_needed(struct callback_data* pArg) {
if ((pArg != nullptr) && pArg->mode == MODE_Pretty) {
- if (osquery::FLAGS_json) {
- osquery::jsonPrint(pArg->prettyPrint->results);
- } else {
- osquery::prettyPrint(pArg->prettyPrint->results,
- pArg->prettyPrint->columns,
- pArg->prettyPrint->lengths);
- }
+ osquery::prettyPrint(pArg->prettyPrint->results,
+ pArg->prettyPrint->columns,
+ pArg->prettyPrint->lengths);
+
pArg->prettyPrint->results.clear();
pArg->prettyPrint->columns.clear();
pArg->prettyPrint->lengths.clear();
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
meta_version(p);
- fprintf(p->out, "\nGeneral settings:\n");
- fprintf(p->out, "%13.13s: %s\n", "Flagfile", FLAGS_flagfile.c_str());
-
- // Show helpful logger-related settings.
- fprintf(
- p->out, "%13.13s: %s", "Logger", osquery::FLAGS_logger_plugin.c_str());
- if (osquery::FLAGS_logger_plugin == "filesystem") {
- fprintf(p->out, " (%s)\n", osquery::FLAGS_logger_path.c_str());
- } else {
- fprintf(p->out, "\n");
- }
-
fprintf(p->out, "\nShell settings:\n");
fprintf(p->out, "%13.13s: %s\n", "echo", p->echoOn != 0 ? "on" : "off");
fprintf(
data.out = stdout;
- // Set modes and settings from CLI flags.
- data.showHeader = static_cast<int>(FLAGS_header);
- if (FLAGS_list) {
- data.mode = MODE_List;
- } else if (FLAGS_line) {
- data.mode = MODE_Line;
- } else if (FLAGS_csv) {
- data.mode = MODE_Csv;
- data.separator[0] = ',';
- } else {
- data.mode = MODE_Pretty;
- }
-
- sqlite3_snprintf(
- sizeof(data.separator), data.separator, "%s", FLAGS_separator.c_str());
- sqlite3_snprintf(
- sizeof(data.nullvalue), data.nullvalue, "%s", FLAGS_nullvalue.c_str());
-
- int rc = 0;
- if (FLAGS_L || !FLAGS_A.empty()) {
- // Helper meta commands from shell switches.
- std::string query = (FLAGS_L) ? ".tables" : ".all " + FLAGS_A;
- auto* cmd = new char[query.size() + 1];
- memset(cmd, 0, query.size() + 1);
- std::copy(query.begin(), query.end(), cmd);
- rc = do_meta_command(cmd, &data);
- delete[] cmd;
- } else if (!FLAGS_pack.empty()) {
- rc = runPack(&data);
- } else if (argc > 1 && argv[1] != nullptr) {
- // Run a command or statement from CLI
- char* query = argv[1];
- if (query[0] == '.') {
- rc = do_meta_command(query, &data);
- rc = (rc == 2) ? 0 : rc;
- } else {
- rc = runQuery(&data, query);
- if (rc != 0) {
- return rc;
- }
- }
- } else {
- // Run commands received from standard input
- if (stdin_is_interactive) {
- printf("Using a ");
- print_bold("virtual database");
- printf(". Need help, type '.help'\n");
-
- auto history_file =
- (fs::path(osquery::osqueryHomeDirectory()) / ".history")
- .make_preferred()
- .string();
- linenoiseHistorySetMaxLen(100);
- linenoiseHistoryLoad(history_file.c_str());
- linenoiseSetCompletionCallback(tableCompletionFunction);
-
- rc = process_input(&data, nullptr);
-
- linenoiseHistorySave(history_file.c_str());
- } else {
- rc = process_input(&data, stdin);
- }
- }
-
set_table_name(&data, nullptr);
sqlite3_free(data.zFreeOnClose);
if (data.prettyPrint != nullptr) {
delete data.prettyPrint;
}
- return rc;
+ return 0;
}
} // namespace osquery
#include <boost/property_tree/json_parser.hpp>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/system.h>
namespace errc = boost::system::errc;
namespace osquery {
-
-FLAG(uint64, read_max, 50 * 1024 * 1024, "Maximum file read size");
-
-/// See reference #1382 for reasons why someone would allow unsafe.
-HIDDEN_FLAG(bool, allow_unsafe, false, "Allow unsafe executable permissions");
-
-/// Disable forensics (atime/mtime preserving) file reads.
-HIDDEN_FLAG(bool, disable_forensic, true, "Disable atime/mtime preservation");
-
static const size_t kMaxRecursiveGlobs = 64;
Status writeTextFile(const fs::path& path,
}
// Apply the max byte-read based on file/link target ownership.
- auto read_max = static_cast<off_t>(FLAGS_read_max);
+ auto read_max = static_cast<off_t>(2048);
if (file_size > read_max) {
if (!dry_run) {
LOG(WARNING) << "Cannot read file that exceeds size limit: "
predicate(content, file_size);
}
- // Attempt to restore the atime and mtime before the file read.
- if (preserve_time && !FLAGS_disable_forensic) {
- handle.fd->setFileTimes(times);
- }
return Status::success();
}
return false;
}
- if (FLAGS_allow_unsafe) {
- return true;
- }
-
Status result = platformIsTmpDir(dir);
if (!result.ok() && result.getCode() < 0) {
// An error has occurred in stat() on dir, most likely because the file path
#include <unistd.h>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
namespace osquery {
const std::string kLinuxMemPath = "/dev/mem";
-FLAG(bool, disable_memory, false, "Disable physical memory reads");
-
Status readMem(int fd, size_t base, size_t length, uint8_t* buffer) {
if (lseek(fd, base, SEEK_SET) == -1) {
return Status(1, "Cannot seek to physical base");
Status readRawMem(size_t base, size_t length, void** buffer) {
*buffer = 0;
- if (FLAGS_disable_memory) {
- return Status(1, "Configuration has disabled physical memory reads");
- }
-
if (length > kLinuxMaxMemRead) {
return Status(1, "Cowardly refusing to read a large number of bytes");
}
+++ /dev/null
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed in accordance with the terms specified in
- * the LICENSE file found in the root directory of this source tree.
- */
-
-#include <algorithm>
-#include <fstream>
-
-#include <stdio.h>
-
-#include <gtest/gtest.h>
-
-#include <boost/filesystem.hpp>
-
-#include <osquery/filesystem/filesystem.h>
-
-#include <osquery/flags.h>
-#include <osquery/logger.h>
-#include <osquery/system.h>
-
-#include <osquery/utils/info/platform_type.h>
-
-#include <osquery/filesystem/mock_file_structure.h>
-
-// Some proc* functions are only compiled when building on linux
-#ifdef __linux__
-#include "osquery/filesystem/linux/proc.h"
-#endif
-
-namespace fs = boost::filesystem;
-
-namespace osquery {
-
-DECLARE_uint64(read_max);
-
-class FilesystemTests : public testing::Test {
- protected:
- fs::path test_working_dir_;
- fs::path fake_directory_;
-
- void SetUp() override {
- fake_directory_ = fs::canonical(createMockFileStructure());
- test_working_dir_ =
- fs::temp_directory_path() /
- fs::unique_path("osquery.test_working_dir.%%%%.%%%%");
- fs::create_directories(test_working_dir_);
-
- if (isPlatform(PlatformType::TYPE_WINDOWS)) {
- etc_hosts_path_ = "C:\\Windows\\System32\\drivers\\etc\\hosts";
- etc_path_ = "C:\\Windows\\System32\\drivers\\etc";
- tmp_path_ = fs::temp_directory_path().string();
- line_ending_ = "\r\n";
-
- auto raw_drive = getEnvVar("SystemDrive");
- system_root_ = (raw_drive.is_initialized() ? *raw_drive : "") + "\\";
- } else {
- etc_hosts_path_ = "/etc/hosts";
- etc_path_ = "/etc";
- tmp_path_ = "/tmp";
- line_ending_ = "\n";
-
- system_root_ = "/";
- }
- }
-
- void TearDown() override {
- fs::remove_all(fake_directory_);
- fs::remove_all(test_working_dir_);
- }
-
- /// Helper method to check if a path was included in results.
- bool contains(const std::vector<std::string>& all, const std::string& n) {
- return !(std::find(all.begin(), all.end(), n) == all.end());
- }
-
- protected:
- std::string etc_hosts_path_;
- std::string etc_path_;
- std::string tmp_path_;
- std::string system_root_;
- std::string line_ending_;
-};
-
-TEST_F(FilesystemTests, test_read_file) {
- std::ofstream test_file((test_working_dir_ / "fstests-file").string());
- test_file.write("test123\n", sizeof("test123"));
- test_file.close();
-
- std::string content;
- auto s = readFile(test_working_dir_ / "fstests-file", content);
-
- EXPECT_TRUE(s.ok());
- EXPECT_EQ(s.toString(), "OK");
- EXPECT_EQ(content, "test123" + line_ending_);
-
- removePath(test_working_dir_ / "fstests-file");
-}
-
-TEST_F(FilesystemTests, test_remove_path) {
- auto test_dir = test_working_dir_ / "rmdir";
- fs::create_directories(test_dir);
-
- auto test_file = test_working_dir_ / "rmdir/rmfile";
- writeTextFile(test_file, "testcontent");
-
- ASSERT_TRUE(pathExists(test_file).ok());
-
- // Try to remove the directory.
- EXPECT_TRUE(removePath(test_dir));
- EXPECT_FALSE(pathExists(test_file).ok());
- EXPECT_FALSE(pathExists(test_dir).ok());
-}
-
-TEST_F(FilesystemTests, test_write_file) {
- auto test_file = test_working_dir_ / "fstests-file2";
- std::string content(2048, 'A');
-
- EXPECT_TRUE(writeTextFile(test_file, content).ok());
- ASSERT_TRUE(pathExists(test_file).ok());
- ASSERT_TRUE(isWritable(test_file).ok());
- ASSERT_TRUE(removePath(test_file).ok());
-
- EXPECT_TRUE(writeTextFile(test_file, content, 0400));
- ASSERT_TRUE(pathExists(test_file).ok());
-
- // On POSIX systems, root can still read/write.
- EXPECT_FALSE(isWritable(test_file).ok());
- EXPECT_TRUE(isReadable(test_file).ok());
- ASSERT_TRUE(removePath(test_file).ok());
-
- EXPECT_TRUE(writeTextFile(test_file, content, 0000));
- ASSERT_TRUE(pathExists(test_file).ok());
-
- // On POSIX systems, root can still read/write.
- EXPECT_FALSE(isWritable(test_file).ok());
- EXPECT_FALSE(isReadable(test_file).ok());
- ASSERT_TRUE(removePath(test_file).ok());
-}
-
-TEST_F(FilesystemTests, test_readwrite_file) {
- auto test_file = test_working_dir_ / "fstests-file3";
- size_t filesize = 4096 * 10;
-
- std::string in_content(filesize, 'A');
- EXPECT_TRUE(writeTextFile(test_file, in_content).ok());
- ASSERT_TRUE(pathExists(test_file).ok());
- ASSERT_TRUE(isReadable(test_file).ok());
-
- // Now read the content back.
- std::string out_content;
- EXPECT_TRUE(readFile(test_file, out_content).ok());
- EXPECT_EQ(filesize, out_content.size());
- EXPECT_EQ(in_content, out_content);
- removePath(test_file);
-
- // Now try to write outside of a 4k chunk size.
- in_content = std::string(filesize + 1, 'A');
- writeTextFile(test_file, in_content);
- out_content.clear();
- readFile(test_file, out_content);
- EXPECT_EQ(in_content, out_content);
- removePath(test_file);
-}
-
-TEST_F(FilesystemTests, test_read_limit) {
- auto max = FLAGS_read_max;
- FLAGS_read_max = 3;
- std::string content;
- auto status = readFile(fake_directory_ / "root.txt", content);
- EXPECT_FALSE(status.ok());
- FLAGS_read_max = max;
-
- // Make sure non-link files are still readable.
- content.erase();
- status = readFile(fake_directory_ / "root.txt", content);
- EXPECT_TRUE(status.ok());
-
- // Any the links are readable too.
- status = readFile(fake_directory_ / "root2.txt", content);
- EXPECT_TRUE(status.ok());
-}
-
-TEST_F(FilesystemTests, test_list_files_missing_directory) {
- std::vector<std::string> results;
- auto status = listFilesInDirectory("/foo/bar", results);
- EXPECT_FALSE(status.ok());
-}
-
-TEST_F(FilesystemTests, test_list_files_invalid_directory) {
- std::vector<std::string> results;
- auto status = listFilesInDirectory("/etc/hosts", results);
- EXPECT_FALSE(status.ok());
-}
-
-TEST_F(FilesystemTests, test_list_files_valid_directory) {
- std::vector<std::string> results;
-
- auto s = listFilesInDirectory(etc_path_, results);
- // This directory may be different on OS X or Linux.
-
- replaceGlobWildcards(etc_hosts_path_);
- EXPECT_TRUE(s.ok());
- EXPECT_EQ(s.toString(), "OK");
- EXPECT_TRUE(contains(results, etc_hosts_path_));
-}
-
-TEST_F(FilesystemTests, test_intermediate_globbing_directories) {
- fs::path thirdLevelDir =
- fs::path(fake_directory_) / "toplevel/%/thirdlevel1";
- std::vector<std::string> results;
- resolveFilePattern(thirdLevelDir, results);
- EXPECT_EQ(results.size(), 1U);
-}
-
-TEST_F(FilesystemTests, test_canonicalization) {
- std::string complex_path =
- (fs::path(fake_directory_) / "deep1/../deep1/..")
- .make_preferred()
- .string();
- std::string simple_path = fake_directory_.make_preferred().string();
-
- if (isPlatform(PlatformType::TYPE_WINDOWS)) {
- simple_path += "\\";
- } else {
- simple_path += "/";
- }
-
- // Use the inline wildcard and canonicalization replacement.
- // The 'simple_path' path contains a trailing '/', the replacement method will
- // distinguish between file and directory paths.
- replaceGlobWildcards(complex_path);
- EXPECT_EQ(simple_path, complex_path);
-
- // Now apply the same inline replacement on the simple_path directory and expect
- // no change to the comparison.
- replaceGlobWildcards(simple_path);
- EXPECT_EQ(simple_path, complex_path);
-
- // Now add a wildcard within the complex_path pattern. The replacement method
- // will not canonicalize past a '*' as the proceeding paths are limiters.
- complex_path = (fs::path(fake_directory_) / "*/deep2/../deep2/")
- .make_preferred()
- .string();
- replaceGlobWildcards(complex_path);
- EXPECT_EQ(complex_path,
- (fs::path(fake_directory_) / "*/deep2/../deep2/")
- .make_preferred()
- .string());
-}
-
-TEST_F(FilesystemTests, test_simple_globs) {
- std::vector<std::string> results;
-
- // Test the shell '*', we will support SQL's '%' too.
- auto status = resolveFilePattern(fake_directory_ / "*", results);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 7U);
-
- // Test the csh-style bracket syntax: {}.
- results.clear();
- resolveFilePattern(fake_directory_ / "{root,door}*", results);
- EXPECT_EQ(results.size(), 3U);
-
- // Test a tilde, home directory expansion, make no asserts about contents.
- results.clear();
- resolveFilePattern("~", results);
- if (results.size() == 0U) {
- LOG(WARNING) << "Tilde expansion failed";
- }
-}
-
-TEST_F(FilesystemTests, test_wildcard_single_all) {
- // Use '%' as a wild card to glob files within the temporarily-created dir.
- std::vector<std::string> results;
- auto status = resolveFilePattern(fake_directory_ / "%", results, GLOB_ALL);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 7U);
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "roto.txt").make_preferred().string()));
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "deep11/").make_preferred().string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_single_files) {
- // Now list again with a restriction to only files.
- std::vector<std::string> results;
- resolveFilePattern(fake_directory_ / "%", results, GLOB_FILES);
- EXPECT_EQ(results.size(), 4U);
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "roto.txt").make_preferred().string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_single_folders) {
- std::vector<std::string> results;
- resolveFilePattern(fake_directory_ / "%", results, GLOB_FOLDERS);
- EXPECT_EQ(results.size(), 3U);
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "deep11/").make_preferred().string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_dual) {
- // Now test two directories deep with a single wildcard for each.
- std::vector<std::string> results;
- auto status = resolveFilePattern(fake_directory_ / "%/%", results);
- EXPECT_TRUE(status.ok());
- EXPECT_TRUE(contains(results,
- fs::path(fake_directory_ / "deep1/level1.txt")
- .make_preferred()
- .string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_double) {
- // TODO: this will fail.
- std::vector<std::string> results;
- auto status = resolveFilePattern(fake_directory_ / "%%", results);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 20U);
- EXPECT_TRUE(contains(results,
- fs::path(fake_directory_ / "deep1/deep2/level2.txt")
- .make_preferred()
- .string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_double_folders) {
- std::vector<std::string> results;
- resolveFilePattern(fake_directory_ / "%%", results, GLOB_FOLDERS);
- EXPECT_EQ(results.size(), 10U);
- EXPECT_TRUE(contains(results,
- fs::path(fake_directory_ / "deep11/deep2/deep3/")
- .make_preferred()
- .string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_end_last_component) {
- std::vector<std::string> results;
- auto status = resolveFilePattern(fake_directory_ / "%11/%sh", results);
- EXPECT_TRUE(status.ok());
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "deep11/not_bash").make_preferred().string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_middle_component) {
- std::vector<std::string> results;
-
- auto status = resolveFilePattern(fake_directory_ / "deep1%/%", results);
-
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 5U);
- EXPECT_TRUE(contains(results,
- fs::path(fake_directory_ / "deep1/level1.txt")
- .make_preferred()
- .string()));
- EXPECT_TRUE(contains(results,
- fs::path(fake_directory_ / "deep11/level1.txt")
- .make_preferred()
- .string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_all_types) {
- std::vector<std::string> results;
-
- auto status = resolveFilePattern(fake_directory_ / "%p11/%/%%", results);
- EXPECT_TRUE(status.ok());
- EXPECT_TRUE(
- contains(results,
- fs::path(fake_directory_ / "deep11/deep2/deep3/level3.txt")
- .make_preferred()
- .string()));
-}
-
-TEST_F(FilesystemTests, test_wildcard_invalid_path) {
- std::vector<std::string> results;
- auto status = resolveFilePattern("/not_there_abcdefz/%%", results);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 0U);
-}
-
-TEST_F(FilesystemTests, test_wildcard_dotdot_files) {
- std::vector<std::string> results;
- auto status = resolveFilePattern(
- fake_directory_ / "deep11/deep2/../../%", results, GLOB_FILES);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 4U);
-
- // The response list will contain canonicalized versions: /tmp/<tests>/...
- std::string door_path =
- fs::path(fake_directory_ / "deep11/deep2/../../door.txt")
- .make_preferred()
- .string();
- replaceGlobWildcards(door_path);
- EXPECT_TRUE(contains(results, door_path));
-}
-
-TEST_F(FilesystemTests, test_no_wild) {
- std::vector<std::string> results;
- auto status =
- resolveFilePattern(fake_directory_ / "roto.txt", results, GLOB_FILES);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(results.size(), 1U);
- EXPECT_TRUE(contains(
- results,
- fs::path(fake_directory_ / "roto.txt").make_preferred().string()));
-}
-
-TEST_F(FilesystemTests, test_safe_permissions) {
- fs::path path_1(fake_directory_ / "door.txt");
- fs::path path_2(fake_directory_ / "deep11");
-
- // For testing we can request a different directory path.
- EXPECT_TRUE(safePermissions(system_root_, path_1));
-
- // A file with a directory.mode & 0x1000 fails.
- EXPECT_FALSE(safePermissions(tmp_path_, path_1));
-
- // A directory for a file will fail.
- EXPECT_FALSE(safePermissions(system_root_, path_2));
-
- // A root-owned file is appropriate
- if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
- EXPECT_TRUE(safePermissions("/", "/dev/zero"));
- }
-}
-
-// This will fail to link (procGetNamespaceInode) if we are not
-// compiling on linux
-#ifdef __linux__
-TEST_F(FilesystemTests, test_user_namespace_parser) {
- auto temp_path = fs::unique_path().native();
- EXPECT_EQ(fs::create_directory(temp_path), true);
-
- auto symlink_path = temp_path + "/namespace";
- EXPECT_EQ(symlink("namespace:[112233]", symlink_path.data()), 0);
-
- ino_t namespace_inode;
- auto status = procGetNamespaceInode(namespace_inode, "namespace", temp_path);
- EXPECT_TRUE(status.ok());
-
- removePath(temp_path);
- EXPECT_EQ(namespace_inode, static_cast<ino_t>(112233));
-}
-#endif
-
-TEST_F(FilesystemTests, test_read_symlink) {
- std::string content;
-
- if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
- auto status = readFile(fake_directory_ / "root2.txt", content);
- EXPECT_TRUE(status.ok());
- EXPECT_EQ(content, "root");
- }
-}
-
-TEST_F(FilesystemTests, test_read_zero) {
- std::string content;
-
- if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
- auto status = readFile("/dev/zero", content, 10);
- EXPECT_EQ(content.size(), 10U);
- for (size_t i = 0; i < 10; i++) {
- EXPECT_EQ(content[i], 0);
- }
- }
-}
-
-TEST_F(FilesystemTests, test_read_urandom) {
- std::string first, second;
-
- if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
- auto status = readFile("/dev/urandom", first, 10);
- EXPECT_TRUE(status.ok());
- status = readFile("/dev/urandom", second, 10);
- EXPECT_NE(first, second);
- }
-}
-
-TEST_F(FilesystemTests, create_directory) {
- auto const recursive = false;
- auto const ignore_existence = false;
- const auto tmp_path =
- fs::temp_directory_path() /
- fs::unique_path("osquery.tests.create_directory.%%%%.%%%%");
- ASSERT_FALSE(fs::exists(tmp_path));
- ASSERT_TRUE(createDirectory(tmp_path, recursive, ignore_existence).ok());
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- ASSERT_FALSE(createDirectory(tmp_path).ok());
- fs::remove(tmp_path);
-}
-
-TEST_F(FilesystemTests, create_directory_without_parent) {
- auto const recursive = false;
- auto const ignore_existence = false;
- const auto tmp_root_path =
- fs::temp_directory_path() /
- fs::unique_path(
- "osquery.tests.create_directory_without_parent.%%%%.%%%%");
- ASSERT_FALSE(fs::exists(tmp_root_path));
- auto const tmp_path = tmp_root_path / "one_more";
- ASSERT_FALSE(fs::exists(tmp_path));
- ASSERT_FALSE(createDirectory(tmp_path, recursive, ignore_existence).ok());
- ASSERT_FALSE(fs::exists(tmp_path));
- ASSERT_FALSE(fs::is_directory(tmp_path));
- fs::remove_all(tmp_root_path);
-}
-
-TEST_F(FilesystemTests, create_directory_recursive) {
- auto const recursive = true;
- auto const ignore_existence = false;
- const auto tmp_root_path =
- fs::temp_directory_path() /
- fs::unique_path("osquery.tests.create_directory_recursive.%%%%.%%%%");
- ASSERT_FALSE(fs::exists(tmp_root_path));
- auto const tmp_path = tmp_root_path / "one_more";
- ASSERT_FALSE(fs::exists(tmp_path));
- ASSERT_TRUE(createDirectory(tmp_path, recursive, ignore_existence).ok());
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- fs::remove_all(tmp_root_path);
-}
-
-TEST_F(FilesystemTests, create_directory_recursive_on_existing_dir) {
- auto const recursive = true;
- auto const ignore_existence = false;
- const auto tmp_root_path =
- fs::temp_directory_path() /
- fs::unique_path(
- "osquery.tests.create_directory_recursive_on_existing_dir.%%%%.%%%%");
- auto const tmp_path = tmp_root_path / "one_more";
- fs::create_directories(tmp_path);
-
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- ASSERT_FALSE(createDirectory(tmp_path, recursive, ignore_existence).ok());
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- fs::remove_all(tmp_root_path);
-}
-
-TEST_F(FilesystemTests, create_dir_recursive_ignore_existence) {
- auto const recursive = true;
- auto const ignore_existence = true;
- const auto tmp_root_path =
- fs::temp_directory_path() /
- fs::unique_path(
- "osquery.tests.create_dir_recursive_ignore_existence.%%%%.%%%%");
- auto const tmp_path = tmp_root_path / "one_more";
- fs::create_directories(tmp_path);
-
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- ASSERT_TRUE(createDirectory(tmp_path, recursive, ignore_existence).ok());
- ASSERT_TRUE(fs::exists(tmp_path));
- ASSERT_TRUE(fs::is_directory(tmp_path));
- fs::remove_all(tmp_root_path);
-}
-
-} // namespace osquery
#include <boost/noncopyable.hpp>
#include <osquery/core.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/plugins/plugin.h>
#include <osquery/query.h>
#include <set>
#include <string>
-#include <osquery/flags.h>
#include <osquery/plugins/plugin.h>
#include <osquery/utils/json/json.h>
namespace osquery {
-/// Allow users to disable enrollment features.
-DECLARE_bool(disable_enrollment);
-
/**
* @brief These tables populate the "host_details" content.
*
+++ /dev/null
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed in accordance with the terms specified in
- * the LICENSE file found in the root directory of this source tree.
- */
-
-#pragma once
-
-#include <boost/lexical_cast.hpp>
-
-#include <osquery/flags.h>
-
-namespace boost {
-/// We define a lexical_cast template for boolean for Gflags boolean string
-/// values.
-template <>
-bool lexical_cast<bool, std::string>(const std::string& arg);
-
-template <>
-std::string lexical_cast<std::string, bool>(const bool& arg);
-} // namespace boost
-
-namespace osquery {
-/**
- * @brief Helper accessor/assignment alias class to support deprecated flags.
- *
- * This templated class wraps Flag::updateValue and Flag::getValue to 'alias'
- * a deprecated flag name as the updated name. The helper macro FLAG_ALIAS
- * will create a global variable instances of this wrapper using the same
- * Gflags naming scheme to prevent collisions and support existing callsites.
- */
-template <typename T>
-class FlagAlias {
- public:
- FlagAlias& operator=(T const& v) {
- Flag::updateValue(name_, boost::lexical_cast<std::string>(v));
- return *this;
- }
-
- /*explicit*/ operator T() const {
- return boost::lexical_cast<T>(Flag::getValue(name_));
- }
-
- FlagAlias(const std::string& /*alias*/,
- const std::string& /*type*/,
- std::string name,
- T* /*storage*/)
- : name_(std::move(name)) {}
-
- private:
- /// Friendly flag name.
- std::string name_;
-};
-} // namespace osquery
-
-/**
- * @brief Create an alias to a command line flag.
- *
- * Like OSQUERY_FLAG, do not use this in the osquery codebase. Use the derived
- * macros that abstract the tail of boolean arguments.
- */
-#define OSQUERY_FLAG_ALIAS(t, a, n, s, e) \
- FlagAlias<t> FLAGS_##a(#a, #t, #n, &FLAGS_##n); \
- namespace flags { \
- static GFLAGS_NAMESPACE::FlagRegisterer oflag_##a( \
- #a, #a, #a, &FLAGS_##n, &FLAGS_##n); \
- const int flag_alias_##a = Flag::createAlias(#a, {#n, s, e, 0, 1}); \
- }
-
-/// See FLAG, FLAG_ALIAS aliases a flag name to an existing FLAG.
-#define FLAG_ALIAS(t, a, n) OSQUERY_FLAG_ALIAS(t, a, n, 0, 0)
-
-/// See FLAG_ALIAS, SHELL_FLAG_ALIAS%es are only available in osqueryi.
-#define SHELL_FLAG_ALIAS(t, a, n) _OSQUERY_FLAG_ALIAS(t, a, n, 1, 0)
-
-/// See FLAG_ALIAS, EXTENSION_FLAG_ALIAS%es are only available to extensions.
-#define EXTENSION_FLAG_ALIAS(a, n) OSQUERY_FLAG_ALIAS(std::string, a, n, 0, 1)
#include <string>
#include <vector>
-#include <osquery/flags.h>
#include <osquery/query.h>
#include <osquery/tables.h>
namespace osquery {
-DECLARE_int32(value_max);
-
/**
* @brief The core interface to executing osquery SQL commands.
*
#include <osquery/data_logger.h>
#include <osquery/filesystem/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/plugins/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/system.h>
-#include <osquery/flagalias.h>
#include <osquery/utils/conversions/split.h>
#include <osquery/utils/info/platform_type.h>
#include <osquery/utils/json/json.h>
namespace osquery {
-FLAG(bool, verbose, false, "Enable verbose informational messages");
-
-/// Despite being a configurable option, this is only read/used at load.
-FLAG(bool, disable_logging, false, "Disable ERROR/INFO logging");
-
-FLAG(string, logger_plugin, "filesystem", "Logger plugin name");
-
-/// Alias for the minloglevel used internally by GLOG.
-FLAG(int32, logger_min_status, 0, "Minimum level for status log recording");
-
-/// Alias for the stderrthreshold used internally by GLOG.
-FLAG(int32,
- logger_min_stderr,
- 0,
- "Minimum level for statuses written to stderr");
-
-/// It is difficult to set logging to stderr on/off at runtime.
-CLI_FLAG(bool, logger_stderr, true, "Write status logs to stderr");
-
-/**
- * @brief This hidden flag is for testing status logging.
- *
- * When enabled, logs are pushed directly to logger plugin from Glog.
- * Otherwise they are buffered and an async request for draining is sent
- * for each log.
- *
- * Within the daemon, logs are drained every 3 seconds.
- */
-HIDDEN_FLAG(bool,
- logger_status_sync,
- false,
- "Always send status logs synchronously");
-
-/**
- * @brief Logger plugin registry.
- *
- * This creates an osquery registry for "logger" which may implement
- * LoggerPlugin. Only strings are logged in practice, and LoggerPlugin provides
- * a helper member for transforming PluginRequest%s to strings.
- */
CREATE_REGISTRY(LoggerPlugin, "logger");
/**
doc.toString(request["log"]);
}
-void setVerboseLevel() {
- if (Flag::getValue("verbose") == "true") {
- // Turn verbosity up to 1.
- // Do log DEBUG, INFO, WARNING, ERROR to their log files.
- // Do log the above and verbose=1 to stderr (can be turned off later).
- FLAGS_minloglevel = google::GLOG_INFO;
- FLAGS_alsologtostderr = true;
- FLAGS_v = 1;
- } else {
- /* We use a different default for the log level if running as a daemon or if
- * running as a shell. If the flag was set we just use that in both cases.
- */
- if (Flag::isDefault("logger_min_status") && Initializer::isShell()) {
- FLAGS_minloglevel = google::GLOG_WARNING;
- } else {
- FLAGS_minloglevel = Flag::getInt32Value("logger_min_status");
- }
- FLAGS_stderrthreshold = Flag::getInt32Value("logger_min_stderr");
- }
-
- if (!FLAGS_logger_stderr) {
- FLAGS_stderrthreshold = 3;
- FLAGS_alsologtostderr = false;
- }
-
- FLAGS_logtostderr = true;
-}
-
void initStatusLogger(const std::string& name, bool init_glog) {
- FLAGS_logbufsecs = 0;
- FLAGS_stop_logging_if_full_disk = true;
- // The max size for individual log file is 10MB.
- FLAGS_max_log_size = 10;
-
- // Begin with only logging to stderr.
- FLAGS_logtostderr = true;
- FLAGS_stderrthreshold = 3;
-
- setVerboseLevel();
// Start the logging, and announce the daemon is starting.
if (init_glog) {
google::InitGoogleLogging(name.c_str());
}
-
- if (!FLAGS_disable_logging) {
- BufferedLogSink::get().setUp();
- }
}
void initLogger(const std::string& name) {
toUnixTime(tm_time),
std::string()});
}
-
- // The daemon will relay according to the schedule.
- if (enabled_ && !Initializer::isDaemon()) {
- relayStatusLogs(FLAGS_logger_status_sync);
- }
}
void BufferedLogSink::WaitTillSent() {
Status logString(const std::string& message,
const std::string& category,
const std::string& receiver) {
- if (FLAGS_disable_logging) {
- return Status::success();
- }
-
Status status;
for (const auto& logger : osquery::split(receiver, ",")) {
if (Registry::get().exists("logger", logger, true)) {
Status logQueryLogItem(const QueryLogItem& results,
const std::string& receiver) {
- if (FLAGS_disable_logging) {
- return Status::success();
- }
-
std::vector<std::string> json_items;
Status status;
std::string json;
}
Status logSnapshotQuery(const QueryLogItem& item) {
- if (FLAGS_disable_logging) {
- return Status::success();
- }
-
std::vector<std::string> json_items;
Status status;
std::string json;
}
void relayStatusLogs(bool async) {
- if (FLAGS_disable_logging) {
- // The logger plugins may not be setUp if logging is disabled.
- // If the database is not setUp, or is in a reset, status logs continue
- // to buffer.
- return;
- }
-
{
ReadLock lock(kBufferedLogSinkLogs);
if (BufferedLogSink::get().dump().size() == 0) {
#include <mutex>
#include <osquery/filesystem.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
namespace pt = boost::property_tree;
namespace osquery {
-FLAG(string,
- logger_path,
- "/var/log/osquery/",
- "Directory path for ERROR/WARN/INFO and results logging");
-/// Legacy, backward compatible "osquery_log_dir" CLI option.
-FLAG_ALIAS(std::string, osquery_log_dir, logger_path);
-
const std::string kFilesystemLoggerFilename = "osqueryd.results.log";
const std::string kFilesystemLoggerSnapshots = "osqueryd.snapshots.log";
const std::string kFilesystemLoggerHealth = "osqueryd.health.log";
REGISTER(FilesystemLoggerPlugin, "logger", "filesystem");
Status FilesystemLoggerPlugin::setUp() {
- log_path_ = fs::path(FLAGS_logger_path);
return Status(0, "OK");
}
// Stop the internal Glog facilities.
google::ShutdownGoogleLogging();
- // The log dir is used for status logging and the filesystem results logs.
- if (isWritable(log_path_.string()).ok()) {
- FLAGS_log_dir = log_path_.string();
- FLAGS_logtostderr = false;
- } else {
- // If we cannot write logs to the filesystem, fallback to stderr.
- // The caller (flags/options) might 'also' be logging to stderr using
- // debug, verbose, etc.
- FLAGS_logtostderr = true;
- }
-
// Restart the Glog facilities using the name `init` was provided.
google::InitGoogleLogging(name.c_str());
google::SetLogDestination(google::WARNING, (basename + ".WARNING.").c_str());
google::SetLogDestination(google::ERROR, (basename + ".ERROR.").c_str());
- // Store settings for logging to stderr.
- bool log_to_stderr = FLAGS_logtostderr;
- bool also_log_to_stderr = FLAGS_alsologtostderr;
- int stderr_threshold = FLAGS_stderrthreshold;
- FLAGS_alsologtostderr = false;
- FLAGS_logtostderr = false;
- FLAGS_stderrthreshold = 5;
-
// Now funnel the intermediate status logs provided to `init`.
logStatus(log);
- // Restore settings for logging to stderr.
- FLAGS_logtostderr = log_to_stderr;
- FLAGS_alsologtostderr = also_log_to_stderr;
- FLAGS_stderrthreshold = stderr_threshold;
-
// The filesystem logger cheats and uses Glog to log to the filesystem so
// we can return failure here and stop the custom log sink.
return Status(1, "No status logger used for filesystem");
#include <syslog.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/utils/conversions/split.h>
namespace osquery {
-FLAG(int32,
- logger_syslog_facility,
- LOG_LOCAL3 >> 3,
- "Syslog facility for status and results logs (0-23, default 19)");
-
class SyslogLoggerPlugin : public LoggerPlugin {
public:
Status logString(const std::string& s);
const std::vector<StatusLogLine>& log) {
closelog();
- // Define the syslog/target's application name.
- if (FLAGS_logger_syslog_facility < 0 ||
- FLAGS_logger_syslog_facility > 23) {
- FLAGS_logger_syslog_facility = LOG_LOCAL3 >> 3;
- }
- openlog(name.c_str(), LOG_PID | LOG_CONS, FLAGS_logger_syslog_facility << 3);
-
// Now funnel the intermediate status logs provided to `init`.
return logStatus(log);
}
+++ /dev/null
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed in accordance with the terms specified in
- * the LICENSE file found in the root directory of this source tree.
- */
-
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include <osquery/data_logger.h>
-#include <osquery/filesystem/filesystem.h>
-#include <osquery/plugins/logger.h>
-#include <osquery/registry_factory.h>
-#include <osquery/system.h>
-#include <osquery/utils/info/platform_type.h>
-#include <osquery/utils/system/time.h>
-
-namespace osquery {
-
-DECLARE_int32(logger_min_status);
-DECLARE_int32(logger_min_stderr);
-DECLARE_bool(logger_secondary_status_only);
-DECLARE_bool(logger_status_sync);
-DECLARE_bool(disable_logging);
-DECLARE_bool(log_numerics_as_numbers);
-
-class LoggerTests : public testing::Test {
- public:
- void SetUp() override {
- Initializer::platformSetup();
- registryAndPluginInit();
-
- // Backup the logging status, then disable.
- FLAGS_disable_logging = false;
- FLAGS_logger_status_sync = true;
-
- // Setup / initialize static members.
- log_lines.clear();
- status_messages.clear();
- statuses_logged = 0;
- last_status = {O_INFO, "", 10, "", "cal_time", 0, "host"};
- }
-
- void TearDown() override {}
-
- // Track lines emitted to logString
- static std::vector<std::string> log_lines;
-
- // Track the results of init
- static StatusLogLine last_status;
- static std::vector<std::string> status_messages;
-
- // Count calls to logStatus
- static size_t statuses_logged;
- static size_t events_logged;
- // Count added and removed snapshot rows
- static size_t snapshot_rows_added;
- static size_t snapshot_rows_removed;
-};
-
-std::vector<std::string> LoggerTests::log_lines;
-StatusLogLine LoggerTests::last_status;
-std::vector<std::string> LoggerTests::status_messages;
-size_t LoggerTests::statuses_logged = 0;
-size_t LoggerTests::events_logged = 0;
-size_t LoggerTests::snapshot_rows_added = 0;
-size_t LoggerTests::snapshot_rows_removed = 0;
-
-inline void placeStatuses(const std::vector<StatusLogLine>& log) {
- for (const auto& status : log) {
- LoggerTests::status_messages.push_back(status.message);
- }
-
- LoggerTests::statuses_logged += log.size();
- if (log.size() > 0) {
- LoggerTests::last_status = log.back();
- }
-}
-
-class TestLoggerPlugin : public LoggerPlugin {
- protected:
- bool usesLogStatus() override {
- return shouldLogStatus;
- }
-
- bool usesLogEvent() override {
- return shouldLogEvent;
- }
-
- Status logEvent(const std::string& e) override {
- LoggerTests::events_logged++;
- return Status::success();
- }
-
- Status logString(const std::string& s) override {
- LoggerTests::log_lines.push_back(s);
- return Status(0, s);
- }
-
- void init(const std::string& name,
- const std::vector<StatusLogLine>& log) override {
- placeStatuses(log);
- }
-
- Status logStatus(const std::vector<StatusLogLine>& log) override {
- placeStatuses(log);
- return Status::success();
- }
-
- Status logSnapshot(const std::string& s) override {
- LoggerTests::snapshot_rows_added += 1;
- LoggerTests::snapshot_rows_removed += 0;
- return Status::success();
- }
-
- public:
- /// Allow test methods to change status logging state.
- bool shouldLogStatus{true};
-
- /// Allow test methods to change event logging state.
- bool shouldLogEvent{true};
-};
-
-TEST_F(LoggerTests, test_plugin) {
- auto& rf = RegistryFactory::get();
- rf.registry("logger")->add("test", std::make_shared<TestLoggerPlugin>());
- rf.setUp();
-
- auto s = Registry::call("logger", "test", {{"string", "foobar"}});
- EXPECT_TRUE(s.ok());
- EXPECT_EQ("foobar", LoggerTests::log_lines.back());
-}
-
-TEST_F(LoggerTests, test_logger_init) {
- auto& rf = RegistryFactory::get();
- // Expect the logger to have been registered from the first test.
- EXPECT_TRUE(rf.exists("logger", "test"));
- EXPECT_TRUE(rf.setActive("logger", "test").ok());
-
- initStatusLogger("logger_test");
- // This will be printed to stdout.
- LOG(WARNING) << "Logger test is generating a warning status (1)";
- initLogger("logger_test");
-
- // The warning message will have been buffered and sent to the active logger
- // which is test.
- EXPECT_EQ(1U, LoggerTests::status_messages.size());
- EXPECT_EQ(1U, LoggerTests::statuses_logged);
-}
-
-TEST_F(LoggerTests, test_log_string) {
- // So far, tests have only used the logger registry/plugin API.
- EXPECT_TRUE(logString("{\"json\": true}", "event"));
- ASSERT_EQ(1U, LoggerTests::log_lines.size());
- EXPECT_EQ("{\"json\": true}", LoggerTests::log_lines.back());
-
- // Expect the logString method to fail if we explicitly request a logger
- // plugin that has not been added to the registry.
- EXPECT_FALSE(logString("{\"json\": true}", "event", "does_not_exist"));
-
- // Expect the plugin not to receive logs if status logging is disabled.
- FLAGS_disable_logging = true;
- EXPECT_TRUE(logString("test", "event"));
- EXPECT_EQ(1U, LoggerTests::log_lines.size());
- FLAGS_disable_logging = false;
-
- // If logging is re-enabled, logs should send as usual.
- EXPECT_TRUE(logString("test", "event"));
- EXPECT_EQ(2U, LoggerTests::log_lines.size());
-}
-
-TEST_F(LoggerTests, test_logger_log_status) {
- std::string warning = "Logger test is generating a warning status (2)";
- auto now = getUnixTime();
- // This will be printed to stdout.
- LOG(WARNING) << warning;
-
- // The second warning status will be sent to the logger plugin.
- EXPECT_EQ(1U, LoggerTests::statuses_logged);
-
- EXPECT_EQ(O_WARNING, LoggerTests::last_status.severity);
- EXPECT_GT(LoggerTests::last_status.line, 0U);
- EXPECT_EQ(warning, LoggerTests::last_status.message);
- EXPECT_GE(now, LoggerTests::last_status.time);
- EXPECT_EQ(getHostIdentifier(), LoggerTests::last_status.identifier);
-}
-
-TEST_F(LoggerTests, test_logger_status_level) {
- const auto logger_min_status = FLAGS_logger_min_status;
- FLAGS_logger_min_status = 0;
- // This will be printed to stdout.
- LOG(INFO) << "Logger test is generating an info status";
- EXPECT_EQ(1U, LoggerTests::statuses_logged);
-
- FLAGS_logger_min_status = 1;
- setVerboseLevel();
-
- LOG(INFO) << "Logger test is generating an info status";
- EXPECT_EQ(1U, LoggerTests::statuses_logged);
- LOG(WARNING) << "Logger test is generating a warning status";
- EXPECT_EQ(2U, LoggerTests::statuses_logged);
- FLAGS_logger_min_status = logger_min_status;
-
- const auto logger_min_stderr = FLAGS_logger_min_stderr;
- FLAGS_logger_min_stderr = 2;
- setVerboseLevel();
- FLAGS_logger_min_status = logger_min_status;
-
- LOG(WARNING) << "Logger test is generating a warning status";
- EXPECT_EQ(3U, LoggerTests::statuses_logged);
- FLAGS_logger_min_stderr = logger_min_stderr;
-
- FLAGS_logger_min_status = 1;
- setVerboseLevel();
-
- LOG(INFO) << "Logger test is generating an info status";
- EXPECT_EQ(3U, LoggerTests::statuses_logged);
- LOG(WARNING) << "Logger test is generating a warning status";
- EXPECT_EQ(4U, LoggerTests::statuses_logged);
- FLAGS_logger_min_status = logger_min_status;
-}
-
-TEST_F(LoggerTests, test_feature_request) {
- // Retrieve the test logger plugin.
- auto plugin = RegistryFactory::get().plugin("logger", "test");
- auto logger = std::dynamic_pointer_cast<TestLoggerPlugin>(plugin);
-
- logger->shouldLogEvent = false;
- logger->shouldLogStatus = false;
- auto status = Registry::call("logger", "test", {{"action", "features"}});
- EXPECT_EQ(0, status.getCode());
-
- logger->shouldLogStatus = true;
- status = Registry::call("logger", "test", {{"action", "features"}});
- EXPECT_EQ(LOGGER_FEATURE_LOGSTATUS, status.getCode());
-}
-
-TEST_F(LoggerTests, test_logger_variations) {
- // Retrieve the test logger plugin.
- auto plugin = RegistryFactory::get().plugin("logger", "test");
- auto logger = std::dynamic_pointer_cast<TestLoggerPlugin>(plugin);
- // Change the behavior.
- logger->shouldLogStatus = false;
-
- // Call the logger initialization again, then reset the behavior.
- initLogger("duplicate_logger");
- logger->shouldLogStatus = true;
-
- // This will be printed to stdout.
- LOG(WARNING) << "Logger test is generating a warning status (3)";
-
- // Since the initLogger call triggered a failed init, meaning the logger
- // does NOT handle Glog logs, there will be no statuses logged.
- EXPECT_EQ(0U, LoggerTests::statuses_logged);
-}
-
-TEST_F(LoggerTests, test_logger_snapshots) {
- // A snapshot query should not include removed items.
- QueryLogItem item;
- item.name = "test_query";
- item.identifier = "unknown_test_host";
- item.time = 0;
- item.calendar_time = "no_time";
-
- // Add a fake set of results.
- item.results.added.push_back({{"test_column", "test_value"}});
- logSnapshotQuery(item);
-
- // Expect the plugin to optionally handle snapshot logging.
- EXPECT_EQ(1U, LoggerTests::snapshot_rows_added);
-
- // Expect a single event, event though there were two added.
- item.results.added.push_back({{"test_column", "test_value"}});
- logSnapshotQuery(item);
- EXPECT_EQ(2U, LoggerTests::snapshot_rows_added);
-
- logSnapshotQuery(item);
- EXPECT_EQ(4U, LoggerTests::snapshot_rows_added);
-}
-
-class SecondTestLoggerPlugin : public LoggerPlugin {
- public:
- Status logString(const std::string& s) override {
- LoggerTests::log_lines.push_back(s);
- return Status(0);
- }
-
- Status logStatus(const std::vector<StatusLogLine>& log) override {
- placeStatuses(log);
- return Status::success();
- }
-
- bool usesLogStatus() override {
- return true;
- }
-
- protected:
- void init(const std::string& binary_name,
- const std::vector<StatusLogLine>& log) override {
- placeStatuses(log);
- }
-};
-
-TEST_F(LoggerTests, test_multiple_loggers) {
- auto& rf = RegistryFactory::get();
- auto second = std::make_shared<SecondTestLoggerPlugin>();
- rf.registry("logger")->add("second_test", second);
- EXPECT_TRUE(rf.setActive("logger", "test,second_test").ok());
-
- auto test_plugin = rf.registry("logger")->plugin("test");
- auto test_logger = std::dynamic_pointer_cast<TestLoggerPlugin>(test_plugin);
- test_logger->shouldLogStatus = false;
-
- // With two active loggers, the string should be added twice.
- logString("this is a test", "added");
- EXPECT_EQ(2U, LoggerTests::log_lines.size());
-
- LOG(WARNING) << "Logger test is generating a warning status (4)";
- // Refer to the above notes about status logs not emitting until the logger
- // it initialized. We do a 0-test to check for dead locks around attempting
- // to forward Glog-based sinks recursively into our sinks.
- EXPECT_EQ(0U, LoggerTests::statuses_logged);
-
- // Now try to initialize multiple loggers (1) forwards, (2) does not.
- initLogger("logger_test");
- LOG(WARNING) << "Logger test is generating a warning status (5)";
- // Now that the "test" logger is initialized, the status log will be
- // forwarded.
- EXPECT_EQ(1U, LoggerTests::statuses_logged);
-}
-
-TEST_F(LoggerTests, test_logger_scheduled_query) {
- RegistryFactory::get().setActive("logger", "test");
- initLogger("scheduled_query");
-
- QueryLogItem item;
- item.name = "test_query";
- item.identifier = "unknown_test_host";
- item.time = 0;
- item.calendar_time = "no_time";
- item.epoch = 0L;
- item.counter = 0L;
- item.results.added.push_back({{"test_column", "test_value"}});
- logQueryLogItem(item);
- EXPECT_EQ(1U, LoggerTests::log_lines.size());
-
- // The entire removed/added is one event when result events is false.
- item.results.removed.push_back({{"test_column", "test_new_value\n"}});
- logQueryLogItem(item);
- EXPECT_EQ(2U, LoggerTests::log_lines.size());
-
- // Now the two removed will be individual events.
- logQueryLogItem(item);
- ASSERT_EQ(4U, LoggerTests::log_lines.size());
-
- // Make sure the JSON output does not have a newline.
- std::string expected =
- "{\"name\":\"test_query\",\"hostIdentifier\":\"unknown_test_host\","
- "\"calendarTime\":\"no_time\",\"unixTime\":0,\"epoch\":0,"
- "\"counter\":0,\"logNumericsAsNumbers\":" +
- std::string(FLAGS_log_numerics_as_numbers ? "true" : "false") +
- ",\"columns\":{\"test_column\":\"test_value\"},\"action\":\"added\"}";
- EXPECT_EQ(LoggerTests::log_lines.back(), expected);
-}
-
-TEST_F(LoggerTests, test_logger_numeric_flag) {
- RegistryFactory::get().setActive("logger", "test");
- initLogger("scheduled_query");
-
- QueryLogItem item;
- item.name = "test_query";
- item.identifier = "unknown_test_host";
- item.time = 0;
- item.calendar_time = "no_time";
- item.epoch = 0L;
- item.counter = 0L;
- item.results.added.push_back({{"test_double_column", 2.000}});
- FLAGS_log_numerics_as_numbers = true;
- logQueryLogItem(item);
- EXPECT_EQ(1U, LoggerTests::log_lines.size());
-
- // Make sure the JSON output serializes the double as a double when the flag
- // FLAGS_log_numerics_as_numbers is true (as we set it, above)
- std::string expected =
- "{\"name\":\"test_query\",\"hostIdentifier\":\"unknown_test_host\","
- "\"calendarTime\":\"no_time\",\"unixTime\":0,\"epoch\":0,"
- "\"counter\":0,\"logNumericsAsNumbers\":true,\"columns\":{\"test_double_"
- "column\":2.0},\"action\":\"added\"}";
- EXPECT_EQ(LoggerTests::log_lines.back(), expected);
-
- FLAGS_log_numerics_as_numbers = false;
- logQueryLogItem(item);
- // Make sure the JSON output serializes the double as a double within a string
- // when FLAGS_log_numerics_as_numbers is false (as we set it, above)
- expected =
- "{\"name\":\"test_query\",\"hostIdentifier\":\"unknown_test_host\","
- "\"calendarTime\":\"no_time\",\"unixTime\":0,\"epoch\":0,"
- "\"counter\":0,\"logNumericsAsNumbers\":false,\"columns\":{\"test_double_"
- "column\":\"2.0\"},\"action\":\"added\"}";
- EXPECT_EQ(LoggerTests::log_lines.back(), expected);
-}
-
-class RecursiveLoggerPlugin : public LoggerPlugin {
- protected:
- bool usesLogStatus() override {
- return true;
- }
-
- Status logString(const std::string& s) override {
- return Status(0, s);
- }
-
- void init(const std::string& name,
- const std::vector<StatusLogLine>& log) override {
- logStatus(log);
- }
-
- Status logStatus(const std::vector<StatusLogLine>& log) override {
- for (const auto& item : log) {
- if (item.message == "recurse") {
- LOG(WARNING) << "Logging a status within a status logger";
- }
- statuses++;
- }
- return Status::success();
- }
-
- Status logSnapshot(const std::string& s) override {
- return Status::success();
- }
-
- public:
- size_t statuses{0};
-};
-
-/*
-TEST_F(LoggerTests, test_recursion) {
- // Stop the internal Glog facilities.
- google::ShutdownGoogleLogging();
-
- auto& rf = RegistryFactory::get();
- auto plugin = std::make_shared<RecursiveLoggerPlugin>();
- rf.registry("logger")->add("recurse", plugin);
- EXPECT_TRUE(rf.exists("logger", "recurse"));
- EXPECT_TRUE(rf.setActive("logger", "recurse").ok());
-
- FLAGS_logtostderr = true;
- initStatusLogger("logger_test");
- initLogger("logger_test");
- LOG(WARNING) << "Log to the recursive logger";
- EXPECT_EQ(1U, plugin->statuses);
-
- FLAGS_logger_status_sync = false;
- LOG(WARNING) << "recurse";
- if (isPlatform(PlatformType::TYPE_WINDOWS)) {
- for (size_t i = 0; i < 100; i++) {
- std::this_thread::sleep_for(std::chrono::microseconds(10));
- if (plugin->statuses == 3U) {
- break;
- }
- }
- }
- EXPECT_EQ(3U, plugin->statuses);
-
- // Try again with the tool type as a daemon.
- auto tool_type = kToolType;
- kToolType = ToolType::DAEMON;
- LOG(WARNING) << "recurse";
-
- // The daemon calls the status relay within the scheduler.
- EXPECT_EQ(3U, plugin->statuses);
-
- // All of recursive log lines will sink during the next call.
- relayStatusLogs(true);
- EXPECT_EQ(4U, plugin->statuses);
- relayStatusLogs(true);
- EXPECT_EQ(5U, plugin->statuses);
- kToolType = tool_type;
-
- EXPECT_EQ(0U, queuedStatuses());
- EXPECT_EQ(0U, queuedSenders());
-
- // Make sure the test file does not create a filesystem log.
- // This will happen if the logtostderr is not set.
- EXPECT_FALSE(pathExists("logger_test.INFO"));
-
- FLAGS_logtostderr = false;
-}
-*/
-} // namespace osquery
#include <osquery/core.h>
#include <osquery/devtools/devtools.h>
#include <osquery/filesystem/fileops.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/main/main.h>
#include <osquery/registry_factory.h>
namespace osquery {
-SHELL_FLAG(int32,
- profile,
- 0,
- "Enable profile mode when non-0, set number of iterations");
-
-HIDDEN_FLAG(int32,
- profile_delay,
- 0,
- "Sleep a number of seconds before and after the profiling");
-
-DECLARE_bool(disable_caching);
-
-int profile(int argc, char* argv[]) {
- std::string query;
- if (!osquery::platformIsatty(stdin)) {
- std::getline(std::cin, query);
- } else if (argc < 2) {
- // No query input provided via stdin or as a positional argument.
- std::cerr << "No query provided via stdin or args to profile..."
- << std::endl;
- return 2;
- } else {
- query = std::string(argv[1]);
- }
-
- auto dbc = osquery::SQLiteDBManager::get();
- for (size_t i = 0; i < static_cast<size_t>(osquery::FLAGS_profile); ++i) {
- osquery::QueryData results;
- auto status = osquery::queryInternal(query, results, dbc);
- dbc->clearAffectedTables();
- if (!status) {
- std::cerr << "Query failed (" << status.getCode()
- << "): " << status.what() << std::endl;
- return status.getCode();
- }
- }
-
- return 0;
-}
-
int startDaemon(Initializer& runner) {
runner.start();
}
int startShell(osquery::Initializer& runner, int argc, char* argv[]) {
- // Check for shell-specific switches and positional arguments.
- if (argc > 1 || !osquery::platformIsatty(stdin) ||
- !osquery::FLAGS_A.empty() || !osquery::FLAGS_pack.empty() ||
- osquery::FLAGS_L || osquery::FLAGS_profile > 0) {
- // A query was set as a positional argument, via stdin, or profiling is on.
- osquery::FLAGS_disable_caching = true;
- }
-
int retcode = 0;
- if (osquery::FLAGS_profile <= 0) {
- runner.start();
- // Virtual tables will be attached to the shell's in-memory SQLite DB.
- retcode = osquery::launchIntoShell(argc, argv);
- } else {
- retcode = profile(argc, argv);
- }
// Finally shutdown.
runner.requestShutdown();
return retcode;
#include <exception>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/utils/config/default_paths.h>
namespace fs = boost::filesystem;
-/**
- * This is the mode that Glog uses for logfiles.
- * Must be at the top level (i.e. outside of the `osquery` namespace).
- */
-DECLARE_int32(logfile_mode);
-
namespace osquery {
-FLAG(string,
- logger_path,
- OSQUERY_LOG_HOME,
- "Directory path for ERROR/WARN/INFO and results logging");
-/// Legacy, backward compatible "osquery_log_dir" CLI option.
-FLAG_ALIAS(std::string, osquery_log_dir, logger_path);
-
-FLAG(int32, logger_mode, 0640, "Decimal mode for log files (default '0640')");
-
const std::string kFilesystemLoggerFilename = "osqueryd.results.log";
const std::string kFilesystemLoggerSnapshots = "osqueryd.snapshots.log";
Status FilesystemLoggerPlugin::setUp() {
- log_path_ = fs::path(FLAGS_logger_path);
-
- // Ensure that the Glog status logs use the same mode as our results log.
- // Glog 0.3.4 does not support a logfile mode.
- // FLAGS_logfile_mode = FLAGS_logger_mode;
-
// Ensure that we create the results log here.
return logStringToFile("", kFilesystemLoggerFilename, true);
}
Status FilesystemLoggerPlugin::logStringToFile(const std::string& s,
const std::string& filename,
bool empty) {
- WriteLock lock(mutex_);
- Status status;
- try {
- status = writeTextFile((log_path_ / filename).string(),
- (empty) ? "" : s + '\n',
- FLAGS_logger_mode);
- } catch (const std::exception& e) {
- return Status(1, e.what());
- }
- return status;
+ return Status(1, "Not supported.");
}
Status FilesystemLoggerPlugin::logStatus(
// Stop the internal Glog facilities.
google::ShutdownGoogleLogging();
- // The log dir is used for status logging and the filesystem results logs.
- if (isWritable(log_path_.string()).ok()) {
- FLAGS_log_dir = log_path_.string();
- FLAGS_logtostderr = false;
- } else {
- // If we cannot write logs to the filesystem, fallback to stderr.
- // The caller (flags/options) might 'also' be logging to stderr using
- // debug, verbose, etc.
- FLAGS_logtostderr = true;
- }
- // Restart the Glog facilities using the name `init` was provided.
google::InitGoogleLogging(name.c_str());
// We may violate Glog global object assumptions. So set names manually.
(basename + ".WARNING.").c_str());
google::SetLogDestination(google::GLOG_ERROR, (basename + ".ERROR.").c_str());
- // Store settings for logging to stderr.
- bool log_to_stderr = FLAGS_logtostderr;
- bool also_log_to_stderr = FLAGS_alsologtostderr;
- int stderr_threshold = FLAGS_stderrthreshold;
- FLAGS_alsologtostderr = false;
- FLAGS_logtostderr = false;
- FLAGS_stderrthreshold = 5;
-
// Now funnel the intermediate status logs provided to `init`.
logStatus(log);
-
- // The filesystem logger cheats and uses Glog to log to the filesystem so
- // we can return failure here and stop the custom log sink.
- // Restore settings for logging to stderr.
- FLAGS_logtostderr = log_to_stderr;
- FLAGS_alsologtostderr = also_log_to_stderr;
- FLAGS_stderrthreshold = stderr_threshold;
}
}
#include <osquery/filesystem/filesystem.h>
#include <osquery/registry_factory.h>
#include <osquery/plugins/logger.h>
-#include <osquery/flagalias.h>
namespace osquery {
#include <sstream>
#include <osquery/logger.h>
-#include <osquery/flags.h>
#include <osquery/registry.h>
#include <osquery/utils/conversions/split.h>
#include <osquery/utils/json/json.h>
namespace osquery {
-HIDDEN_FLAG(bool, registry_exceptions, false, "Allow plugin exceptions");
-
RegistryFactory& RegistryFactory::get() {
static RegistryFactory instance;
return instance;
} catch (const std::exception& e) {
LOG(ERROR) << registry_name << " registry " << item_name
<< " plugin caused exception: " << e.what();
- if (FLAGS_registry_exceptions) {
- throw;
- }
return Status(1, e.what());
} catch (...) {
LOG(ERROR) << registry_name << " registry " << item_name
<< " plugin caused unknown exception";
- if (FLAGS_registry_exceptions) {
- throw std::runtime_error(registry_name + ": " + item_name + " failed");
- }
return Status(2, "Unknown exception");
}
}
namespace osquery {
-FLAG(int32, value_max, 512, "Maximum returned row value size");
-
CREATE_LAZY_REGISTRY(SQLPlugin, "sql");
SQL::SQL(const std::string& query, bool use_cache) {
#include <osquery/utils/conversions/castvariant.h>
#include <osquery/core.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/sql.h>
namespace osquery {
-FLAG(string,
- disable_tables,
- "Not Specified",
- "Comma-delimited list of table names to be disabled");
-
-FLAG(string, nullvalue, "", "Set string for NULL values, default ''");
-
using OpReg = QueryPlanner::Opcode::Register;
using SQLiteDBInstanceRef = std::shared_ptr<SQLiteDBInstance>;
SQLiteDBManager::SQLiteDBManager() : db_(nullptr) {
sqlite3_soft_heap_limit64(1);
- setDisabledTables(Flag::getValue("disable_tables"));
}
bool SQLiteDBManager::isDisabled(const std::string& table_name) {
}
}
-void SQLiteDBManager::setDisabledTables(const std::string& list) {
- const auto& tables = split(list, ",");
- disabled_tables_ =
- std::unordered_set<std::string>(tables.begin(), tables.end());
-}
-
SQLiteDBInstanceRef SQLiteDBManager::getUnique() {
auto instance = std::make_shared<SQLiteDBInstance>();
attachVirtualTables(instance);
row[colNames[i]] = sqlite3_column_double(prepared_statement, i);
break;
case SQLITE_NULL:
- row[colNames[i]] = FLAGS_nullvalue;
+ row[colNames[i]] = "";
break;
default:
// Everything else (SQLITE_TEXT, SQLITE3_TEXT, SQLITE_BLOB) is
namespace osquery {
-DECLARE_bool(log_numerics_as_numbers);
-
QueryDataTyped getTestDBExpectedResults() {
QueryDataTyped d;
RowTyped row1;
doc.add("unixTime", 1408993857);
doc.add("epoch", std::size_t{0});
doc.add("counter", std::size_t{0});
- doc.add("logNumericsAsNumbers", FLAGS_log_numerics_as_numbers);
return std::make_pair(std::move(doc), std::move(i));
}
#include <unordered_set>
#include <osquery/core.h>
-#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/registry_factory.h>
#include <osquery/sql/dynamic_table_row.h>
namespace osquery {
-FLAG(bool, enable_foreign, false, "Enable no-op foreign virtual tables");
-
-FLAG(uint64,
- table_delay,
- 0,
- "Add an optional microsecond delay between table scans");
-
-SHELL_FLAG(bool, planner, false, "Enable osquery runtime planner output");
-
RecursiveMutex kAttachMutex;
namespace tables {
}
static void plan(const std::string& output) {
- if (FLAGS_planner) {
- fprintf(stderr, "osquery planner: %s\n", output.c_str());
- }
}
int xOpen(sqlite3_vtab* tab, sqlite3_vtab_cursor** ppCursor) {
}
void attachVirtualTables(const SQLiteDBInstanceRef& instance) {
- if (FLAGS_enable_foreign) {
-#if !defined(OSQUERY_EXTERNAL)
- // Foreign table schema is available for the shell and daemon only.
-// registerForeignTables();
-#endif
- }
-
PluginResponse response;
bool is_extension = false;
#include <osquery/utils/system/time.h>
-#include <osquery/flags.h>
#include <osquery/system.h>
#include <osquery/tables.h>
namespace osquery {
-DECLARE_bool(utc);
-
namespace tables {
QueryData genTime(QueryContext& context) {
gmtime_r(&local_time, &gmt);
struct tm now;
- if (FLAGS_utc) {
- now = gmt;
- } else {
- localtime_r(&local_time, &now);
- }
+ localtime_r(&local_time, &now);
struct tm local;
localtime_r(&local_time, &local);
/// The relative path within the source repo to find test content.
std::string kTestDataPath{"../../../tools/tests/"};
-DECLARE_string(enroll_tls_endpoint);
-DECLARE_bool(disable_logging);
-
using chrono_clock = std::chrono::high_resolution_clock;
void initTesting() {
fs::remove_all(kTestWorkingDirectory);
fs::create_directories(kTestWorkingDirectory);
- FLAGS_disable_logging = true;
-
Initializer::platformSetup();
}