mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-08 02:18:53 +00:00
331 lines
11 KiB
C++
331 lines
11 KiB
C++
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
|
|
#include <thrift/protocol/TBinaryProtocol.h>
|
|
#include <thrift/server/TSimpleServer.h>
|
|
#include <thrift/transport/TServerSocket.h>
|
|
#include <thrift/transport/TBufferTransports.h>
|
|
#include <thrift/transport/TSocket.h>
|
|
|
|
#include <osquery/extensions.h>
|
|
#include <osquery/filesystem.h>
|
|
#include <osquery/logger.h>
|
|
|
|
using namespace apache::thrift;
|
|
using namespace apache::thrift::protocol;
|
|
using namespace apache::thrift::transport;
|
|
using namespace apache::thrift::server;
|
|
|
|
using namespace osquery::extensions;
|
|
|
|
namespace osquery {
|
|
namespace extensions {
|
|
|
|
void ExtensionHandler::ping(ExtensionStatus& _return) {
|
|
_return.code = ExtensionCode::EXT_SUCCESS;
|
|
_return.message = "pong";
|
|
}
|
|
|
|
void ExtensionHandler::call(ExtensionResponse& _return,
|
|
const std::string& registry,
|
|
const std::string& item,
|
|
const ExtensionPluginRequest& request) {
|
|
// 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 = Registry::getAlias(registry, item);
|
|
|
|
PluginResponse response;
|
|
PluginRequest plugin_request;
|
|
for (const auto& request_item : request) {
|
|
plugin_request[request_item.first] = request_item.second;
|
|
}
|
|
|
|
auto status = Registry::call(registry, local_item, request, response);
|
|
_return.status.code = status.getCode();
|
|
_return.status.message = status.getMessage();
|
|
|
|
if (status.ok()) {
|
|
for (const auto& response_item : response) {
|
|
_return.response.push_back(response_item);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExtensionManagerHandler::registerExtension(
|
|
ExtensionStatus& _return,
|
|
const InternalExtensionInfo& info,
|
|
const ExtensionRegistry& registry) {
|
|
if (exists(info.name)) {
|
|
LOG(WARNING) << "Refusing to register duplicate extension " << info.name;
|
|
_return.code = ExtensionCode::EXT_FAILED;
|
|
_return.message = "Duplicate extension registered";
|
|
return;
|
|
}
|
|
|
|
// Every call to registerExtension is assigned a new RouteUUID.
|
|
RouteUUID uuid = rand();
|
|
LOG(INFO) << "Registering extension (" << info.name << ", " << uuid
|
|
<< ", version=" << info.version << ", sdk=" << info.sdk_version
|
|
<< ")";
|
|
|
|
if (!Registry::addBroadcast(uuid, registry).ok()) {
|
|
LOG(WARNING) << "Could not add extension (" << uuid
|
|
<< ") broadcast to registry";
|
|
_return.code = ExtensionCode::EXT_FAILED;
|
|
_return.message = "Failed adding registry broadcase";
|
|
return;
|
|
}
|
|
|
|
extensions_[uuid] = info;
|
|
_return.code = ExtensionCode::EXT_SUCCESS;
|
|
_return.message = "OK";
|
|
_return.uuid = uuid;
|
|
}
|
|
|
|
void ExtensionManagerHandler::deregisterExtension(
|
|
ExtensionStatus& _return, const ExtensionRouteUUID uuid) {
|
|
if (extensions_.count(uuid) == 0) {
|
|
_return.code = ExtensionCode::EXT_FAILED;
|
|
_return.message = "No extension UUID registered";
|
|
return;
|
|
}
|
|
|
|
Registry::removeBroadcast(uuid);
|
|
extensions_.erase(uuid);
|
|
}
|
|
|
|
bool ExtensionManagerHandler::exists(const std::string& name) {
|
|
for (const auto& extension : extensions_) {
|
|
if (extension.second.name == name) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ExtensionRunner::~ExtensionRunner() { remove(path_); }
|
|
|
|
void ExtensionRunner::enter() {
|
|
// Set the socket information for the extension manager.
|
|
auto socket_path = path_;
|
|
|
|
// Create the thrift instances.
|
|
boost::shared_ptr<ExtensionHandler> handler(new ExtensionHandler());
|
|
boost::shared_ptr<TProcessor> processor(new ExtensionProcessor(handler));
|
|
boost::shared_ptr<TServerTransport> serverTransport(
|
|
new TServerSocket(socket_path));
|
|
boost::shared_ptr<TTransportFactory> transportFactory(
|
|
new TBufferedTransportFactory());
|
|
boost::shared_ptr<TProtocolFactory> protocolFactory(
|
|
new TBinaryProtocolFactory());
|
|
|
|
// Start the Thrift server's run loop.
|
|
TSimpleServer server(
|
|
processor, serverTransport, transportFactory, protocolFactory);
|
|
server.serve();
|
|
}
|
|
|
|
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.
|
|
boost::shared_ptr<ExtensionManagerHandler> handler(
|
|
new ExtensionManagerHandler());
|
|
boost::shared_ptr<TProcessor> processor(
|
|
new ExtensionManagerProcessor(handler));
|
|
boost::shared_ptr<TServerTransport> serverTransport(
|
|
new TServerSocket(socket_path));
|
|
boost::shared_ptr<TTransportFactory> transportFactory(
|
|
new TBufferedTransportFactory());
|
|
boost::shared_ptr<TProtocolFactory> protocolFactory(
|
|
new TBinaryProtocolFactory());
|
|
|
|
// Start the Thrift server's run loop.
|
|
TSimpleServer server(
|
|
processor, serverTransport, transportFactory, protocolFactory);
|
|
server.serve();
|
|
}
|
|
|
|
void ExtensionWatcher::enter() {
|
|
// Watch the manager, if the socket is removed then the extension will die.
|
|
boost::shared_ptr<TSocket> socket(new TSocket(manager_path_));
|
|
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
|
|
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
|
|
|
|
// Open a long-lived client to the extension manager.
|
|
ExtensionManagerClient client(protocol);
|
|
transport->open();
|
|
|
|
ExtensionStatus status;
|
|
while (true) {
|
|
// Ping the extension manager until it goes down.
|
|
client.ping(status);
|
|
if (status.code != ExtensionCode::EXT_SUCCESS && fatal_) {
|
|
transport->close();
|
|
exitFatal();
|
|
}
|
|
boost::this_thread::sleep(boost::posix_time::milliseconds(interval_));
|
|
}
|
|
|
|
// Code will never reach this socket close.
|
|
transport->close();
|
|
}
|
|
|
|
void ExtensionWatcher::exitFatal() {
|
|
// Exit the extension.
|
|
// Not yet implemented.
|
|
}
|
|
|
|
Status startExtension() {
|
|
// No assumptions about how the extensions logs, the first action is to
|
|
// start the extension's registry.
|
|
Registry::setUp();
|
|
|
|
auto status = startExtensionWatcher("/tmp/osquery.sock", 100, true);
|
|
if (status.ok()) {
|
|
status = startExtension("/tmp/osquery.sock", "test", "0.1", "0.1");
|
|
}
|
|
return status;
|
|
}
|
|
|
|
Status startExtension(const std::string& manager_path,
|
|
const std::string& name,
|
|
const std::string& version,
|
|
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);
|
|
}
|
|
|
|
// Open a socket to the extension manager to register.
|
|
boost::shared_ptr<TSocket> socket(new TSocket(manager_path));
|
|
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
|
|
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
|
|
|
|
// 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;
|
|
|
|
// Register the extension's registery broadcast with the manager.
|
|
ExtensionManagerClient client(protocol);
|
|
ExtensionStatus status;
|
|
try {
|
|
transport->open();
|
|
client.registerExtension(status, info, broadcast);
|
|
transport->close();
|
|
}
|
|
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);
|
|
}
|
|
|
|
// Start the extension's Thrift server
|
|
Dispatcher::getInstance().addService(
|
|
std::make_shared<ExtensionRunner>(manager_path, status.uuid));
|
|
return Status(0, std::to_string(status.uuid));
|
|
}
|
|
|
|
Status callExtension(const RouteUUID uuid,
|
|
const std::string& registry,
|
|
const std::string& item,
|
|
const PluginRequest& request,
|
|
PluginResponse& response) {
|
|
// Not yet implemented.
|
|
return Status(0, "OK");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// Open a socket to the extension manager to register.
|
|
boost::shared_ptr<TSocket> socket(new TSocket(extension_path));
|
|
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
|
|
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
|
|
|
|
ExtensionClient client(protocol);
|
|
ExtensionResponse ext_response;
|
|
try {
|
|
transport->open();
|
|
client.call(ext_response, registry, item, request);
|
|
transport->close();
|
|
}
|
|
catch (const std::exception& e) {
|
|
return Status(1, "Extension call failed: " + std::string(e.what()));
|
|
}
|
|
|
|
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() {
|
|
return startExtensionManager("/tmp/osquery.sock");
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// Start the extension manager thread.
|
|
Dispatcher::getInstance().addService(
|
|
std::make_shared<ExtensionManagerRunner>(manager_path));
|
|
return Status(0, "OK");
|
|
}
|
|
}
|