mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
416 lines
13 KiB
C++
416 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2014-present, 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.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <osquery/dispatcher.h>
|
|
#include <osquery/extensions.h>
|
|
|
|
#ifdef WIN32
|
|
#pragma warning(push, 3)
|
|
|
|
/*
|
|
* MSVC complains that ExtensionManagerHandler inherits the call() function from
|
|
* ExtensionHandler via dominance. This is because ExtensionManagerHandler
|
|
* implements ExtensionManagerIf and ExtensionHandler who both implement
|
|
* ExtensionIf. ExtensionIf declares a virtual call() function that
|
|
* ExtensionHandler defines. This _shouldn't_ cause any issues.
|
|
*/
|
|
#pragma warning(disable : 4250)
|
|
#endif
|
|
|
|
// osquery is built with various versions of thrift that use different search
|
|
// paths for their includes. Unfortunately, changing include paths is not
|
|
// possible in every build system.
|
|
// clang-format off
|
|
#include CONCAT(OSQUERY_THRIFT_SERVER_LIB,/TThreadedServer.h)
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/protocol/TBinaryProtocol.h)
|
|
|
|
#ifdef WIN32
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TPipeServer.h)
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TPipe.h)
|
|
#else
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TServerSocket.h)
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TSocket.h)
|
|
#endif
|
|
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TBufferTransports.h)
|
|
#include CONCAT(OSQUERY_THRIFT_LIB,/concurrency/ThreadManager.h)
|
|
|
|
// Include intermediate Thrift-generated interface definitions.
|
|
#include CONCAT(OSQUERY_THRIFT,Extension.h)
|
|
#include CONCAT(OSQUERY_THRIFT,ExtensionManager.h)
|
|
// clang-format on
|
|
|
|
namespace osquery {
|
|
|
|
using namespace apache::thrift;
|
|
using namespace apache::thrift::protocol;
|
|
using namespace apache::thrift::transport;
|
|
using namespace apache::thrift::server;
|
|
using namespace apache::thrift::concurrency;
|
|
|
|
/// Create easier to reference typedefs for Thrift layer implementations.
|
|
#define SHARED_PTR_IMPL OSQUERY_THRIFT_POINTER::shared_ptr
|
|
|
|
#ifdef WIN32
|
|
typedef TPipe TPlatformSocket;
|
|
typedef TPipeServer TPlatformServerSocket;
|
|
typedef SHARED_PTR_IMPL<TPipe> TPlatformSocketRef;
|
|
#else
|
|
typedef TSocket TPlatformSocket;
|
|
typedef TServerSocket TPlatformServerSocket;
|
|
typedef SHARED_PTR_IMPL<TSocket> TPlatformSocketRef;
|
|
#endif
|
|
|
|
typedef SHARED_PTR_IMPL<TTransport> TTransportRef;
|
|
typedef SHARED_PTR_IMPL<TProtocol> TProtocolRef;
|
|
|
|
typedef SHARED_PTR_IMPL<TProcessor> TProcessorRef;
|
|
typedef SHARED_PTR_IMPL<TServerTransport> TServerTransportRef;
|
|
typedef SHARED_PTR_IMPL<TTransportFactory> TTransportFactoryRef;
|
|
typedef SHARED_PTR_IMPL<TProtocolFactory> TProtocolFactoryRef;
|
|
typedef SHARED_PTR_IMPL<ThreadManager> TThreadManagerRef;
|
|
|
|
#ifndef WIN32
|
|
typedef SHARED_PTR_IMPL<PosixThreadFactory> PosixThreadFactoryRef;
|
|
#endif
|
|
|
|
using TThreadedServerRef = std::shared_ptr<TThreadedServer>;
|
|
|
|
namespace extensions {
|
|
|
|
/**
|
|
* @brief The Thrift API server used by an osquery Extension process.
|
|
*
|
|
* An extension will load and start a thread to serve the ExtensionHandler
|
|
* Thrift runloop. This handler is the implementation of the thrift IDL spec.
|
|
* It implements all the Extension API handlers.
|
|
*
|
|
*/
|
|
class ExtensionHandler : virtual public ExtensionIf {
|
|
public:
|
|
ExtensionHandler() : uuid_(0) {}
|
|
explicit ExtensionHandler(RouteUUID uuid) : uuid_(uuid) {}
|
|
|
|
/// Ping an Extension for status and metrics.
|
|
void ping(ExtensionStatus& _return);
|
|
|
|
/**
|
|
* @brief The Thrift API used by Registry::call for an extension route.
|
|
*
|
|
* @param _return The return response (combo Status and PluginResponse).
|
|
* @param registry The name of the Extension registry.
|
|
* @param item The Extension plugin name.
|
|
* @param request The plugin request.
|
|
*/
|
|
void call(ExtensionResponse& _return,
|
|
const std::string& registry,
|
|
const std::string& item,
|
|
const ExtensionPluginRequest& request);
|
|
|
|
/// Request an extension to shutdown.
|
|
void shutdown();
|
|
|
|
protected:
|
|
/// Transient UUID assigned to the extension after registering.
|
|
RouteUUID uuid_;
|
|
};
|
|
|
|
/**
|
|
* @brief The Thrift API server used by an osquery process.
|
|
*
|
|
* An extension will load and start a thread to serve the
|
|
* ExtensionManagerHandler. This listens for extensions and allows them to
|
|
* register their Registry route information. Calls to the registry may then
|
|
* match a route exposed by an extension.
|
|
* This handler is the implementation of the thrift IDL spec.
|
|
* It implements all the ExtensionManager API handlers.
|
|
*
|
|
*/
|
|
class ExtensionManagerHandler : virtual public ExtensionManagerIf,
|
|
public ExtensionHandler {
|
|
public:
|
|
ExtensionManagerHandler();
|
|
|
|
/// Return a list of Route UUIDs and extension metadata.
|
|
void extensions(InternalExtensionList& _return);
|
|
|
|
/**
|
|
* @brief Return a map of osquery options (Flags, bootstrap CLI flags).
|
|
*
|
|
* osquery options are set via command line flags or overridden by a config
|
|
* options dictionary. There are some CLI-only flags that should never
|
|
* be overridden. If a bootstrap flag is changed there is undefined behavior
|
|
* since bootstrap candidates are settings needed before a configuration
|
|
* plugin is setUp.
|
|
*
|
|
* Extensions may broadcast config or logger plugins that need a snapshot
|
|
* of the current options. The best example is the `config_plugin` bootstrap
|
|
* flag.
|
|
*/
|
|
void options(InternalOptionList& _return);
|
|
|
|
/**
|
|
* @brief Request a Route UUID and advertise a set of Registry routes.
|
|
*
|
|
* When an Extension starts it must call registerExtension using a well known
|
|
* ExtensionManager UNIX domain socket path. The ExtensionManager will check
|
|
* the broadcasted routes for duplicates as well as enforce SDK version
|
|
* compatibility checks. On success the Extension is returned a Route UUID and
|
|
* begins to serve the ExtensionHandler Thrift API.
|
|
*
|
|
* @param _return The output Status and optional assigned RouteUUID.
|
|
* @param info The osquery Thrift-internal Extension metadata container.
|
|
* @param registry The Extension's Registry::getBroadcast information.
|
|
*/
|
|
void registerExtension(ExtensionStatus& _return,
|
|
const InternalExtensionInfo& info,
|
|
const ExtensionRegistry& registry);
|
|
|
|
/**
|
|
* @brief Request an Extension removal and removal of Registry routes.
|
|
*
|
|
* When an Extension process is graceful killed it should deregister.
|
|
* Other privileged tools may choose to deregister an Extension by
|
|
* the transient Extension's Route UUID, obtained using
|
|
* ExtensionManagerHandler::extensions.
|
|
*
|
|
* @param _return The output Status.
|
|
* @param uuid The assigned Route UUID to deregister.
|
|
*/
|
|
void deregisterExtension(ExtensionStatus& _return,
|
|
const ExtensionRouteUUID uuid);
|
|
|
|
/**
|
|
* @brief Execute an SQL statement in osquery core.
|
|
*
|
|
* Extensions do not have access to the internal SQLite implementation.
|
|
* For complex queries (beyond select all from a table) the statement must
|
|
* be passed into SQLite.
|
|
*
|
|
* @param _return The output Status and QueryData (as response).
|
|
* @param sql The sql statement.
|
|
*/
|
|
void query(ExtensionResponse& _return, const std::string& sql);
|
|
|
|
/**
|
|
* @brief Get SQL column information for SQL statements in osquery core.
|
|
*
|
|
* Extensions do not have access to the internal SQLite implementation.
|
|
* For complex queries (beyond metadata for a table) the statement must
|
|
* be passed into SQLite.
|
|
*
|
|
* @param _return The output Status and TableColumns (as response).
|
|
* @param sql The sql statement.
|
|
*/
|
|
void getQueryColumns(ExtensionResponse& _return, const std::string& sql);
|
|
|
|
protected:
|
|
/// A shutdown request does not apply to ExtensionManagers.
|
|
void shutdown() {}
|
|
|
|
private:
|
|
/// Check if an extension exists by the name it registered.
|
|
bool exists(const std::string& name);
|
|
|
|
/// Introspect into the registry, checking if any extension routes have been
|
|
/// removed.
|
|
void refresh();
|
|
|
|
/// Maintain a map of extension UUID to metadata for tracking deregistration.
|
|
InternalExtensionList extensions_;
|
|
};
|
|
|
|
typedef SHARED_PTR_IMPL<ExtensionHandler> ExtensionHandlerRef;
|
|
typedef SHARED_PTR_IMPL<ExtensionManagerHandler> ExtensionManagerHandlerRef;
|
|
}
|
|
|
|
/// A Dispatcher service thread that watches an ExtensionManagerHandler.
|
|
class ExtensionWatcher : public InternalRunnable {
|
|
public:
|
|
virtual ~ExtensionWatcher() {}
|
|
ExtensionWatcher(const std::string& path, size_t interval, bool fatal)
|
|
: path_(path), interval_(interval), fatal_(fatal) {
|
|
// Set the interval to a minimum of 200 milliseconds.
|
|
interval_ = (interval_ < 200) ? 200 : interval_;
|
|
}
|
|
|
|
public:
|
|
/// The Dispatcher thread entry point.
|
|
void start() override;
|
|
|
|
/// Perform health checks.
|
|
virtual void watch();
|
|
|
|
protected:
|
|
/// Exit the extension process with a fatal if the ExtensionManager dies.
|
|
void exitFatal(int return_code = 1);
|
|
|
|
protected:
|
|
/// The UNIX domain socket path for the ExtensionManager.
|
|
std::string path_;
|
|
|
|
/// The internal in milliseconds to ping the ExtensionManager.
|
|
size_t interval_;
|
|
|
|
/// If the ExtensionManager socket is closed, should the extension exit.
|
|
bool fatal_;
|
|
};
|
|
|
|
class ExtensionManagerWatcher : public ExtensionWatcher {
|
|
public:
|
|
ExtensionManagerWatcher(const std::string& path, size_t interval)
|
|
: ExtensionWatcher(path, interval, false) {}
|
|
|
|
/// The Dispatcher thread entry point.
|
|
void start() override;
|
|
|
|
/// Start a specialized health check for an ExtensionManager.
|
|
void watch() override;
|
|
|
|
private:
|
|
/// Allow extensions to fail for several intervals.
|
|
std::map<RouteUUID, size_t> failures_;
|
|
};
|
|
|
|
class ExtensionRunnerCore : public InternalRunnable {
|
|
public:
|
|
virtual ~ExtensionRunnerCore();
|
|
explicit ExtensionRunnerCore(const std::string& path)
|
|
: path_(path), server_(nullptr) {}
|
|
|
|
public:
|
|
/// Given a handler transport and protocol start a thrift threaded server.
|
|
void startServer(TProcessorRef processor);
|
|
|
|
// The Dispatcher thread service stop point.
|
|
void stop();
|
|
|
|
protected:
|
|
/// The UNIX domain socket used for requests from the ExtensionManager.
|
|
std::string path_;
|
|
|
|
/// Transport instance, will be interrupted if the thread is removed.
|
|
TServerTransportRef transport_{nullptr};
|
|
|
|
/// Server instance, will be stopped if thread service is removed.
|
|
TThreadedServerRef server_{nullptr};
|
|
|
|
/// Protect the service start and stop, this mutex protects server creation.
|
|
std::mutex service_start_;
|
|
|
|
/// Record a dispatcher's request to stop the service.
|
|
bool service_stopping_{false};
|
|
};
|
|
|
|
/**
|
|
* @brief A Dispatcher service thread that starts ExtensionHandler.
|
|
*
|
|
* This runner will start a Thrift Extension server, call serve, and wait
|
|
* until the extension exists or the ExtensionManager (core) terminates or
|
|
* deregisters the extension.
|
|
*
|
|
*/
|
|
class ExtensionRunner : public ExtensionRunnerCore {
|
|
public:
|
|
ExtensionRunner(const std::string& manager_path, RouteUUID uuid)
|
|
: ExtensionRunnerCore(""), uuid_(uuid) {
|
|
path_ = getExtensionSocket(uuid, manager_path);
|
|
}
|
|
|
|
public:
|
|
void start();
|
|
|
|
/// Access the UUID provided by the ExtensionManager.
|
|
RouteUUID getUUID() {
|
|
return uuid_;
|
|
}
|
|
|
|
private:
|
|
/// The unique and transient Extension UUID assigned by the ExtensionManager.
|
|
RouteUUID uuid_;
|
|
};
|
|
|
|
/**
|
|
* @brief A Dispatcher service thread that starts ExtensionManagerHandler.
|
|
*
|
|
* This runner will start a Thrift ExtensionManager server, call serve, and wait
|
|
* until for extensions to register, or thrift API calls.
|
|
*
|
|
*/
|
|
class ExtensionManagerRunner : public ExtensionRunnerCore {
|
|
public:
|
|
virtual ~ExtensionManagerRunner();
|
|
explicit ExtensionManagerRunner(const std::string& manager_path)
|
|
: ExtensionRunnerCore(manager_path) {}
|
|
|
|
public:
|
|
void start();
|
|
};
|
|
|
|
/// Internal accessor for extension clients.
|
|
class EXInternal {
|
|
public:
|
|
explicit EXInternal(const std::string& path)
|
|
: socket_(new TPlatformSocket(path)),
|
|
transport_(new TBufferedTransport(socket_)),
|
|
protocol_(new TBinaryProtocol(transport_)) {}
|
|
|
|
virtual ~EXInternal() {
|
|
transport_->close();
|
|
}
|
|
|
|
protected:
|
|
TPlatformSocketRef socket_;
|
|
TTransportRef transport_;
|
|
TProtocolRef protocol_;
|
|
};
|
|
|
|
/// Internal accessor for a client to an extension (from an extension manager).
|
|
class EXClient : public EXInternal {
|
|
public:
|
|
explicit EXClient(const std::string& path)
|
|
: EXInternal(path),
|
|
client_(std::make_shared<extensions::ExtensionClient>(protocol_)) {
|
|
(void)transport_->open();
|
|
}
|
|
|
|
const std::shared_ptr<extensions::ExtensionClient>& get() {
|
|
return client_;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<extensions::ExtensionClient> client_;
|
|
};
|
|
|
|
/// Internal accessor for a client to an extension manager (from an extension).
|
|
class EXManagerClient : public EXInternal {
|
|
public:
|
|
explicit EXManagerClient(const std::string& manager_path)
|
|
: EXInternal(manager_path),
|
|
client_(
|
|
std::make_shared<extensions::ExtensionManagerClient>(protocol_)) {
|
|
(void)transport_->open();
|
|
}
|
|
|
|
const std::shared_ptr<extensions::ExtensionManagerClient>& get() {
|
|
return client_;
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<extensions::ExtensionManagerClient> client_;
|
|
};
|
|
}
|
|
|
|
#ifdef WIN32
|
|
#pragma warning(pop)
|
|
#endif
|