osquery-1/osquery/extensions/interface.h

352 lines
11 KiB
C
Raw Normal View History

2015-02-19 23:19:00 +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.
*
*/
#pragma once
#include <osquery/extensions.h>
#include "osquery/dispatcher/dispatcher.h"
// 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
2015-04-04 23:49:17 +00:00
#include CONCAT(OSQUERY_THRIFT_SERVER_LIB,/TThreadPoolServer.h)
#include CONCAT(OSQUERY_THRIFT_LIB,/protocol/TBinaryProtocol.h)
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TServerSocket.h)
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TBufferTransports.h)
#include CONCAT(OSQUERY_THRIFT_LIB,/transport/TSocket.h)
2015-02-19 23:19:00 +00:00
// Include intermediate Thrift-generated interface definitions.
2015-04-04 23:49:17 +00:00
#include CONCAT(OSQUERY_THRIFT,Extension.h)
#include CONCAT(OSQUERY_THRIFT,ExtensionManager.h)
2015-02-19 23:19:00 +00:00
// clang-format on
2015-05-04 03:02:01 +00:00
namespace osquery {
2015-02-19 23:19:00 +00:00
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace apache::thrift::concurrency;
2015-05-06 00:09:07 +00:00
/// Create easier to reference typedefs for Thrift layer implementations.
#define SHARED_PTR_IMPL OSQUERY_THRIFT_POINTER::shared_ptr
typedef SHARED_PTR_IMPL<TSocket> TSocketRef;
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<PosixThreadFactory> PosixThreadFactoryRef;
typedef std::shared_ptr<TThreadPoolServer> TThreadPoolServerRef;
namespace extensions {
2015-02-19 23:19:00 +00:00
/**
* @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) {}
2015-02-24 11:47:12 +00:00
explicit ExtensionHandler(RouteUUID uuid) : uuid_(uuid) {}
2015-02-19 23:19:00 +00:00
/// 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);
protected:
2015-05-06 00:09:07 +00:00
/// Transient UUID assigned to the extension after registering.
RouteUUID uuid_;
2015-02-19 23:19:00 +00:00
};
/**
* @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);
2015-02-19 23:19:00 +00:00
/**
* @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);
2015-02-19 23:19:00 +00:00
/**
* @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.
*
2015-04-12 02:50:35 +00:00
* When an Extension process is graceful killed it should deregister.
* Other privileged tools may choose to deregister an Extension by
2015-02-19 23:19:00 +00:00
* 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);
private:
/// Check if an extension exists by the name it registered.
bool exists(const std::string& name);
2015-05-06 00:09:07 +00:00
/// Introspect into the registry, checking if any extension routes have been
/// removed.
void refresh();
2015-02-19 23:19:00 +00:00
2015-04-12 02:50:35 +00:00
/// Maintain a map of extension UUID to metadata for tracking deregistration.
2015-02-19 23:19:00 +00:00
InternalExtensionList extensions_;
};
2015-05-06 00:09:07 +00:00
typedef SHARED_PTR_IMPL<ExtensionHandler> ExtensionHandlerRef;
typedef SHARED_PTR_IMPL<ExtensionManagerHandler> ExtensionManagerHandlerRef;
2015-02-19 23:19:00 +00:00
}
/// 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)
2015-03-14 01:18:18 +00:00
: path_(path), interval_(interval), fatal_(fatal) {
// Set the interval to a minimum of 200 milliseconds.
2015-03-14 01:18:18 +00:00
interval_ = (interval_ < 200) ? 200 : interval_;
}
2015-02-19 23:19:00 +00:00
public:
/// The Dispatcher thread entry point.
2015-05-06 00:09:07 +00:00
void start();
2015-02-19 23:19:00 +00:00
/// 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_;
2015-05-06 00:09:07 +00:00
2015-02-19 23:19:00 +00:00
/// The internal in milliseconds to ping the ExtensionManager.
size_t interval_;
2015-05-06 00:09:07 +00:00
2015-02-19 23:19:00 +00:00
/// 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) {}
2015-05-06 00:09:07 +00:00
/// Start a specialized health check for an ExtensionManager.
2015-02-19 23:19:00 +00:00
void watch();
private:
/// Allow extensions to fail for several intervals.
std::map<RouteUUID, size_t> failures_;
2015-02-19 23:19:00 +00:00
};
2015-05-06 00:09:07 +00:00
class ExtensionRunnerCore : public InternalRunnable {
public:
virtual ~ExtensionRunnerCore();
explicit ExtensionRunnerCore(const std::string& path)
2015-05-06 00:09:07 +00:00
: 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_;
/// Server instance, will be stopped if thread service is removed.
TThreadPoolServerRef server_;
};
/**
* @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 {
2015-02-19 23:19:00 +00:00
public:
2015-04-12 02:50:35 +00:00
ExtensionRunner(const std::string& manager_path, RouteUUID uuid)
2015-05-06 00:09:07 +00:00
: ExtensionRunnerCore(""), uuid_(uuid) {
2015-02-19 23:19:00 +00:00
path_ = getExtensionSocket(uuid, manager_path);
}
public:
2015-05-06 00:09:07 +00:00
void start();
2015-02-19 23:19:00 +00:00
/// Access the UUID provided by the ExtensionManager.
RouteUUID getUUID() { return uuid_; }
private:
/// The unique and transient Extension UUID assigned by the ExtensionManager.
RouteUUID uuid_;
};
2015-05-06 00:09:07 +00:00
/**
* @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 {
2015-02-19 23:19:00 +00:00
public:
2015-04-12 02:50:35 +00:00
explicit ExtensionManagerRunner(const std::string& manager_path)
2015-05-06 00:09:07 +00:00
: ExtensionRunnerCore(manager_path) {}
2015-02-19 23:19:00 +00:00
public:
2015-05-06 00:09:07 +00:00
void start();
2015-02-19 23:19:00 +00:00
};
/// Internal accessor for extension clients.
class EXInternal {
public:
2015-02-24 11:47:12 +00:00
explicit EXInternal(const std::string& path)
2015-05-06 00:09:07 +00:00
: socket_(new TSocket(path)),
transport_(new TBufferedTransport(socket_)),
protocol_(new TBinaryProtocol(transport_)) {}
2015-02-19 23:19:00 +00:00
virtual ~EXInternal() { transport_->close(); }
protected:
2015-05-06 00:09:07 +00:00
TSocketRef socket_;
TTransportRef transport_;
TProtocolRef protocol_;
2015-02-19 23:19:00 +00:00
};
/// 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();
2015-02-19 23:19:00 +00:00
}
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:
2015-02-24 11:47:12 +00:00
explicit EXManagerClient(const std::string& manager_path)
: EXInternal(manager_path),
client_(
std::make_shared<extensions::ExtensionManagerClient>(protocol_)) {
(void)transport_->open();
2015-02-19 23:19:00 +00:00
}
const std::shared_ptr<extensions::ExtensionManagerClient>& get() {
return client_;
}
private:
std::shared_ptr<extensions::ExtensionManagerClient> client_;
};
2015-02-24 11:47:12 +00:00
}