osquery-1/osquery/extensions/extensions.cpp

460 lines
15 KiB
C++
Raw Normal View History

2015-02-04 03:55:16 +00:00
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
2015-02-12 06:07:25 +00:00
#include <csignal>
2015-02-10 05:57:45 +00:00
2015-02-19 23:19:00 +00:00
#include <osquery/events.h>
2015-02-04 03:55:16 +00:00
#include <osquery/filesystem.h>
#include <osquery/logger.h>
2015-02-19 23:19:00 +00:00
#include <osquery/registry.h>
#include <osquery/sql.h>
2015-02-04 03:55:16 +00:00
2015-02-19 23:19:00 +00:00
#include "osquery/extensions/interface.h"
2015-02-04 03:55:16 +00:00
using namespace osquery::extensions;
namespace osquery {
2015-02-19 01:19:45 +00:00
const int kWatcherMLatency = 3000;
2015-02-17 08:36:20 +00:00
FLAG(bool, disable_extensions, false, "Disable extension API");
2015-02-17 08:36:20 +00:00
FLAG(string,
extensions_socket,
"/var/osquery/osquery.em",
"Path to the extensions UNIX domain socket")
2015-02-04 03:55:16 +00:00
ExtensionRunner::~ExtensionRunner() { remove(path_); }
void ExtensionRunner::enter() {
// Set the socket information for the extension manager.
auto socket_path = path_;
// Create the thrift instances.
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<ExtensionHandler> handler(
new ExtensionHandler());
OSQUERY_THRIFT_POINTER::shared_ptr<TProcessor> processor(
new ExtensionProcessor(handler));
OSQUERY_THRIFT_POINTER::shared_ptr<TServerTransport> serverTransport(
2015-02-04 03:55:16 +00:00
new TServerSocket(socket_path));
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TTransportFactory> transportFactory(
2015-02-04 03:55:16 +00:00
new TBufferedTransportFactory());
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TProtocolFactory> protocolFactory(
2015-02-04 03:55:16 +00:00
new TBinaryProtocolFactory());
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<ThreadManager> threadManager =
2015-02-19 01:19:45 +00:00
ThreadManager::newSimpleThreadManager(FLAGS_worker_threads);
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<PosixThreadFactory> threadFactory =
OSQUERY_THRIFT_POINTER::shared_ptr<PosixThreadFactory>(
new PosixThreadFactory());
2015-02-19 01:19:45 +00:00
threadManager->threadFactory(threadFactory);
threadManager->start();
2015-02-04 03:55:16 +00:00
// Start the Thrift server's run loop.
2015-02-09 02:05:36 +00:00
try {
2015-02-19 23:19:00 +00:00
VLOG(1) << "Extension service starting: " << socket_path;
2015-02-19 01:19:45 +00:00
TThreadPoolServer server(processor,
serverTransport,
transportFactory,
protocolFactory,
threadManager);
2015-02-09 02:05:36 +00:00
server.serve();
} catch (const std::exception& e) {
2015-02-19 01:19:45 +00:00
LOG(ERROR) << "Cannot start extension handler: " << socket_path << " ("
2015-02-09 02:05:36 +00:00
<< e.what() << ")";
2015-02-19 01:19:45 +00:00
return;
2015-02-09 02:05:36 +00:00
}
2015-02-04 03:55:16 +00:00
}
ExtensionManagerRunner::~ExtensionManagerRunner() {
// Remove the socket path.
remove(path_);
}
void ExtensionManagerRunner::enter() {
// Set the socket information for the extension manager.
auto socket_path = path_;
// Create the thrift instances.
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<ExtensionManagerHandler> handler(
2015-02-04 03:55:16 +00:00
new ExtensionManagerHandler());
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TProcessor> processor(
2015-02-04 03:55:16 +00:00
new ExtensionManagerProcessor(handler));
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TServerTransport> serverTransport(
2015-02-04 03:55:16 +00:00
new TServerSocket(socket_path));
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TTransportFactory> transportFactory(
2015-02-04 03:55:16 +00:00
new TBufferedTransportFactory());
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<TProtocolFactory> protocolFactory(
2015-02-04 03:55:16 +00:00
new TBinaryProtocolFactory());
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<ThreadManager> threadManager =
2015-02-19 01:19:45 +00:00
ThreadManager::newSimpleThreadManager(FLAGS_worker_threads);
2015-02-19 23:19:00 +00:00
OSQUERY_THRIFT_POINTER::shared_ptr<PosixThreadFactory> threadFactory =
OSQUERY_THRIFT_POINTER::shared_ptr<PosixThreadFactory>(
new PosixThreadFactory());
2015-02-19 01:19:45 +00:00
threadManager->threadFactory(threadFactory);
threadManager->start();
2015-02-04 03:55:16 +00:00
// Start the Thrift server's run loop.
2015-02-09 02:05:36 +00:00
try {
2015-02-19 23:19:00 +00:00
VLOG(1) << "Extension manager service starting: " << socket_path;
2015-02-19 01:19:45 +00:00
TThreadPoolServer server(processor,
serverTransport,
transportFactory,
protocolFactory,
threadManager);
2015-02-09 02:05:36 +00:00
server.serve();
} catch (const std::exception& e) {
LOG(WARNING) << "Extensions disabled: cannot start extension manager ("
<< socket_path << ") (" << e.what() << ")";
}
2015-02-04 03:55:16 +00:00
}
void ExtensionWatcher::enter() {
// Watch the manager, if the socket is removed then the extension will die.
2015-02-19 01:19:45 +00:00
while (true) {
watch();
interruptableSleep(interval_);
}
}
2015-02-04 03:55:16 +00:00
2015-02-19 01:19:45 +00:00
void ExtensionWatcher::exitFatal(int return_code) {
// Exit the extension.
::exit(return_code);
}
2015-02-04 03:55:16 +00:00
2015-02-19 01:19:45 +00:00
void ExtensionWatcher::watch() {
2015-02-04 03:55:16 +00:00
ExtensionStatus status;
2015-02-19 01:19:45 +00:00
try {
auto client = EXManagerClient(path_);
2015-02-04 03:55:16 +00:00
// Ping the extension manager until it goes down.
2015-02-19 01:19:45 +00:00
client.get()->ping(status);
} catch (const std::exception& e) {
LOG(WARNING) << "Extension watcher ending: osquery core has gone away";
exitFatal(0);
}
if (status.code != ExtensionCode::EXT_SUCCESS && fatal_) {
exitFatal();
}
}
void ExtensionManagerWatcher::watch() {
// Watch the set of extensions, if the socket is removed then the extension
// will be deregistered.
const auto uuids = Registry::routeUUIDs();
ExtensionStatus status;
for (const auto& uuid : uuids) {
try {
auto client = EXClient(getExtensionSocket(uuid));
// Ping the extension until it goes down.
client.get()->ping(status);
} catch (const std::exception& e) {
LOG(INFO) << "Extension UUID " << uuid << " has gone away";
Registry::removeBroadcast(uuid);
}
2015-02-04 03:55:16 +00:00
if (status.code != ExtensionCode::EXT_SUCCESS && fatal_) {
2015-02-19 01:19:45 +00:00
Registry::removeBroadcast(uuid);
2015-02-04 03:55:16 +00:00
}
}
}
2015-02-19 01:19:45 +00:00
Status startExtension(const std::string& name, const std::string& version) {
return startExtension(name, version, "0.0.0");
2015-02-04 03:55:16 +00:00
}
2015-02-19 01:19:45 +00:00
Status startExtension(const std::string& name,
const std::string& version,
const std::string& min_sdk_version) {
2015-02-04 03:55:16 +00:00
// No assumptions about how the extensions logs, the first action is to
// start the extension's registry.
Registry::setUp();
2015-02-19 01:19:45 +00:00
auto status =
startExtensionWatcher(FLAGS_extensions_socket, kWatcherMLatency, true);
if (!status.ok()) {
// If the threaded watcher fails to start, fail the extension.
return status;
}
status = startExtension(
FLAGS_extensions_socket, name, version, min_sdk_version, kSDKVersion);
if (!status.ok()) {
// If the extension failed to start then the EM is most likely unavailable.
return status;
}
try {
Dispatcher::joinServices();
} catch (const std::exception& e) {
// The extension manager may shutdown without notifying the extension.
return Status(0, e.what());
2015-02-04 03:55:16 +00:00
}
2015-02-19 01:19:45 +00:00
// An extension will only return on failure.
return Status(0, "OK");
2015-02-04 03:55:16 +00:00
}
Status startExtension(const std::string& manager_path,
const std::string& name,
const std::string& version,
2015-02-19 01:19:45 +00:00
const std::string& min_sdk_version,
2015-02-04 03:55:16 +00:00
const std::string& sdk_version) {
// Make sure the extension manager path exists, and is writable.
if (!pathExists(manager_path) || !isWritable(manager_path)) {
return Status(1, "Extension manager socket not availabe: " + manager_path);
}
// The Registry broadcast is used as the ExtensionRegistry.
auto broadcast = Registry::getBroadcast();
InternalExtensionInfo info;
info.name = name;
info.version = version;
info.sdk_version = sdk_version;
2015-02-19 01:19:45 +00:00
info.min_sdk_version = min_sdk_version;
2015-02-04 03:55:16 +00:00
// Register the extension's registry broadcast with the manager.
2015-02-04 03:55:16 +00:00
ExtensionStatus status;
try {
2015-02-19 01:19:45 +00:00
auto client = EXManagerClient(manager_path);
client.get()->registerExtension(status, info, broadcast);
2015-02-04 03:55:16 +00:00
}
catch (const std::exception& e) {
return Status(1, "Extension register failed: " + std::string(e.what()));
}
if (status.code != ExtensionCode::EXT_SUCCESS) {
return Status(status.code, status.message);
}
2015-02-19 01:19:45 +00:00
// Now that the uuid is known, try to clean up stale socket paths.
auto extension_path = getExtensionSocket(status.uuid, manager_path);
if (pathExists(extension_path).ok()) {
if (!isWritable(extension_path).ok()) {
return Status(1, "Cannot write extension socket: " + extension_path);
}
if (!remove(extension_path).ok()) {
return Status(1, "Cannot remove extension socket: " + extension_path);
}
}
2015-02-04 03:55:16 +00:00
// Start the extension's Thrift server
Dispatcher::getInstance().addService(
std::make_shared<ExtensionRunner>(manager_path, status.uuid));
2015-02-19 01:19:45 +00:00
VLOG(1) << "Extension (" << name << ", " << status.uuid << ", " << version
<< ", " << sdk_version << ") registered";
2015-02-04 03:55:16 +00:00
return Status(0, std::to_string(status.uuid));
}
2015-02-19 01:19:45 +00:00
Status queryExternal(const std::string& manager_path,
const std::string& query,
QueryData& results) {
// Make sure the extension path exists, and is writable.
if (!pathExists(manager_path) || !isWritable(manager_path)) {
return Status(1, "Extension manager socket not availabe: " + manager_path);
}
ExtensionResponse response;
try {
auto client = EXManagerClient(manager_path);
client.get()->query(response, query);
} catch (const std::exception& e) {
return Status(1, "Extension call failed: " + std::string(e.what()));
}
for (const auto& row : response.response) {
results.push_back(row);
}
return Status(response.status.code, response.status.message);
}
Status queryExternal(const std::string& query, QueryData& results) {
return queryExternal(FLAGS_extensions_socket, query, results);
}
Status getQueryColumnsExternal(const std::string& manager_path,
const std::string& query,
tables::TableColumns& columns) {
// Make sure the extension path exists, and is writable.
if (!pathExists(manager_path) || !isWritable(manager_path)) {
return Status(1, "Extension manager socket not availabe: " + manager_path);
}
ExtensionResponse response;
try {
auto client = EXManagerClient(manager_path);
client.get()->getQueryColumns(response, query);
} catch (const std::exception& e) {
return Status(1, "Extension call failed: " + std::string(e.what()));
}
// Translate response map: {string: string} to a vector: pair(name, type).
for (const auto& column : response.response) {
for (const auto& column_detail : column) {
columns.push_back(make_pair(column_detail.first, column_detail.second));
}
}
return Status(response.status.code, response.status.message);
}
Status getQueryColumnsExternal(const std::string& query,
tables::TableColumns& columns) {
return getQueryColumnsExternal(FLAGS_extensions_socket, query, columns);
}
2015-02-10 20:00:03 +00:00
Status pingExtension(const std::string& path) {
if (FLAGS_disable_extensions) {
return Status(1, "Extensions disabled");
}
// Make sure the extension path exists, and is writable.
if (!pathExists(path) || !isWritable(path)) {
return Status(1, "Extension socket not availabe: " + path);
}
ExtensionStatus ext_status;
try {
2015-02-19 01:19:45 +00:00
auto client = EXClient(path);
client.get()->ping(ext_status);
2015-02-10 20:00:03 +00:00
} catch (const std::exception& e) {
return Status(1, "Extension call failed: " + std::string(e.what()));
}
return Status(ext_status.code, ext_status.message);
}
2015-02-10 20:50:07 +00:00
Status getExtensions(ExtensionList& extensions) {
if (FLAGS_disable_extensions) {
return Status(1, "Extensions disabled");
}
return getExtensions(FLAGS_extensions_socket, extensions);
}
Status getExtensions(const std::string& manager_path,
ExtensionList& extensions) {
// Make sure the extension path exists, and is writable.
if (!pathExists(manager_path) || !isWritable(manager_path)) {
return Status(1, "Extension manager socket not availabe: " + manager_path);
}
InternalExtensionList ext_list;
try {
2015-02-19 01:19:45 +00:00
auto client = EXManagerClient(manager_path);
client.get()->extensions(ext_list);
2015-02-10 20:50:07 +00:00
} catch (const std::exception& e) {
return Status(1, "Extension call failed: " + std::string(e.what()));
}
// Add the extension manager to the list called (core).
2015-02-19 23:19:00 +00:00
extensions[0] = {"core", OSQUERY_VERSION, "0.0.0", OSQUERY_SDK_VERSION};
2015-02-10 20:50:07 +00:00
// Convert from Thrift-internal list type to RouteUUID/ExtenionInfo type.
2015-02-19 23:19:00 +00:00
for (const auto& ext : ext_list) {
extensions[ext.first] = {ext.second.name,
ext.second.version,
ext.second.min_sdk_version,
ext.second.sdk_version};
2015-02-10 20:50:07 +00:00
}
return Status(0, "OK");
}
2015-02-04 03:55:16 +00:00
Status callExtension(const RouteUUID uuid,
const std::string& registry,
const std::string& item,
const PluginRequest& request,
PluginResponse& response) {
2015-02-10 20:00:03 +00:00
if (FLAGS_disable_extensions) {
return Status(1, "Extensions disabled");
}
2015-02-10 20:50:07 +00:00
return callExtension(
getExtensionSocket(uuid), registry, item, request, response);
2015-02-04 03:55:16 +00:00
}
Status callExtension(const std::string& extension_path,
const std::string& registry,
const std::string& item,
const PluginRequest& request,
PluginResponse& response) {
// Make sure the extension manager path exists, and is writable.
if (!pathExists(extension_path) || !isWritable(extension_path)) {
return Status(1, "Extension socket not availabe: " + extension_path);
}
ExtensionResponse ext_response;
try {
2015-02-19 01:19:45 +00:00
auto client = EXClient(extension_path);
client.get()->call(ext_response, registry, item, request);
2015-02-04 03:55:16 +00:00
}
catch (const std::exception& e) {
return Status(1, "Extension call failed: " + std::string(e.what()));
}
2015-02-10 20:50:07 +00:00
// Convert from Thrift-internal list type to PluginResponse type.
2015-02-04 03:55:16 +00:00
if (ext_response.status.code == ExtensionCode::EXT_SUCCESS) {
for (const auto& item : ext_response.response) {
response.push_back(item);
}
}
return Status(ext_response.status.code, ext_response.status.message);
}
Status startExtensionWatcher(const std::string& manager_path,
size_t interval,
bool fatal) {
// Make sure the extension manager path exists, and is writable.
if (!pathExists(manager_path) || !isWritable(manager_path)) {
return Status(1, "Extension manager socket not availabe: " + manager_path);
}
// Start a extension manager watcher, if the manager dies, so should we.
Dispatcher::getInstance().addService(
std::make_shared<ExtensionWatcher>(manager_path, interval, fatal));
return Status(0, "OK");
}
Status startExtensionManager() {
2015-02-10 20:00:03 +00:00
if (FLAGS_disable_extensions) {
return Status(1, "Extensions disabled");
}
return startExtensionManager(FLAGS_extensions_socket);
2015-02-04 03:55:16 +00:00
}
Status startExtensionManager(const std::string& manager_path) {
// Check if the socket location exists.
if (pathExists(manager_path).ok()) {
if (!isWritable(manager_path).ok()) {
return Status(1, "Cannot write extension socket: " + manager_path);
}
if (!remove(manager_path).ok()) {
return Status(1, "Cannot remove extension socket: " + manager_path);
}
}
2015-02-19 01:19:45 +00:00
// Start a extension manager watcher, if the manager dies, so should we.
Dispatcher::getInstance().addService(
std::make_shared<ExtensionManagerWatcher>(manager_path,
kWatcherMLatency));
2015-02-04 03:55:16 +00:00
// Start the extension manager thread.
Dispatcher::getInstance().addService(
std::make_shared<ExtensionManagerRunner>(manager_path));
return Status(0, "OK");
}
}