osquery-1/osquery/sql/sql.cpp

157 lines
4.1 KiB
C++
Raw Normal View History

2015-02-03 05:21:36 +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.
*
*/
#include <sstream>
#include <osquery/core.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/tables.h>
#include <osquery/registry.h>
namespace osquery {
2015-03-18 19:01:58 +00:00
FLAG(int32, value_max, 512, "Maximum returned row value size");
const std::map<ConstraintOperator, std::string> kSQLOperatorRepr = {
{EQUALS, "="},
{GREATER_THAN, ">"},
{LESS_THAN_OR_EQUALS, "<="},
{LESS_THAN, "<"},
{GREATER_THAN_OR_EQUALS, ">="},
2015-02-03 05:21:36 +00:00
};
typedef unsigned char byte;
2015-02-03 05:21:36 +00:00
SQL::SQL(const std::string& q) { status_ = query(q, results_); }
2015-09-07 18:09:06 +00:00
const QueryData& SQL::rows() const { return results_; }
2015-02-03 05:21:36 +00:00
bool SQL::ok() { return status_.ok(); }
2015-09-07 18:09:06 +00:00
const Status& SQL::getStatus() const { return status_; }
2015-02-03 05:21:36 +00:00
std::string SQL::getMessageString() { return status_.toString(); }
void escapeNonPrintableBytes(std::string& data) {
std::string escaped;
// clang-format off
char const hex_chars[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
};
// clang-format on
bool needs_replacement = false;
for (size_t i = 0; i < data.length(); i++) {
if (((byte)data[i]) < 0x20 || ((byte)data[i]) >= 0x80) {
needs_replacement = true;
escaped += "\\x";
escaped += hex_chars[(((byte)data[i])) >> 4];
escaped += hex_chars[((byte)data[i] & 0x0F) >> 0];
} else {
escaped += data[i];
}
}
// Only replace if any escapes were made.
if (needs_replacement) {
data = escaped;
}
}
void SQL::escapeResults() {
for (auto& row : results_) {
for (auto& column : row) {
escapeNonPrintableBytes(column.second);
}
2015-02-03 05:21:36 +00:00
}
}
QueryData SQL::selectAllFrom(const std::string& table) {
PluginResponse response;
2015-07-02 23:47:16 +00:00
PluginRequest request = {{"action", "generate"}};
Registry::call("table", table, request, response);
return response;
2015-02-03 05:21:36 +00:00
}
QueryData SQL::selectAllFrom(const std::string& table,
const std::string& column,
ConstraintOperator op,
2015-02-03 05:21:36 +00:00
const std::string& expr) {
PluginResponse response;
PluginRequest request = {{"action", "generate"}};
QueryContext ctx;
ctx.constraints[column].add(Constraint(op, expr));
2015-02-03 05:21:36 +00:00
TablePlugin::setRequestFromContext(ctx, request);
Registry::call("table", table, request, response);
return response;
2015-02-03 05:21:36 +00:00
}
2015-02-19 23:19:00 +00:00
Status SQLPlugin::call(const PluginRequest& request, PluginResponse& response) {
response.clear();
if (request.count("action") == 0) {
return Status(1, "SQL plugin must include a request action");
}
if (request.at("action") == "query") {
return this->query(request.at("query"), response);
} else if (request.at("action") == "columns") {
TableColumns columns;
2015-02-19 23:19:00 +00:00
auto status = this->getQueryColumns(request.at("query"), columns);
// Convert columns to response
for (const auto& column : columns) {
response.push_back(
{{"n", column.first}, {"t", columnTypeName(column.second)}});
2015-02-19 23:19:00 +00:00
}
return status;
} else if (request.at("action") == "attach") {
// Attach a virtual table name using an optional included definition.
return this->attach(request.at("table"));
} else if (request.at("action") == "detach") {
this->detach(request.at("table"));
return Status(0, "OK");
2015-02-19 23:19:00 +00:00
}
return Status(1, "Unknown action");
}
2015-02-03 05:21:36 +00:00
Status query(const std::string& q, QueryData& results) {
2015-02-19 23:19:00 +00:00
return Registry::call(
"sql", "sql", {{"action", "query"}, {"query", q}}, results);
2015-02-03 05:21:36 +00:00
}
Status getQueryColumns(const std::string& q, TableColumns& columns) {
2015-02-19 23:19:00 +00:00
PluginResponse response;
auto status = Registry::call(
"sql", "sql", {{"action", "columns"}, {"query", q}}, response);
// Convert response to columns
for (const auto& item : response) {
columns.push_back(make_pair(item.at("n"), columnTypeName(item.at("t"))));
2015-02-19 23:19:00 +00:00
}
return status;
2015-02-03 05:21:36 +00:00
}
}