2014-07-31 00:35:19 +00:00
|
|
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <mutex>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <rocksdb/env.h>
|
|
|
|
#include <rocksdb/options.h>
|
|
|
|
|
2014-10-27 01:39:03 +00:00
|
|
|
#include "osquery/database/db_handle.h"
|
|
|
|
#include "osquery/filesystem.h"
|
2014-08-05 23:13:55 +00:00
|
|
|
#include "osquery/status.h"
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-08-05 23:13:55 +00:00
|
|
|
using osquery::Status;
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
namespace osquery {
|
2014-07-31 00:35:19 +00:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Constants
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
const std::string kConfigurations = "configurations";
|
|
|
|
const std::string kQueries = "queries";
|
2014-09-19 08:54:33 +00:00
|
|
|
const std::string kEvents = "events";
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-09-22 21:35:07 +00:00
|
|
|
const std::vector<std::string> kDomains = {kConfigurations, kQueries, kEvents};
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-10-27 18:55:28 +00:00
|
|
|
DEFINE_osquery_flag(string,
|
|
|
|
db_path,
|
|
|
|
"/tmp/rocksdb-osquery",
|
2014-10-29 21:25:25 +00:00
|
|
|
"If using a disk-based backing store, specify a path.");
|
2014-10-27 01:39:03 +00:00
|
|
|
|
2014-10-27 18:55:28 +00:00
|
|
|
DEFINE_osquery_flag(bool,
|
|
|
|
use_in_memory_database,
|
|
|
|
false,
|
|
|
|
"Keep osquery backing-store in memory.");
|
2014-10-27 01:39:03 +00:00
|
|
|
|
2014-07-31 00:35:19 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// constructors and destructors
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-10-27 01:39:03 +00:00
|
|
|
DBHandle::DBHandle(const std::string& path, bool in_memory) {
|
2014-07-31 00:35:19 +00:00
|
|
|
options_.create_if_missing = true;
|
|
|
|
options_.create_missing_column_families = true;
|
|
|
|
|
|
|
|
if (in_memory) {
|
|
|
|
// Remove when upgrading to RocksDB 3.2
|
|
|
|
// Replace with:
|
|
|
|
// options_.env = rocksdb::NewMemEnv(rocksdb::Env::Default());
|
|
|
|
throw std::domain_error("Requires RocksDB 3.3 https://fburl.com/27350299");
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
column_families_.push_back(rocksdb::ColumnFamilyDescriptor(
|
|
|
|
rocksdb::kDefaultColumnFamilyName, rocksdb::ColumnFamilyOptions()));
|
2014-07-31 00:35:19 +00:00
|
|
|
|
2014-08-29 02:21:52 +00:00
|
|
|
for (const auto& cf_name : kDomains) {
|
2014-08-15 07:25:30 +00:00
|
|
|
column_families_.push_back(rocksdb::ColumnFamilyDescriptor(
|
|
|
|
cf_name, rocksdb::ColumnFamilyOptions()));
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
|
|
|
|
2014-10-30 22:03:05 +00:00
|
|
|
if (pathExists(path).ok() && !isWritable(path).ok()) {
|
2014-10-27 01:39:03 +00:00
|
|
|
throw std::domain_error("Cannot write to RocksDB path: " + path);
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
status_ =
|
2014-10-28 00:37:36 +00:00
|
|
|
rocksdb::DB::Open(options_, path, column_families_, &handles_, &db_);
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DBHandle::~DBHandle() {
|
|
|
|
for (auto handle : handles_) {
|
2014-11-11 16:17:28 +00:00
|
|
|
delete handle;
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
2014-11-11 16:17:28 +00:00
|
|
|
delete db_;
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// getInstance methods
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::shared_ptr<DBHandle> DBHandle::getInstance() {
|
2014-10-27 01:39:03 +00:00
|
|
|
return getInstance(FLAGS_db_path, FLAGS_use_in_memory_database);
|
2014-07-31 00:35:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<DBHandle> DBHandle::getInstanceInMemory() {
|
|
|
|
// Remove when upgrading to RocksDB 3.3
|
|
|
|
throw std::domain_error("Requires RocksDB 3.3 https://fburl.com/27350299");
|
|
|
|
return getInstance("", true);
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
std::shared_ptr<DBHandle> DBHandle::getInstanceAtPath(const std::string& path) {
|
2014-07-31 00:35:19 +00:00
|
|
|
return getInstance(path, false);
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
std::shared_ptr<DBHandle> DBHandle::getInstance(const std::string& path,
|
|
|
|
bool in_memory) {
|
2014-07-31 00:35:19 +00:00
|
|
|
static std::shared_ptr<DBHandle> db_handle =
|
2014-08-15 07:25:30 +00:00
|
|
|
std::shared_ptr<DBHandle>(new DBHandle(path, in_memory));
|
2014-07-31 00:35:19 +00:00
|
|
|
return db_handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// getters and setters
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-08-05 23:13:55 +00:00
|
|
|
osquery::Status DBHandle::getStatus() {
|
2014-07-31 00:35:19 +00:00
|
|
|
return Status(status_.code(), status_.ToString());
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
rocksdb::DB* DBHandle::getDB() { return db_; }
|
2014-07-31 00:35:19 +00:00
|
|
|
|
|
|
|
rocksdb::ColumnFamilyHandle* DBHandle::getHandleForColumnFamily(
|
2014-08-15 07:25:30 +00:00
|
|
|
const std::string& cf) {
|
2014-07-31 00:35:19 +00:00
|
|
|
for (int i = 0; i < kDomains.size(); i++) {
|
|
|
|
if (kDomains[i] == cf) {
|
|
|
|
return handles_[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Data manipulation methods
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
osquery::Status DBHandle::Get(const std::string& domain,
|
|
|
|
const std::string& key,
|
|
|
|
std::string& value) {
|
2014-07-31 00:35:19 +00:00
|
|
|
auto s = getDB()->Get(
|
2014-08-15 07:25:30 +00:00
|
|
|
rocksdb::ReadOptions(), getHandleForColumnFamily(domain), key, &value);
|
2014-07-31 00:35:19 +00:00
|
|
|
return Status(s.code(), s.ToString());
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
osquery::Status DBHandle::Put(const std::string& domain,
|
|
|
|
const std::string& key,
|
|
|
|
const std::string& value) {
|
2014-07-31 00:35:19 +00:00
|
|
|
auto s = getDB()->Put(
|
2014-08-15 07:25:30 +00:00
|
|
|
rocksdb::WriteOptions(), getHandleForColumnFamily(domain), key, value);
|
2014-07-31 00:35:19 +00:00
|
|
|
return Status(s.code(), s.ToString());
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
osquery::Status DBHandle::Delete(const std::string& domain,
|
|
|
|
const std::string& key) {
|
2014-07-31 00:35:19 +00:00
|
|
|
auto s = getDB()->Delete(
|
2014-08-15 07:25:30 +00:00
|
|
|
rocksdb::WriteOptions(), getHandleForColumnFamily(domain), key);
|
2014-07-31 00:35:19 +00:00
|
|
|
return Status(s.code(), s.ToString());
|
|
|
|
}
|
|
|
|
|
2014-08-15 07:25:30 +00:00
|
|
|
osquery::Status DBHandle::Scan(const std::string& domain,
|
|
|
|
std::vector<std::string>& results) {
|
|
|
|
auto it = getDB()->NewIterator(rocksdb::ReadOptions(),
|
|
|
|
getHandleForColumnFamily(domain));
|
2014-07-31 00:35:19 +00:00
|
|
|
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
|
|
|
results.push_back(it->key().ToString());
|
|
|
|
}
|
|
|
|
delete it;
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
2014-08-15 07:25:30 +00:00
|
|
|
}
|