mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 01:55:20 +00:00
971bee4441
fbshipit-source-id: 8ffef5e6a393ac67ce56dcb74845402e43d964a0
279 lines
8.1 KiB
C++
279 lines
8.1 KiB
C++
/**
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under both the Apache 2.0 license (found in the
|
|
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
|
* in the COPYING file in the root directory of this source tree).
|
|
* You may select, at your option, one of the above-listed licenses.
|
|
*/
|
|
|
|
#include <chrono>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <osquery/core.h>
|
|
#include <osquery/filesystem/filesystem.h>
|
|
#include <osquery/logger.h>
|
|
#include <osquery/registry_factory.h>
|
|
#include <osquery/system.h>
|
|
#include <osquery/sql.h>
|
|
|
|
#include "osquery/extensions/interface.h"
|
|
|
|
#include <osquery/utils/conversions/split.h>
|
|
#include <osquery/utils/info/platform_type.h>
|
|
#include <osquery/utils/info/version.h>
|
|
|
|
using chrono_clock = std::chrono::high_resolution_clock;
|
|
|
|
namespace osquery {
|
|
|
|
const std::vector<std::string> kSDKVersionChanges = {
|
|
{"1.7.7"},
|
|
};
|
|
|
|
Status ExtensionInterface::ping() {
|
|
// Need to translate return code into 0 and extract the UUID.
|
|
assert(uuid_ < INT_MAX);
|
|
return Status(static_cast<int>(uuid_), "pong");
|
|
}
|
|
|
|
Status ExtensionInterface::call(const std::string& registry,
|
|
const std::string& item,
|
|
const PluginRequest& request,
|
|
PluginResponse& response) {
|
|
// Call will receive an extension or core's request to call the other's
|
|
// internal registry call. It is the ONLY actor that resolves registry
|
|
// item aliases.
|
|
auto local_item = RegistryFactory::get().getAlias(registry, item);
|
|
if (local_item.empty()) {
|
|
// Extensions may not know about active (non-option based registries).
|
|
local_item = RegistryFactory::get().getActive(registry);
|
|
}
|
|
|
|
return RegistryFactory::call(registry, local_item, request, response);
|
|
}
|
|
|
|
void ExtensionInterface::shutdown() {
|
|
// Request a graceful shutdown of the Thrift listener.
|
|
VLOG(1) << "Extension " << uuid_ << " requested shutdown";
|
|
Initializer::requestShutdown(EXIT_SUCCESS);
|
|
}
|
|
|
|
ExtensionList ExtensionManagerInterface::extensions() {
|
|
refresh();
|
|
|
|
ReadLock lock(extensions_mutex_);
|
|
return extensions_;
|
|
}
|
|
|
|
OptionList ExtensionManagerInterface::options() {
|
|
OptionList options;
|
|
auto flags = Flag::flags();
|
|
for (const auto& flag : flags) {
|
|
options[flag.first].value = flag.second.value;
|
|
options[flag.first].default_value = flag.second.default_value;
|
|
options[flag.first].type = flag.second.type;
|
|
}
|
|
return options;
|
|
}
|
|
|
|
Status ExtensionManagerInterface::registerExtension(
|
|
const ExtensionInfo& info,
|
|
const ExtensionRegistry& registry,
|
|
RouteUUID& uuid) {
|
|
if (exists(info.name)) {
|
|
LOG(WARNING) << "Refusing to register duplicate extension " << info.name;
|
|
return Status((int)ExtensionCode::EXT_FAILED,
|
|
"Duplicate extension registered");
|
|
}
|
|
|
|
// Enforce API change requirements.
|
|
for (const auto& change : kSDKVersionChanges) {
|
|
if (!versionAtLeast(change, info.sdk_version)) {
|
|
LOG(WARNING) << "Could not add extension " << info.name
|
|
<< ": incompatible extension SDK " << info.sdk_version;
|
|
return Status((int)ExtensionCode::EXT_FAILED,
|
|
"Incompatible extension SDK version");
|
|
}
|
|
}
|
|
|
|
// srand must be called in the active thread on Windows due to thread saftey
|
|
if (isPlatform(PlatformType::TYPE_WINDOWS)) {
|
|
std::srand(static_cast<unsigned int>(
|
|
chrono_clock::now().time_since_epoch().count()));
|
|
}
|
|
// Every call to registerExtension is assigned a new RouteUUID.
|
|
uuid = static_cast<uint16_t>(rand());
|
|
LOG(INFO) << "Registering extension (" << info.name << ", " << uuid
|
|
<< ", version=" << info.version << ", sdk=" << info.sdk_version
|
|
<< ")";
|
|
|
|
auto status = RegistryFactory::get().addBroadcast(uuid, registry);
|
|
if (!status.ok()) {
|
|
LOG(WARNING) << "Could not add extension " << info.name << ": "
|
|
<< status.getMessage();
|
|
return Status((int)ExtensionCode::EXT_FAILED,
|
|
"Failed adding registry: " + status.getMessage());
|
|
}
|
|
|
|
WriteLock lock(extensions_mutex_);
|
|
extensions_[uuid] = info;
|
|
return Status();
|
|
}
|
|
|
|
Status ExtensionManagerInterface::query(const std::string& sql, QueryData& qd) {
|
|
return osquery::query(sql, qd);
|
|
}
|
|
|
|
Status ExtensionManagerInterface::deregisterExtension(RouteUUID uuid) {
|
|
{
|
|
ReadLock lock(extensions_mutex_);
|
|
if (extensions_.count(uuid) == 0) {
|
|
return Status((int)ExtensionCode::EXT_FAILED, "No extension UUID found");
|
|
}
|
|
}
|
|
|
|
// On success return the uuid of the now de-registered extension.
|
|
RegistryFactory::get().removeBroadcast(uuid);
|
|
|
|
WriteLock lock(extensions_mutex_);
|
|
extensions_.erase(uuid);
|
|
return Status();
|
|
}
|
|
|
|
Status ExtensionManagerInterface::getQueryColumns(const std::string& sql,
|
|
QueryData& qd) {
|
|
TableColumns columns;
|
|
auto status = osquery::getQueryColumns(sql, columns);
|
|
if (status.ok()) {
|
|
for (const auto& col : columns) {
|
|
qd.push_back({{std::get<0>(col), columnTypeName(std::get<1>(col))}});
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void ExtensionManagerInterface::refresh() {
|
|
std::vector<RouteUUID> removed_routes;
|
|
const auto uuids = RegistryFactory::get().routeUUIDs();
|
|
|
|
WriteLock lock(extensions_mutex_);
|
|
for (const auto& ext : extensions_) {
|
|
// Find extension UUIDs that have gone away.
|
|
if (std::find(uuids.begin(), uuids.end(), ext.first) == uuids.end()) {
|
|
removed_routes.push_back(ext.first);
|
|
}
|
|
}
|
|
|
|
// Remove each from the manager's list of extension metadata.
|
|
for (const auto& uuid : removed_routes) {
|
|
extensions_.erase(uuid);
|
|
}
|
|
}
|
|
|
|
bool ExtensionManagerInterface::exists(const std::string& name) {
|
|
refresh();
|
|
|
|
// Search the remaining extension list for duplicates.
|
|
ReadLock lock(extensions_mutex_);
|
|
for (const auto& extension : extensions_) {
|
|
if (extension.second.name == name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void removeStalePaths(const std::string& manager) {
|
|
std::vector<std::string> paths;
|
|
// Attempt to remove all stale extension sockets.
|
|
resolveFilePattern(manager + ".*", paths);
|
|
for (const auto& path : paths) {
|
|
removePath(path);
|
|
}
|
|
}
|
|
|
|
ExtensionRunnerCore::~ExtensionRunnerCore() = default;
|
|
|
|
ExtensionRunnerCore::ExtensionRunnerCore(const std::string& path)
|
|
: InternalRunnable("ExtensionRunnerCore"), ExtensionRunnerInterface() {
|
|
path_ = path;
|
|
}
|
|
|
|
void ExtensionRunnerCore::stop() {
|
|
{
|
|
WriteLock lock(service_start_);
|
|
service_stopping_ = true;
|
|
}
|
|
|
|
stopServer();
|
|
}
|
|
|
|
void ExtensionRunnerCore::startServer() {
|
|
{
|
|
WriteLock lock(service_start_);
|
|
// A request to stop the service may occur before the thread starts.
|
|
if (service_stopping_) {
|
|
return;
|
|
}
|
|
|
|
if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
|
|
// Before starting and after stopping the manager, remove stale sockets.
|
|
// This is not relevant in Windows
|
|
removeStalePaths(path_);
|
|
}
|
|
|
|
connect();
|
|
}
|
|
|
|
serve();
|
|
}
|
|
|
|
ExtensionRunner::ExtensionRunner(const std::string& manager_path,
|
|
RouteUUID uuid)
|
|
: ExtensionRunnerCore(""), uuid_(uuid) {
|
|
path_ = getExtensionSocket(uuid, manager_path);
|
|
}
|
|
|
|
RouteUUID ExtensionRunner::getUUID() const {
|
|
return uuid_;
|
|
}
|
|
|
|
void ExtensionRunner::start() {
|
|
setThreadName(name() + " " + path_);
|
|
init(uuid_);
|
|
|
|
VLOG(1) << "Extension service starting: " << path_;
|
|
try {
|
|
startServer();
|
|
} catch (const std::exception& e) {
|
|
LOG(ERROR) << "Cannot start extension handler: " << path_ << " ("
|
|
<< e.what() << ")";
|
|
}
|
|
}
|
|
|
|
ExtensionManagerRunner::ExtensionManagerRunner(const std::string& manager_path)
|
|
: ExtensionRunnerCore(manager_path) {}
|
|
|
|
ExtensionManagerRunner::~ExtensionManagerRunner() {
|
|
// Only attempt to remove stale paths if the server was started.
|
|
WriteLock lock(service_start_);
|
|
stopServerManager();
|
|
}
|
|
|
|
void ExtensionManagerRunner::start() {
|
|
init(0, true);
|
|
|
|
VLOG(1) << "Extension manager service starting: " << path_;
|
|
try {
|
|
startServer();
|
|
} catch (const std::exception& e) {
|
|
LOG(WARNING) << "Extensions disabled: cannot start extension manager ("
|
|
<< path_ << ") (" << e.what() << ")";
|
|
}
|
|
}
|
|
} // namespace osquery
|