osquery-1/include/osquery/tables.h

356 lines
12 KiB
C
Raw Normal View History

/*
* 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.
*
*/
2014-11-25 20:30:29 +00:00
#pragma once
#include <map>
2014-12-03 04:36:46 +00:00
#include <memory>
2014-11-25 20:30:29 +00:00
#include <vector>
#include <set>
2014-11-25 20:30:29 +00:00
#include <boost/lexical_cast.hpp>
2015-01-30 18:44:25 +00:00
#include <boost/property_tree/ptree.hpp>
2014-11-25 20:30:29 +00:00
2015-01-30 18:44:25 +00:00
#include <osquery/registry.h>
#include <osquery/core.h>
2015-05-24 01:52:42 +00:00
#include <osquery/database.h>
#include <osquery/status.h>
2014-11-25 20:30:29 +00:00
2015-04-12 02:50:35 +00:00
/// Allow Tables to use "tracked" deprecated OS APIs.
#define OSQUERY_USE_DEPRECATED(expr) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
expr; \
_Pragma("clang diagnostic pop") \
} while (0)
2014-11-25 20:30:29 +00:00
namespace osquery {
/**
* @brief The SQLite type affinities are available as macros
*
* Type affinities: TEXT, INTEGER, BIGINT
*
* You can represent any data that can be lexically casted to a string.
* Using the type affinity names helps table developers understand the data
* types they are storing, and more importantly how they are treated at query
* time.
*/
#define TEXT(x) boost::lexical_cast<std::string>(x)
/// See the affinity type documentation for TEXT.
2014-11-25 20:30:29 +00:00
#define INTEGER(x) boost::lexical_cast<std::string>(x)
/// See the affinity type documentation for TEXT.
2014-11-25 20:30:29 +00:00
#define BIGINT(x) boost::lexical_cast<std::string>(x)
/// See the affinity type documentation for TEXT.
2014-11-25 20:30:29 +00:00
#define UNSIGNED_BIGINT(x) boost::lexical_cast<std::string>(x)
/// See the affinity type documentation for TEXT.
#define DOUBLE(x) boost::lexical_cast<std::string>(x)
2014-11-25 20:30:29 +00:00
/**
* @brief The SQLite type affinities as represented as implementation literals.
*
* Type affinities: TEXT=std::string, INTEGER=int, BIGINT=long long int
*
* Just as the SQLite data is represented as lexically casted strings, as table
* may make use of the implementation language literals.
*/
2014-11-25 20:30:29 +00:00
#define TEXT_LITERAL std::string
/// See the literal type documentation for TEXT_LITERAL.
2014-11-25 20:30:29 +00:00
#define INTEGER_LITERAL int
/// See the literal type documentation for TEXT_LITERAL.
2014-11-25 20:30:29 +00:00
#define BIGINT_LITERAL long long int
/// See the literal type documentation for TEXT_LITERAL.
2014-11-25 20:30:29 +00:00
#define UNSIGNED_BIGINT_LITERAL unsigned long long int
/// See the literal type documentation for TEXT_LITERAL.
#define DOUBLE_LITERAL double
/// Cast an SQLite affinity type to the literal type.
2014-11-25 20:30:29 +00:00
#define AS_LITERAL(literal, value) boost::lexical_cast<literal>(value)
2015-01-12 18:02:44 +00:00
/// Helper alias for TablePlugin names.
2015-01-30 18:44:25 +00:00
typedef std::string TableName;
typedef std::vector<std::pair<std::string, std::string> > TableColumns;
2015-01-12 18:02:44 +00:00
typedef std::map<std::string, std::vector<std::string> > TableData;
/**
* @brief A ConstraintOperator is applied in an query predicate.
*
* If the query contains a join or where clause with a constraint operator and
* expression the table generator may limit the data appropriately.
*/
enum ConstraintOperator : unsigned char {
2014-11-25 20:30:29 +00:00
EQUALS = 2,
GREATER_THAN = 4,
LESS_THAN_OR_EQUALS = 8,
LESS_THAN = 16,
GREATER_THAN_OR_EQUALS = 32
};
/// Type for flags for what constraint operators are admissible.
typedef unsigned char ConstraintOperatorFlag;
/// Flag for any operator type.
#define ANY_OP 0xFFU
/**
* @brief A Constraint is an operator and expression.
*
* The constraint is applied to columns which have literal and affinity types.
*/
2014-11-25 20:30:29 +00:00
struct Constraint {
unsigned char op;
std::string expr;
/// Construct a Constraint with the most-basic information, the operator.
2015-02-24 11:47:12 +00:00
explicit Constraint(unsigned char _op) { op = _op; }
2015-01-12 18:02:44 +00:00
// A constraint list in a context knows only the operator at creation.
2015-04-12 02:50:35 +00:00
explicit Constraint(unsigned char _op, const std::string& _expr)
: op(_op), expr(_expr) {}
2014-11-25 20:30:29 +00:00
};
/**
* @brief A ConstraintList is a set of constraints for a column. This list
* should be mapped to a left-hand-side column name.
*
* The table generator does not need to check each constraint in its decision
* logic. The common constraint checking patterns (match) are abstracted using
* simple logic operators on the literal SQLite affinity types.
*
* A constraint list supports all AS_LITERAL types, and all ConstraintOperators.
*/
2014-11-25 20:30:29 +00:00
struct ConstraintList {
/// The SQLite affinity type.
std::string affinity;
/**
* @brief Check if an expression matches the query constraints.
*
2015-01-12 18:02:44 +00:00
* Evaluate ALL constraints in this ConstraintList against the string
2015-04-12 02:50:35 +00:00
* expression. The affinity of the constraint will be used as the affinite
2015-01-12 18:02:44 +00:00
* and lexical type of the expression and set of constraint expressions.
* If there are no predicate constraints in this list, all expression will
* match. Constraints are limitations.
2015-01-12 18:02:44 +00:00
*
* @param expr a SQL type expression of the column literal type to check.
* @return If the expression matched all constraints.
*/
2015-02-11 03:18:56 +00:00
bool matches(const std::string& expr) const;
2014-11-25 20:30:29 +00:00
2015-01-12 18:02:44 +00:00
/**
* @brief Check if an expression matches the query constraints.
*
* `matches` also supports the set of SQL affinite types.
* The expression expr will be evaluated as a string and compared using
* the affinity of the constraint.
*
* @param expr a SQL type expression of the column literal type to check.
* @return If the expression matched all constraints.
*/
template <typename T>
2015-02-11 03:18:56 +00:00
bool matches(const T& expr) const {
2015-01-12 18:02:44 +00:00
return matches(TEXT(expr));
}
/**
* @brief Check and return if there are constraints on this column.
2015-01-12 18:02:44 +00:00
*
* A ConstraintList is used in a ConstraintMap with a column name as the
2015-01-12 18:02:44 +00:00
* map index. Tables that act on optional constraints should check if any
* constraint was provided. The ops parameter serves to specify which
* operators we want to check existence for.
2015-01-12 18:02:44 +00:00
*
* @param ops (Optional: default ANY_OP) The operators types to look for.
2015-01-12 18:02:44 +00:00
* @return true if any constraint exists.
*/
bool exists(const ConstraintOperatorFlag ops = ANY_OP) const {
if (ops == ANY_OP) {
return (constraints_.size() > 0);
} else {
for (const struct Constraint &c : constraints_) {
if (c.op & ops) {
return true;
}
}
return false;
}
}
2015-01-12 18:02:44 +00:00
/**
2015-04-12 02:50:35 +00:00
* @brief Check if a constraint exist AND matches the type expression.
2015-01-12 18:02:44 +00:00
*
* See ConstraintList::exists and ConstraintList::matches.
*
* @param expr The expression to match.
* @return true if any constraint exists AND matches the type expression.
*/
2015-01-12 18:02:44 +00:00
template <typename T>
2015-02-11 03:18:56 +00:00
bool existsAndMatches(const T& expr) const {
return (exists() && matches(expr));
}
2015-01-12 18:02:44 +00:00
/**
* @brief Check if a constraint is missing or matches a type expression.
*
* A ConstraintList is used in a ConstraintMap with a column name as the
2015-01-12 18:02:44 +00:00
* map index. Tables that act on required constraints can make decisions
* on missing constraints or a constraint match.
*
* @param expr The expression to match.
* @return true if constraint is missing or matches the type expression.
*/
template <typename T>
2015-02-11 03:18:56 +00:00
bool notExistsOrMatches(const T& expr) const {
return (!exists() || matches(expr));
}
/**
2015-01-12 18:02:44 +00:00
* @brief Helper templated function for ConstraintList::matches.
*/
2014-11-25 20:30:29 +00:00
template <typename T>
2015-02-11 03:18:56 +00:00
bool literal_matches(const T& base_expr) const;
2014-11-25 20:30:29 +00:00
/**
* @brief Get all expressions for a given ConstraintOperator.
*
* This is most useful if the table generation requires as column.
* The generator may `getAll(EQUALS)` then iterate.
*
* @param op the ConstraintOperator.
* @return A list of TEXT%-represented types matching the operator.
*/
2015-02-11 03:18:56 +00:00
std::set<std::string> getAll(ConstraintOperator op) const;
/// See ConstraintList::getAll, but as a selected literal type.
template<typename T>
2015-02-11 03:18:56 +00:00
std::set<T> getAll(ConstraintOperator op) const {
std::set<T> literal_matches;
auto matches = getAll(op);
for (const auto& match : matches) {
literal_matches.insert(AS_LITERAL(T, match));
}
return literal_matches;
}
2014-11-25 20:30:29 +00:00
/// Constraint list accessor, types and operator.
const std::vector<struct Constraint> getAll() const { return constraints_; }
/**
* @brief Add a new Constraint to the list of constraints.
*
* @param constraint a new operator/expression to constrain.
*/
2014-11-25 20:30:29 +00:00
void add(const struct Constraint& constraint) {
2015-01-12 18:02:44 +00:00
constraints_.push_back(constraint);
2014-11-25 20:30:29 +00:00
}
2015-01-12 18:02:44 +00:00
2015-01-30 18:44:25 +00:00
/**
* @brief Serialize a ConstraintList into a property tree.
*
* The property tree will use the format:
* {
* "affinity": affinity,
* "list": [
* {"op": op, "expr": expr}, ...
* ]
* }
*/
void serialize(boost::property_tree::ptree& tree) const;
/// See ConstraintList::unserialize.
2015-01-30 18:44:25 +00:00
void unserialize(const boost::property_tree::ptree& tree);
2015-04-12 02:50:35 +00:00
ConstraintList() : affinity("TEXT") {}
2015-01-12 18:02:44 +00:00
private:
/// List of constraint operator/expressions.
std::vector<struct Constraint> constraints_;
private:
FRIEND_TEST(TablesTests, test_constraint_list);
2014-11-25 20:30:29 +00:00
};
/// Pass a constraint map to the query request.
typedef std::map<std::string, struct ConstraintList> ConstraintMap;
2015-04-12 02:50:35 +00:00
/// Populate a constraint list from a query's parsed predicate.
2014-11-25 20:30:29 +00:00
typedef std::vector<std::pair<std::string, struct Constraint> > ConstraintSet;
/**
* @brief A QueryContext is provided to every table generator for optimization
* on query components like predicate constraints and limits.
*/
struct QueryContext {
2014-11-25 20:30:29 +00:00
ConstraintMap constraints;
/// Support a limit to the number of results.
int limit;
2015-01-30 18:44:25 +00:00
QueryContext() : limit(0) {}
2014-11-25 20:30:29 +00:00
};
typedef struct QueryContext QueryContext;
2014-11-25 20:30:29 +00:00
typedef struct Constraint Constraint;
2015-01-12 18:02:44 +00:00
/**
* @brief The TablePlugin defines the name, types, and column information.
*
* To attach a virtual table create a TablePlugin subclass and register the
* virtual table name as the plugin ID. osquery will enumerate all registered
2015-04-12 02:50:35 +00:00
* TablePlugins and attempt to attach them to SQLite at instantiation.
*
* Note: When updating this class, be sure to update the corresponding template
* in osquery/tables/templates/default.cpp.in
2015-01-12 18:02:44 +00:00
*/
2015-01-30 18:44:25 +00:00
class TablePlugin : public Plugin {
protected:
2015-02-11 03:18:56 +00:00
virtual TableColumns columns() const {
2015-01-30 18:44:25 +00:00
TableColumns columns;
return columns;
}
2015-01-12 18:02:44 +00:00
2015-01-30 18:44:25 +00:00
virtual QueryData generate(QueryContext& request) {
QueryData data;
return data;
}
2015-01-12 18:02:44 +00:00
protected:
std::string columnDefinition() const;
PluginResponse routeInfo() const;
2015-01-12 18:02:44 +00:00
public:
2015-01-30 18:44:25 +00:00
/// Public API methods.
Status call(const PluginRequest& request, PluginResponse& response);
2015-01-12 18:02:44 +00:00
2015-01-30 18:44:25 +00:00
public:
/// Helper data structure transformation methods
static void setRequestFromContext(const QueryContext& context,
PluginRequest& request);
static void setResponseFromQueryData(const QueryData& data,
PluginResponse& response);
static void setContextFromRequest(const PluginRequest& request,
QueryContext& context);
public:
/// When external table plugins are registered the core will attach them
/// as virtual tables to the SQL internal implementation
static Status addExternal(const std::string& name,
const PluginResponse& info);
static void removeExternal(const std::string& name);
private:
FRIEND_TEST(VirtualTableTests, test_tableplugin_columndefinition);
FRIEND_TEST(VirtualTableTests, test_tableplugin_statement);
2015-01-12 18:02:44 +00:00
};
/// Helper method to generate the virtual table CREATE statement.
std::string columnDefinition(const TableColumns& columns);
std::string columnDefinition(const PluginResponse& response);
CREATE_LAZY_REGISTRY(TablePlugin, "table");
2014-11-25 20:30:29 +00:00
}