2014-12-18 18:50:47 +00:00
|
|
|
/*
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2014-12-18 18:50:47 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-01-23 22:52:07 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2014-12-18 18:50:47 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2014-09-26 07:28:18 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2015-05-24 01:52:42 +00:00
|
|
|
#include <osquery/database.h>
|
2015-03-18 19:01:58 +00:00
|
|
|
#include <osquery/flags.h>
|
2015-01-26 08:02:02 +00:00
|
|
|
#include <osquery/tables.h>
|
2014-09-26 07:28:18 +00:00
|
|
|
|
|
|
|
namespace osquery {
|
2015-03-18 19:01:58 +00:00
|
|
|
|
|
|
|
DECLARE_int32(value_max);
|
|
|
|
|
2014-09-26 07:28:18 +00:00
|
|
|
/**
|
|
|
|
* @brief The core interface to executing osquery SQL commands
|
|
|
|
*
|
|
|
|
* @code{.cpp}
|
|
|
|
* auto sql = SQL("SELECT * FROM time");
|
|
|
|
* if (sql.ok()) {
|
|
|
|
* LOG(INFO) << "============================";
|
|
|
|
* for (const auto& row : sql.rows()) {
|
|
|
|
* for (const auto& it : row) {
|
|
|
|
* LOG(INFO) << it.first << " => " << it.second;
|
|
|
|
* }
|
|
|
|
* LOG(INFO) << "============================";
|
|
|
|
* }
|
|
|
|
* } else {
|
|
|
|
* LOG(ERROR) << sql.getMessageString();
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*/
|
|
|
|
class SQL {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* @brief Instantiate an instance of the class with a query
|
|
|
|
*
|
|
|
|
* @param q An osquery SQL query
|
|
|
|
*/
|
|
|
|
explicit SQL(const std::string& q);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Accessor for the rows returned by the query
|
|
|
|
*
|
|
|
|
* @return A QueryData object of the query results
|
|
|
|
*/
|
2015-09-07 18:09:06 +00:00
|
|
|
const QueryData& rows() const;
|
2014-09-26 07:28:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Accessor to switch off of when checking the success of a query
|
|
|
|
*
|
|
|
|
* @return A bool indicating the success or failure of the operation
|
|
|
|
*/
|
|
|
|
bool ok();
|
|
|
|
|
2015-01-23 22:52:07 +00:00
|
|
|
/**
|
|
|
|
* @brief Get the status returned by the query
|
|
|
|
*
|
|
|
|
* @return The query status
|
|
|
|
*/
|
2015-09-07 18:09:06 +00:00
|
|
|
const Status& getStatus() const;
|
2015-01-23 22:52:07 +00:00
|
|
|
|
2014-09-26 07:28:18 +00:00
|
|
|
/**
|
|
|
|
* @brief Accessor for the message string indicating the status of the query
|
|
|
|
*
|
|
|
|
* @return The message string indicating the status of the query
|
|
|
|
*/
|
|
|
|
std::string getMessageString();
|
|
|
|
|
2015-11-02 08:46:04 +00:00
|
|
|
/// ASCII escape the results of the query.
|
|
|
|
void escapeResults();
|
2014-09-26 07:28:18 +00:00
|
|
|
|
2015-11-02 08:46:04 +00:00
|
|
|
public:
|
2014-11-30 05:48:56 +00:00
|
|
|
/**
|
|
|
|
* @brief Get all, 'SELECT * ...', results given a virtual table name.
|
|
|
|
*
|
2015-01-26 08:02:02 +00:00
|
|
|
* @param table The name of the virtual table.
|
2014-11-30 05:48:56 +00:00
|
|
|
* @return A QueryData object of the 'SELECT *...' query results.
|
|
|
|
*/
|
|
|
|
static QueryData selectAllFrom(const std::string& table);
|
|
|
|
|
2015-01-26 08:02:02 +00:00
|
|
|
/**
|
|
|
|
* @brief Get all with constraint, 'SELECT * ... where', results given
|
|
|
|
* a virtual table name and single constraint
|
|
|
|
*
|
|
|
|
* @param table The name of the virtual table.
|
|
|
|
* @param column Table column name to apply constraint.
|
|
|
|
* @param op The SQL comparitive operator.
|
|
|
|
* @param expr The constraint expression.
|
|
|
|
* @return A QueryData object of the 'SELECT *...' query results.
|
|
|
|
*/
|
|
|
|
static QueryData selectAllFrom(const std::string& table,
|
|
|
|
const std::string& column,
|
2015-05-20 20:27:53 +00:00
|
|
|
ConstraintOperator op,
|
2015-01-26 08:02:02 +00:00
|
|
|
const std::string& expr);
|
|
|
|
|
2015-01-23 22:52:07 +00:00
|
|
|
protected:
|
2014-09-26 07:28:18 +00:00
|
|
|
/**
|
|
|
|
* @brief Private default constructor
|
|
|
|
*
|
|
|
|
* The osquery::SQL class should only ever be instantiated with a query
|
|
|
|
*/
|
2014-10-28 00:37:36 +00:00
|
|
|
SQL(){};
|
2014-09-26 07:28:18 +00:00
|
|
|
|
|
|
|
/// the internal member which holds the results of the query
|
|
|
|
QueryData results_;
|
|
|
|
|
|
|
|
/// the internal member which holds the status of the query
|
|
|
|
Status status_;
|
|
|
|
};
|
2015-02-03 05:21:36 +00:00
|
|
|
|
2015-02-23 05:56:52 +00:00
|
|
|
/**
|
|
|
|
* @brief The osquery SQL implementation is managed as a plugin.
|
|
|
|
*
|
|
|
|
* The osquery RegistryFactory creates a Registry type called "sql", then
|
|
|
|
* requires a single plugin registration also called "sql". Calls within
|
|
|
|
* the application use boilerplate methods that wrap Registry::call%s to this
|
|
|
|
* well-known registry and registry item name.
|
|
|
|
*
|
|
|
|
* Abstracting the SQL implementation behind the osquery registry allows
|
|
|
|
* the SDK (libosquery) to describe how the SQL implementation is used without
|
|
|
|
* having dependencies on the thrird-party code.
|
|
|
|
*
|
|
|
|
* When osqueryd/osqueryi are built libosquery_additional, the library which
|
|
|
|
* provides the core plugins and core virtual tables, includes SQLite as
|
|
|
|
* the SQL implementation.
|
|
|
|
*/
|
2015-02-19 23:19:00 +00:00
|
|
|
class SQLPlugin : public Plugin {
|
|
|
|
public:
|
2015-02-23 05:56:52 +00:00
|
|
|
/// Run a SQL query string against the SQL implementation.
|
2015-02-19 23:19:00 +00:00
|
|
|
virtual Status query(const std::string& q, QueryData& results) const = 0;
|
2015-02-23 05:56:52 +00:00
|
|
|
/// Use the SQL implementation to parse a query string and return details
|
|
|
|
/// (name, type) about the columns.
|
2015-02-19 23:19:00 +00:00
|
|
|
virtual Status getQueryColumns(const std::string& q,
|
2015-05-20 20:27:53 +00:00
|
|
|
TableColumns& columns) const = 0;
|
2015-02-19 23:19:00 +00:00
|
|
|
|
2015-02-23 05:56:52 +00:00
|
|
|
/**
|
|
|
|
* @brief Attach a table at runtime.
|
|
|
|
*
|
|
|
|
* The SQL implementation plugin may need to manage how virtual tables are
|
|
|
|
* attached at run time. In the case of SQLite where a single DB object is
|
|
|
|
* managed, tables are enumerated and attached during initialization.
|
|
|
|
*/
|
|
|
|
virtual Status attach(const std::string& name) {
|
|
|
|
return Status(0, "Not used");
|
|
|
|
}
|
|
|
|
/// Tables may be detached by name.
|
|
|
|
virtual void detach(const std::string& name) {}
|
|
|
|
|
2015-02-19 23:19:00 +00:00
|
|
|
public:
|
|
|
|
Status call(const PluginRequest& request, PluginResponse& response);
|
|
|
|
};
|
|
|
|
|
2015-02-03 05:21:36 +00:00
|
|
|
/**
|
|
|
|
* @brief Execute a query
|
|
|
|
*
|
|
|
|
* This is a lower-level version of osquery::SQL. Prefer to use osquery::SQL.
|
|
|
|
*
|
|
|
|
* @code{.cpp}
|
|
|
|
* std::string q = "SELECT * FROM time;";
|
|
|
|
* QueryData results;
|
|
|
|
* auto status = query(q, results);
|
|
|
|
* if (status.ok()) {
|
|
|
|
* for (const auto& each : results) {
|
|
|
|
* for (const auto& it : each) {
|
|
|
|
* LOG(INFO) << it.first << ": " << it.second;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* } else {
|
|
|
|
* LOG(ERROR) << "Error: " << status.what();
|
|
|
|
* }
|
|
|
|
* @endcode
|
|
|
|
*
|
|
|
|
* @param q the query to execute
|
|
|
|
* @param results A QueryData structure to emit result rows on success.
|
|
|
|
* @return A status indicating query success.
|
|
|
|
*/
|
|
|
|
Status query(const std::string& query, QueryData& results);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Analyze a query, providing information about the result columns
|
|
|
|
*
|
|
|
|
* This function asks SQLite to determine what the names and types are of the
|
|
|
|
* result columns of the provided query. Only table columns (not expressions or
|
|
|
|
* subqueries) can have their types determined. Types that are not determined
|
|
|
|
* are indicated with the string "UNKNOWN".
|
|
|
|
*
|
|
|
|
* @param q the query to analyze
|
|
|
|
* @param columns the vector to fill with column information
|
|
|
|
*
|
|
|
|
* @return status indicating success or failure of the operation
|
|
|
|
*/
|
2015-05-20 20:27:53 +00:00
|
|
|
Status getQueryColumns(const std::string& q, TableColumns& columns);
|
2015-01-23 22:52:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* @brief A mocked subclass of SQL useful for testing
|
|
|
|
*/
|
|
|
|
class MockSQL : public SQL {
|
|
|
|
public:
|
2015-02-18 18:51:26 +00:00
|
|
|
explicit MockSQL() : MockSQL(QueryData{}) {}
|
2015-01-23 22:52:07 +00:00
|
|
|
explicit MockSQL(const QueryData& results) : MockSQL(results, Status()) {}
|
|
|
|
explicit MockSQL(const QueryData& results, const Status& status) {
|
|
|
|
results_ = results;
|
|
|
|
status_ = status;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-04 02:40:24 +00:00
|
|
|
CREATE_LAZY_REGISTRY(SQLPlugin, "sql");
|
2014-09-26 07:28:18 +00:00
|
|
|
}
|