osquery-1/osquery/sql/virtual_sqlite_table.cpp
Jonathan Keljo 1870fd86d8 Introduce TableRow interface
Summary:
Continuing to march toward low-overhead, type-safe table rows, this commit
changes `TableRow` to be an interface rather than simply an alias for `Row`.
Accordingly, `DynamicTableRow` becomes an implementation of that interface
backed by a `Row`. The few remaining pieces of code that treated `TableRow`s as
`Row`s now call methods on the `TableRow` interface. Subsequent commits will
add code generation for strongly-typed table-specific implementations of
`TableRow`.

(Adapted from https://github.com/facebook/osquery/pull/5198)

Reviewed By: guliashvili

Differential Revision: D13438015

fbshipit-source-id: 61d5547e878e519c9706f94f844aab9d3e553410
2019-01-09 13:50:15 -08:00

118 lines
3.3 KiB
C++

/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under both the Apache 2.0 license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
* in the COPYING file in the root directory of this source tree).
* You may select, at your option, one of the above-listed licenses.
*/
#include <osquery/core.h>
#include <osquery/filesystem/filesystem.h>
#include <osquery/logger.h>
#include <osquery/sql.h>
#include <osquery/utils/info/platform_type.h>
#include "osquery/sql/dynamic_table_row.h"
#include "osquery/sql/sqlite_util.h"
namespace fs = boost::filesystem;
namespace osquery {
const char* getSystemVFS(bool respect_locking) {
if (respect_locking) {
return nullptr;
}
if (isPlatform(PlatformType::TYPE_POSIX)) {
return "unix-none";
} else if (isPlatform(PlatformType::TYPE_WINDOWS)) {
return "win32-none";
}
return nullptr;
}
Status genSqliteTableRow(sqlite3_stmt* stmt,
TableRows& qd,
const fs::path& sqlite_db) {
auto r = make_table_row();
for (int i = 0; i < sqlite3_column_count(stmt); ++i) {
auto column_name = std::string(sqlite3_column_name(stmt, i));
auto column_type = sqlite3_column_type(stmt, i);
switch (column_type) {
case SQLITE_TEXT: {
auto text_value = sqlite3_column_text(stmt, i);
if (text_value != nullptr) {
r[column_name] = std::string(reinterpret_cast<const char*>(text_value));
}
break;
}
case SQLITE_FLOAT: {
auto float_value = sqlite3_column_double(stmt, i);
r[column_name] = DOUBLE(float_value);
break;
}
case SQLITE_INTEGER: {
auto int_value = sqlite3_column_int(stmt, i);
r[column_name] = INTEGER(int_value);
break;
}
}
}
if (r.count("path") > 0) {
LOG(WARNING) << "Row contains a path key, refusing to overwrite";
} else {
r["path"] = sqlite_db.string();
}
qd.push_back(std::move(r));
return Status();
}
Status genTableRowsForSqliteTable(const fs::path& sqlite_db,
const std::string& sqlite_query,
TableRows& results,
bool respect_locking) {
sqlite3* db = nullptr;
if (!pathExists(sqlite_db).ok()) {
return Status(1, "Database path does not exist");
}
auto rc = sqlite3_open_v2(
sqlite_db.string().c_str(),
&db,
(SQLITE_OPEN_READONLY | SQLITE_OPEN_PRIVATECACHE | SQLITE_OPEN_NOMUTEX),
getSystemVFS(respect_locking));
if (rc != SQLITE_OK || db == nullptr) {
VLOG(1) << "Cannot open specified database: "
<< getStringForSQLiteReturnCode(rc);
if (db != nullptr) {
sqlite3_close(db);
}
return Status(1, "Could not open database");
}
sqlite3_stmt* stmt = nullptr;
rc = sqlite3_prepare_v2(db, sqlite_query.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
sqlite3_close(db);
VLOG(1) << "Could not prepare database at path: " << sqlite_db;
return Status(rc, "Could not prepare database");
}
while ((sqlite3_step(stmt)) == SQLITE_ROW) {
auto s = genSqliteTableRow(stmt, results, sqlite_db);
if (!s.ok()) {
break;
}
}
// Close handles and free memory
sqlite3_finalize(stmt);
sqlite3_close(db);
return Status{};
}
} // namespace osquery