2015-09-07 18:09:06 +00:00
|
|
|
/*
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2015-09-07 18:09:06 +00:00
|
|
|
* 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 <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2017-08-20 09:44:38 +00:00
|
|
|
#include <osquery/query.h>
|
2015-09-07 18:09:06 +00:00
|
|
|
#include <osquery/registry.h>
|
|
|
|
#include <osquery/status.h>
|
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
2016-03-05 17:29:51 +00:00
|
|
|
/**
|
|
|
|
* @brief Small struct containing the query and ID information for a
|
|
|
|
* distributed query
|
|
|
|
*/
|
|
|
|
struct DistributedQueryRequest {
|
|
|
|
public:
|
|
|
|
explicit DistributedQueryRequest() {}
|
|
|
|
|
|
|
|
std::string query;
|
|
|
|
std::string id;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Serialize a DistributedQueryRequest into a property tree
|
|
|
|
*
|
|
|
|
* @param r the DistributedQueryRequest to serialize
|
2017-08-14 17:55:45 +00:00
|
|
|
* @param d the output rapidjson document
|
2016-03-05 17:29:51 +00:00
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status serializeDistributedQueryRequest(const DistributedQueryRequest& r,
|
2017-08-07 23:34:44 +00:00
|
|
|
rapidjson::Document& d);
|
2016-03-05 17:29:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Serialize a DistributedQueryRequest object into a JSON string
|
|
|
|
*
|
|
|
|
* @param r the DistributedQueryRequest to serialize
|
|
|
|
* @param json the output JSON string
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status serializeDistributedQueryRequestJSON(const DistributedQueryRequest& r,
|
|
|
|
std::string& json);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deserialize a DistributedQueryRequest object from a property tree
|
|
|
|
*
|
2017-08-14 17:55:45 +00:00
|
|
|
* @param d the input rapidjson value
|
2016-03-05 17:29:51 +00:00
|
|
|
* @param r the output DistributedQueryRequest structure
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
2017-08-07 23:34:44 +00:00
|
|
|
Status deserializeDistributedQueryRequest(const rapidjson::Value& d,
|
|
|
|
DistributedQueryRequest& r);
|
2016-03-05 17:29:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deserialize a DistributedQueryRequest object from a JSON string
|
|
|
|
*
|
|
|
|
* @param json the input JSON string
|
|
|
|
* @param r the output DistributedQueryRequest structure
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status deserializeDistributedQueryRequestJSON(const std::string& json,
|
|
|
|
DistributedQueryRequest& r);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Small struct containing the results of a distributed query
|
|
|
|
*/
|
|
|
|
struct DistributedQueryResult {
|
|
|
|
public:
|
2016-11-04 06:54:55 +00:00
|
|
|
DistributedQueryResult() {}
|
|
|
|
DistributedQueryResult(const DistributedQueryRequest& req,
|
|
|
|
const QueryData& res,
|
2017-01-21 06:52:47 +00:00
|
|
|
const ColumnNames& cols,
|
2016-11-04 06:54:55 +00:00
|
|
|
const Status& s)
|
2017-01-21 06:52:47 +00:00
|
|
|
: request(req), results(res), columns(cols), status(s) {}
|
2016-03-05 17:29:51 +00:00
|
|
|
|
|
|
|
DistributedQueryRequest request;
|
|
|
|
QueryData results;
|
2017-01-21 06:52:47 +00:00
|
|
|
ColumnNames columns;
|
2016-11-04 06:54:55 +00:00
|
|
|
Status status;
|
2016-03-05 17:29:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Serialize a DistributedQueryResult into a property tree
|
|
|
|
*
|
|
|
|
* @param r the DistributedQueryResult to serialize
|
2017-08-14 17:55:45 +00:00
|
|
|
* @param d the output rapidjson document
|
2016-03-05 17:29:51 +00:00
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status serializeDistributedQueryResult(const DistributedQueryResult& r,
|
2017-08-07 23:34:44 +00:00
|
|
|
rapidjson::Document& d);
|
2016-03-05 17:29:51 +00:00
|
|
|
/**
|
|
|
|
* @brief Serialize a DistributedQueryResult object into a JSON string
|
|
|
|
*
|
|
|
|
* @param r the DistributedQueryResult to serialize
|
|
|
|
* @param json the output JSON string
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status serializeDistributedQueryResultJSON(const DistributedQueryResult& r,
|
|
|
|
std::string& json);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deserialize a DistributedQueryResult object from a property tree
|
|
|
|
*
|
2017-08-14 17:55:45 +00:00
|
|
|
* @param d the input rapidjson document
|
2016-03-05 17:29:51 +00:00
|
|
|
* @param r the output DistributedQueryResult structure
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
2017-08-07 23:34:44 +00:00
|
|
|
Status deserializeDistributedQueryResult(const rapidjson::Document& d,
|
|
|
|
DistributedQueryResult& r);
|
2016-03-05 17:29:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Deserialize a DistributedQueryResult object from a JSON string
|
|
|
|
*
|
|
|
|
* @param json the input JSON string
|
|
|
|
* @param r the output DistributedQueryResult structure
|
|
|
|
*
|
|
|
|
* @return Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status deserializeDistributedQueryResultJSON(const std::string& json,
|
|
|
|
DistributedQueryResult& r);
|
|
|
|
|
2015-09-07 18:09:06 +00:00
|
|
|
class DistributedPlugin : public Plugin {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* @brief Get the queries to be executed
|
|
|
|
*
|
|
|
|
* Consider the following example JSON which represents the expected format
|
|
|
|
*
|
|
|
|
* @code{.json}
|
|
|
|
* {
|
|
|
|
* "queries": {
|
|
|
|
* "id1": "select * from osquery_info",
|
|
|
|
* "id2": "select * from osquery_schedule"
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* @param json is the string to populate the queries data structure with
|
|
|
|
* @return a Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
virtual Status getQueries(std::string& json) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Write the results that were executed
|
|
|
|
*
|
|
|
|
* Consider the following JSON which represents the format that will be used:
|
|
|
|
*
|
|
|
|
* @code{.json}
|
|
|
|
* {
|
|
|
|
* "queries": {
|
|
|
|
* "id1": [
|
|
|
|
* {
|
|
|
|
* "col1": "val1",
|
|
|
|
* "col2": "val2"
|
|
|
|
* },
|
|
|
|
* {
|
|
|
|
* "col1": "val1",
|
|
|
|
* "col2": "val2"
|
|
|
|
* }
|
|
|
|
* ],
|
|
|
|
* "id2": [
|
|
|
|
* {
|
|
|
|
* "col1": "val1",
|
|
|
|
* "col2": "val2"
|
|
|
|
* }
|
|
|
|
* ]
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* @param json is the results data to write
|
|
|
|
* @return a Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
virtual Status writeResults(const std::string& json) = 0;
|
|
|
|
|
|
|
|
/// Main entrypoint for distirbuted plugin requests
|
2016-08-27 12:12:48 +00:00
|
|
|
Status call(const PluginRequest& request, PluginResponse& response) override;
|
2015-09-07 18:09:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Class for managing the set of distributed queries to execute
|
|
|
|
*
|
|
|
|
* Consider the following workflow example, without any error handling
|
|
|
|
*
|
|
|
|
* @code{.cpp}
|
|
|
|
* auto dist = Distributed();
|
|
|
|
* while (true) {
|
|
|
|
* dist.pullUpdates();
|
|
|
|
* if (dist.getPendingQueryCount() > 0) {
|
|
|
|
* dist.runQueries();
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*/
|
|
|
|
class Distributed {
|
|
|
|
public:
|
|
|
|
/// Default constructor
|
2016-08-27 12:12:48 +00:00
|
|
|
Distributed() {}
|
2015-09-07 18:09:06 +00:00
|
|
|
|
|
|
|
/// Retrieve queued queries from a remote server
|
|
|
|
Status pullUpdates();
|
|
|
|
|
|
|
|
/// Get the number of queries which are waiting to be executed
|
|
|
|
size_t getPendingQueryCount();
|
|
|
|
|
|
|
|
/// Get the number of results which are waiting to be flushed
|
|
|
|
size_t getCompletedCount();
|
|
|
|
|
|
|
|
/// Serialize result data into a JSON string and clear the results
|
|
|
|
Status serializeResults(std::string& json);
|
|
|
|
|
|
|
|
/// Process and execute queued queries
|
|
|
|
Status runQueries();
|
|
|
|
|
2017-05-05 22:14:21 +00:00
|
|
|
// Getter for ID of currently executing request
|
|
|
|
static std::string getCurrentRequestId();
|
|
|
|
|
2015-09-07 18:09:06 +00:00
|
|
|
protected:
|
|
|
|
/**
|
|
|
|
* @brief Process several queries from a distributed plugin
|
|
|
|
*
|
|
|
|
* Given a response from a distributed plugin, parse the results and enqueue
|
|
|
|
* them in the internal state of the class
|
|
|
|
*
|
|
|
|
* @param work is the string from DistributedPlugin::getQueries
|
|
|
|
* @return a Status indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
Status acceptWork(const std::string& work);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Pop a request object off of the queries_ member
|
|
|
|
*
|
|
|
|
* @return a DistributedQueryRequest object which needs to be executed
|
|
|
|
*/
|
|
|
|
DistributedQueryRequest popRequest();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Queue a result to be batch sent to the server
|
|
|
|
*
|
|
|
|
* @param result is a DistributedQueryResult object to be sent to the server
|
|
|
|
*/
|
|
|
|
void addResult(const DistributedQueryResult& result);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Flush all of the collected results to the server
|
|
|
|
*/
|
|
|
|
Status flushCompleted();
|
|
|
|
|
2017-05-05 22:14:21 +00:00
|
|
|
// Setter for ID of currently executing request
|
|
|
|
static void setCurrentRequestId(const std::string& cReqId);
|
|
|
|
|
2015-09-07 18:09:06 +00:00
|
|
|
std::vector<DistributedQueryResult> results_;
|
|
|
|
|
2017-05-05 22:14:21 +00:00
|
|
|
// ID of the currently executing query
|
|
|
|
static std::string currentRequestId_;
|
|
|
|
|
2015-09-07 18:09:06 +00:00
|
|
|
private:
|
|
|
|
friend class DistributedTests;
|
|
|
|
FRIEND_TEST(DistributedTests, test_workflow);
|
|
|
|
};
|
|
|
|
}
|