2015-01-30 18:44:25 +00:00
|
|
|
/*
|
2016-02-11 19:48:58 +00:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2015-01-30 18:44:25 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
#include <cstdlib>
|
2015-01-30 18:44:25 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
2016-05-17 19:39:11 +00:00
|
|
|
#ifndef WIN32
|
2015-03-04 16:45:21 +00:00
|
|
|
#include <dlfcn.h>
|
2016-05-17 19:39:11 +00:00
|
|
|
#endif
|
2015-03-04 16:45:21 +00:00
|
|
|
|
2015-02-23 05:56:52 +00:00
|
|
|
#include <osquery/extensions.h>
|
2015-02-19 01:19:45 +00:00
|
|
|
#include <osquery/logger.h>
|
2015-01-30 18:44:25 +00:00
|
|
|
#include <osquery/registry.h>
|
|
|
|
|
2016-02-12 17:39:20 +00:00
|
|
|
#include "osquery/core/conversions.h"
|
2016-09-02 22:04:03 +00:00
|
|
|
#include "osquery/core/json.h"
|
2017-01-07 20:21:35 +00:00
|
|
|
#include "osquery/core/process.h"
|
2016-02-12 17:39:20 +00:00
|
|
|
|
[fix #1390] query pack re-org
This commit contains the features specified in #1390 as well as a
refactoring of the general osquery configuration code.
The API for the config plugins hasn't changed, although now there's a
`genPack` method that config plugins can implement. If a plugin doesn't
implement `genPack`, then the map<string, string> format cannot be used.
The default config plugin, the filesystem plugin, now implements
`genPack`, so existing query packs code will continue to work as it
always has.
Now many other config plugins can implement custom pack handling for
what makes sense in their context. `genPacks` is not a pure virtual, so
it doesn't have to be implemented in your plugin if you don't want to
use it. Also, more importantly, all config plugins can use the standard
inline pack format if they want to use query packs. Which is awesome.
For more information, refer to #1390, the documentation and the doxygen
comments included with this pull requests, as well as the following
example config which is now supported, regardless of what config plugin
you're using:
```json
{
"options": {
"enable_monitor": "true"
},
"packs": {
"core_os_monitoring": {
"version": "1.4.5",
"discovery": [
"select pid from processes where name like '%osqueryd%';"
],
"queries": {
"kernel_modules": {
"query": "SELECT name, size FROM kernel_modules;",
"interval": 600
},
"system_controls": {
"query": "SELECT * FROM system_controls;",
"interval": 600,
"snapshot": true,
},
"usb_devices": {
"query": "SELECT * FROM usb_devices;",
"interval": 600
}
}
},
"osquery_internal_info": {
"version": "1.4.5",
"discovery": [
"select pid from processes where name like '%osqueryd%';"
],
"queries": {
"info": {
"query": "select i.*, p.resident_size, p.user_time, p.system_time, time.minutes as counter from osquery_info i, processes p, time where p.pid = i.pid;",
"interval": 60,
"snapshot": true
},
"registry": {
"query": "SELECT * FROM osquery_registry;",
"interval": 600,
"snapshot": true
},
"schedule": {
"query": "select name, interval, executions, output_size, wall_time, (user_time/executions) as avg_user_time, (system_time/executions) as avg_system_time, average_memory from osquery_schedule;",
"interval": 60,
"snapshot": true
}
}
}
}
}
```
The `osquery_packs` table was modified to remove the superfluous
columns which could already have been found in `osquery_schedule`. Two
more columns were added in their place, representing stats about pack's
discovery query execution history.
Notably, the internal API for the `osquery::Config` class has changed
rather dramatically as apart of the refactoring. We think this is an
improvement. While strictly adhering to the osquery config plugin
interface will have avoided any compatibility errors, advanced users may
notice compilation errors if they access config data directly. All
internal users of the config have obviously been updated. Yet another
reason to merge your code into mainline; we update it for you when we
refactor!
2015-08-19 20:27:49 +00:00
|
|
|
namespace pt = boost::property_tree;
|
|
|
|
|
2015-01-30 18:44:25 +00:00
|
|
|
namespace osquery {
|
|
|
|
|
2015-06-30 18:48:11 +00:00
|
|
|
HIDDEN_FLAG(bool, registry_exceptions, false, "Allow plugin exceptions");
|
|
|
|
|
2016-08-10 03:27:42 +00:00
|
|
|
void registryAndPluginInit() {
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& it : AutoRegisterInterface::registries()) {
|
|
|
|
it->run();
|
2016-08-10 03:27:42 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& it : AutoRegisterInterface::plugins()) {
|
|
|
|
it->run();
|
2016-08-10 03:27:42 +00:00
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
|
|
|
|
AutoRegisterSet().swap(AutoRegisterInterface::registries());
|
|
|
|
AutoRegisterSet().swap(AutoRegisterInterface::plugins());
|
2016-08-10 03:27:42 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
void RegistryInterface::remove(const std::string& item_name) {
|
2015-02-04 03:55:16 +00:00
|
|
|
if (items_.count(item_name) > 0) {
|
|
|
|
items_[item_name]->tearDown();
|
|
|
|
items_.erase(item_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate list of aliases to remove (those that mask item_name).
|
|
|
|
std::vector<std::string> removed_aliases;
|
|
|
|
for (const auto& alias : aliases_) {
|
|
|
|
if (alias.second == item_name) {
|
|
|
|
removed_aliases.push_back(alias.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& alias : removed_aliases) {
|
|
|
|
aliases_.erase(alias);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
bool RegistryInterface::isInternal(const std::string& item_name) const {
|
2015-02-25 04:29:57 +00:00
|
|
|
if (std::find(internal_.begin(), internal_.end(), item_name) ==
|
|
|
|
internal_.end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
Status RegistryInterface::setActive(const std::string& item_name) {
|
2015-11-24 05:52:00 +00:00
|
|
|
// Default support multiple active plugins.
|
|
|
|
for (const auto& item : osquery::split(item_name, ",")) {
|
|
|
|
if (items_.count(item) == 0 && external_.count(item) == 0) {
|
|
|
|
return Status(1, "Unknown registry plugin: " + item);
|
|
|
|
}
|
2015-02-25 04:29:57 +00:00
|
|
|
}
|
2015-04-30 01:53:25 +00:00
|
|
|
|
2016-02-09 05:50:08 +00:00
|
|
|
Status status(0, "OK");
|
2015-02-25 04:29:57 +00:00
|
|
|
active_ = item_name;
|
2015-04-30 01:53:25 +00:00
|
|
|
// The active plugin is setup when initialized.
|
2015-11-24 05:52:00 +00:00
|
|
|
for (const auto& item : osquery::split(item_name, ",")) {
|
|
|
|
if (exists(item, true)) {
|
2017-01-07 20:21:35 +00:00
|
|
|
status = RegistryFactory::get().plugin(name_, item)->setUp();
|
|
|
|
} else if (exists(item, false) && !RegistryFactory::get().external()) {
|
2016-02-09 05:50:08 +00:00
|
|
|
// If the active plugin is within an extension we must wait.
|
|
|
|
// An extension will first broadcast the registry, then receive the list
|
|
|
|
// of active plugins, active them if they are extension-local, and finally
|
|
|
|
// start their extension socket.
|
|
|
|
status = pingExtension(getExtensionSocket(external_.at(item_name)));
|
2015-11-24 05:52:00 +00:00
|
|
|
}
|
2015-04-30 01:53:25 +00:00
|
|
|
}
|
2016-02-09 05:50:08 +00:00
|
|
|
return status;
|
2015-02-25 04:29:57 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
RegistryRoutes RegistryInterface::getRoutes() const {
|
2015-02-04 03:55:16 +00:00
|
|
|
RegistryRoutes route_table;
|
|
|
|
for (const auto& item : items_) {
|
2015-02-25 04:29:57 +00:00
|
|
|
if (isInternal(item.first)) {
|
2015-02-19 01:19:45 +00:00
|
|
|
// This is an internal plugin, do not include the route.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
bool has_alias = false;
|
|
|
|
for (const auto& alias : aliases_) {
|
|
|
|
if (alias.second == item.first) {
|
|
|
|
// If the item name is masked by at least one alias, it will not
|
|
|
|
// broadcast under the internal item name.
|
|
|
|
route_table[alias.first] = item.second->routeInfo();
|
|
|
|
has_alias = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_alias) {
|
|
|
|
route_table[item.first] = item.second->routeInfo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return route_table;
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
Status RegistryInterface::call(const std::string& item_name,
|
|
|
|
const PluginRequest& request,
|
|
|
|
PluginResponse& response) {
|
2015-11-24 05:52:00 +00:00
|
|
|
// Search local plugins (items) for the plugin.
|
2015-02-04 03:55:16 +00:00
|
|
|
if (items_.count(item_name) > 0) {
|
2015-02-11 03:18:56 +00:00
|
|
|
return items_.at(item_name)->call(request, response);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
2015-02-23 05:56:52 +00:00
|
|
|
|
2015-11-24 05:52:00 +00:00
|
|
|
// Check if the item was broadcasted as a plugin within an extension.
|
2015-02-23 05:56:52 +00:00
|
|
|
if (external_.count(item_name) > 0) {
|
|
|
|
// The item is a registered extension, call the extension by UUID.
|
2015-12-08 01:15:30 +00:00
|
|
|
return callExtension(
|
|
|
|
external_.at(item_name), name_, item_name, request, response);
|
2015-02-23 05:56:52 +00:00
|
|
|
} else if (routes_.count(item_name) > 0) {
|
|
|
|
// The item has a route, but no extension, pass in the route info.
|
|
|
|
response = routes_.at(item_name);
|
|
|
|
return Status(0, "Route only");
|
2017-01-07 20:21:35 +00:00
|
|
|
} else if (RegistryFactory::get().external()) {
|
2015-03-30 06:51:52 +00:00
|
|
|
// If this is an extension's registry forward unknown calls to the core.
|
|
|
|
return callExtension(0, name_, item_name, request, response);
|
2015-02-23 05:56:52 +00:00
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(1, "Cannot call registry item: " + item_name);
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
Status RegistryInterface::addAlias(const std::string& item_name,
|
|
|
|
const std::string& alias) {
|
2015-02-04 03:55:16 +00:00
|
|
|
if (aliases_.count(alias) > 0) {
|
|
|
|
return Status(1, "Duplicate alias: " + alias);
|
|
|
|
}
|
|
|
|
aliases_[alias] = item_name;
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::string RegistryInterface::getAlias(const std::string& alias) const {
|
2015-02-04 03:55:16 +00:00
|
|
|
if (aliases_.count(alias) == 0) {
|
|
|
|
return alias;
|
|
|
|
}
|
|
|
|
return aliases_.at(alias);
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
Status RegistryInterface::addPlugin(const std::string& plugin_name,
|
|
|
|
const PluginRef& plugin_item,
|
|
|
|
bool internal) {
|
|
|
|
if (items_.count(plugin_name) > 0) {
|
|
|
|
return Status(1, "Duplicate registry item exists: " + plugin_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
plugin_item->setName(plugin_name);
|
|
|
|
items_.emplace(std::make_pair(plugin_name, plugin_item));
|
|
|
|
|
2016-02-09 05:50:08 +00:00
|
|
|
// The item can be listed as internal, meaning it does not broadcast.
|
|
|
|
if (internal) {
|
2017-01-07 20:21:35 +00:00
|
|
|
internal_.push_back(plugin_name);
|
2016-02-09 05:50:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
void RegistryInterface::setUp() {
|
2015-04-30 01:53:25 +00:00
|
|
|
// If this registry does not auto-setup do NOT setup the registry items.
|
|
|
|
if (!auto_setup_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-13 15:11:08 +00:00
|
|
|
// If the registry is using a single 'active' plugin, setUp that plugin.
|
|
|
|
// For config and logger, only setUp the selected plugin.
|
|
|
|
if (active_.size() != 0 && exists(active_, true)) {
|
|
|
|
items_.at(active_)->setUp();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
// Try to set up each of the registry items.
|
|
|
|
// If they fail, remove them from the registry.
|
|
|
|
std::vector<std::string> failed;
|
|
|
|
for (auto& item : items_) {
|
|
|
|
if (!item.second->setUp().ok()) {
|
|
|
|
failed.push_back(item.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& failed_item : failed) {
|
|
|
|
remove(failed_item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
void RegistryInterface::configure() {
|
2016-02-11 04:08:34 +00:00
|
|
|
if (!active_.empty() && exists(active_, true)) {
|
2015-12-08 07:08:00 +00:00
|
|
|
items_.at(active_)->configure();
|
|
|
|
} else {
|
|
|
|
for (auto& item : items_) {
|
|
|
|
item.second->configure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
Status RegistryInterface::addExternal(const RouteUUID& uuid,
|
|
|
|
const RegistryRoutes& routes) {
|
2016-02-09 05:50:08 +00:00
|
|
|
// Add each route name (item name) to the tracking.
|
|
|
|
for (const auto& route : routes) {
|
|
|
|
// Keep the routes info assigned to the registry.
|
|
|
|
routes_[route.first] = route.second;
|
|
|
|
auto status = addExternalPlugin(route.first, route.second);
|
|
|
|
external_[route.first] = uuid;
|
|
|
|
if (!status.ok()) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove all the routes for a given uuid.
|
2017-01-07 20:21:35 +00:00
|
|
|
void RegistryInterface::removeExternal(const RouteUUID& uuid) {
|
2016-02-09 05:50:08 +00:00
|
|
|
std::vector<std::string> removed_items;
|
|
|
|
for (const auto& item : external_) {
|
|
|
|
if (item.second == uuid) {
|
|
|
|
removeExternalPlugin(item.first);
|
|
|
|
removed_items.push_back(item.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove items belonging to the external uuid.
|
|
|
|
for (const auto& item : removed_items) {
|
|
|
|
external_.erase(item);
|
|
|
|
routes_.erase(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
/// Facility method to check if a registry item exists.
|
2017-01-07 20:21:35 +00:00
|
|
|
bool RegistryInterface::exists(const std::string& item_name, bool local) const {
|
2015-02-23 05:56:52 +00:00
|
|
|
bool has_local = (items_.count(item_name) > 0);
|
|
|
|
bool has_external = (external_.count(item_name) > 0);
|
|
|
|
bool has_route = (routes_.count(item_name) > 0);
|
|
|
|
return (local) ? has_local : has_local || has_external || has_route;
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Facility method to list the registry item identifiers.
|
2017-01-07 20:21:35 +00:00
|
|
|
std::vector<std::string> RegistryInterface::names() const {
|
2015-02-04 03:55:16 +00:00
|
|
|
std::vector<std::string> names;
|
|
|
|
for (const auto& item : items_) {
|
|
|
|
names.push_back(item.first);
|
|
|
|
}
|
2015-02-23 05:56:52 +00:00
|
|
|
|
|
|
|
// Also add names of external plugins.
|
|
|
|
for (const auto& item : external_) {
|
|
|
|
names.push_back(item.first);
|
|
|
|
}
|
2015-02-04 03:55:16 +00:00
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
void RegistryFactory::add(const std::string& name, RegistryInterfaceRef reg) {
|
|
|
|
if (exists(name)) {
|
|
|
|
throw std::runtime_error("Cannot add duplicate registry: " + name);
|
|
|
|
}
|
|
|
|
registries_[name] = std::move(reg);
|
2016-08-31 23:45:06 +00:00
|
|
|
}
|
2015-02-04 03:55:16 +00:00
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
RegistryInterfaceRef RegistryFactory::registry(const std::string& t) const {
|
|
|
|
if (!exists(t)) {
|
|
|
|
throw std::runtime_error("Unknown registry requested: " + t);
|
|
|
|
}
|
|
|
|
return registries_.at(t);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::map<std::string, RegistryInterfaceRef> RegistryFactory::all() const {
|
|
|
|
return registries_;
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::map<std::string, PluginRef> RegistryFactory::plugins(
|
|
|
|
const std::string& registry_name) const {
|
|
|
|
return registry(registry_name)->plugins();
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
PluginRef RegistryFactory::plugin(const std::string& registry_name,
|
|
|
|
const std::string& item_name) const {
|
|
|
|
return registry(registry_name)->plugin(item_name);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RegistryBroadcast RegistryFactory::getBroadcast() {
|
|
|
|
RegistryBroadcast broadcast;
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& registry : registries_) {
|
2015-02-04 03:55:16 +00:00
|
|
|
broadcast[registry.first] = registry.second->getRoutes();
|
|
|
|
}
|
|
|
|
return broadcast;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::addBroadcast(const RouteUUID& uuid,
|
|
|
|
const RegistryBroadcast& broadcast) {
|
2017-01-07 20:21:35 +00:00
|
|
|
WriteLock lock(mutex_);
|
|
|
|
if (extensions_.count(uuid) > 0) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(1, "Duplicate extension UUID: " + std::to_string(uuid));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the extension does not broadcast conflicting registry items.
|
2017-01-07 20:21:35 +00:00
|
|
|
if (!allowDuplicates()) {
|
2015-02-04 03:55:16 +00:00
|
|
|
for (const auto& registry : broadcast) {
|
|
|
|
for (const auto& item : registry.second) {
|
2017-01-07 20:21:35 +00:00
|
|
|
if (exists(registry.first, item.first)) {
|
2015-02-19 01:19:45 +00:00
|
|
|
VLOG(1) << "Extension " << uuid
|
|
|
|
<< " has duplicate plugin name: " << item.first
|
|
|
|
<< " in registry: " << registry.first;
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(1, "Duplicate registry item: " + item.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-23 05:56:52 +00:00
|
|
|
// Once duplication is satisfied call each registry's addExternal.
|
|
|
|
Status status;
|
|
|
|
for (const auto& registry : broadcast) {
|
2017-01-07 20:21:35 +00:00
|
|
|
if (!exists(registry.first)) {
|
|
|
|
VLOG(1) << "Extension " << uuid
|
|
|
|
<< "contains unknown registry: " << registry.first;
|
|
|
|
return Status(1, "Unknown registry: " + registry.first);
|
|
|
|
}
|
|
|
|
status = this->registry(registry.first)->addExternal(uuid, registry.second);
|
2015-02-23 05:56:52 +00:00
|
|
|
if (!status.ok()) {
|
|
|
|
// If any registry fails to add the set of external routes, stop.
|
|
|
|
break;
|
|
|
|
}
|
2015-02-25 04:29:57 +00:00
|
|
|
|
|
|
|
for (const auto& plugin : registry.second) {
|
|
|
|
VLOG(1) << "Extension " << uuid << " registered " << registry.first
|
|
|
|
<< " plugin " << plugin.first;
|
|
|
|
}
|
2015-02-23 05:56:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If any registry failed, remove each (assume a broadcast is atomic).
|
|
|
|
if (!status.ok()) {
|
|
|
|
for (const auto& registry : broadcast) {
|
2017-01-07 20:21:35 +00:00
|
|
|
this->registry(registry.first)->removeExternal(uuid);
|
2015-02-23 05:56:52 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
extensions_.insert(uuid);
|
2015-02-23 05:56:52 +00:00
|
|
|
return status;
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::removeBroadcast(const RouteUUID& uuid) {
|
2017-01-07 20:21:35 +00:00
|
|
|
WriteLock lock(mutex_);
|
|
|
|
if (extensions_.count(uuid) == 0) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(1, "Unknown extension UUID: " + std::to_string(uuid));
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& registry : registries_) {
|
2015-02-23 05:56:52 +00:00
|
|
|
registry.second->removeExternal(uuid);
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
extensions_.erase(uuid);
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(0, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds an alias for an internal registry item. This registry will only
|
|
|
|
/// broadcast the alias name.
|
|
|
|
Status RegistryFactory::addAlias(const std::string& registry_name,
|
|
|
|
const std::string& item_name,
|
|
|
|
const std::string& alias) {
|
2017-01-07 20:21:35 +00:00
|
|
|
if (!exists(registry_name)) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return Status(1, "Unknown registry: " + registry_name);
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
return registries_.at(registry_name)->addAlias(item_name, alias);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the item_name or the item alias if an alias exists.
|
2017-01-07 20:21:35 +00:00
|
|
|
std::string RegistryFactory::getAlias(const std::string& registry_name,
|
|
|
|
const std::string& alias) const {
|
|
|
|
if (!exists(registry_name)) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return alias;
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
return registries_.at(registry_name)->getAlias(alias);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::call(const std::string& registry_name,
|
|
|
|
const std::string& item_name,
|
|
|
|
const PluginRequest& request,
|
|
|
|
PluginResponse& response) {
|
2015-02-23 05:56:52 +00:00
|
|
|
// Forward factory call to the registry.
|
2015-04-27 21:56:18 +00:00
|
|
|
try {
|
2015-11-24 05:52:00 +00:00
|
|
|
if (item_name.find(",") != std::string::npos) {
|
|
|
|
// Call is multiplexing plugins (usually for multiple loggers).
|
|
|
|
for (const auto& item : osquery::split(item_name, ",")) {
|
2017-01-07 20:21:35 +00:00
|
|
|
get().registry(registry_name)->call(item, request, response);
|
2015-11-24 05:52:00 +00:00
|
|
|
}
|
|
|
|
// All multiplexed items are called without regard for statuses.
|
|
|
|
return Status(0);
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
return get().registry(registry_name)->call(item_name, request, response);
|
2015-04-27 21:56:18 +00:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
LOG(ERROR) << registry_name << " registry " << item_name
|
|
|
|
<< " plugin caused exception: " << e.what();
|
2015-06-30 18:48:11 +00:00
|
|
|
if (FLAGS_registry_exceptions) {
|
2015-09-02 23:05:48 +00:00
|
|
|
throw;
|
2015-06-30 18:48:11 +00:00
|
|
|
}
|
2015-04-27 21:56:18 +00:00
|
|
|
return Status(1, e.what());
|
|
|
|
} catch (...) {
|
|
|
|
LOG(ERROR) << registry_name << " registry " << item_name
|
|
|
|
<< " plugin caused unknown exception";
|
2015-06-30 18:48:11 +00:00
|
|
|
if (FLAGS_registry_exceptions) {
|
|
|
|
throw std::runtime_error(registry_name + ": " + item_name + " failed");
|
|
|
|
}
|
2015-04-27 21:56:18 +00:00
|
|
|
return Status(2, "Unknown exception");
|
|
|
|
}
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::call(const std::string& registry_name,
|
|
|
|
const std::string& item_name,
|
|
|
|
const PluginRequest& request) {
|
|
|
|
PluginResponse response;
|
2015-02-23 05:56:52 +00:00
|
|
|
// Wrapper around a call expecting a response.
|
2015-02-04 03:55:16 +00:00
|
|
|
return call(registry_name, item_name, request, response);
|
|
|
|
}
|
|
|
|
|
2015-02-25 04:29:57 +00:00
|
|
|
Status RegistryFactory::call(const std::string& registry_name,
|
|
|
|
const PluginRequest& request,
|
|
|
|
PluginResponse& response) {
|
2017-01-07 20:21:35 +00:00
|
|
|
auto& plugin = get().registry(registry_name)->getActive();
|
2015-04-27 21:56:18 +00:00
|
|
|
return call(registry_name, plugin, request, response);
|
2015-02-25 04:29:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::call(const std::string& registry_name,
|
|
|
|
const PluginRequest& request) {
|
|
|
|
PluginResponse response;
|
|
|
|
return call(registry_name, request, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status RegistryFactory::setActive(const std::string& registry_name,
|
|
|
|
const std::string& item_name) {
|
2017-01-07 20:21:35 +00:00
|
|
|
WriteLock lock(mutex_);
|
2015-02-25 04:29:57 +00:00
|
|
|
return registry(registry_name)->setActive(item_name);
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::string RegistryFactory::getActive(const std::string& registry_name) const {
|
2015-03-08 21:52:13 +00:00
|
|
|
return registry(registry_name)->getActive();
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
void RegistryFactory::setUp() {
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& registry : get().all()) {
|
2015-02-04 03:55:16 +00:00
|
|
|
registry.second->setUp();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RegistryFactory::exists(const std::string& registry_name,
|
2015-02-23 05:56:52 +00:00
|
|
|
const std::string& item_name,
|
2017-01-07 20:21:35 +00:00
|
|
|
bool local) const {
|
|
|
|
if (!exists(registry_name)) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-23 05:56:52 +00:00
|
|
|
// Check the registry.
|
|
|
|
return registry(registry_name)->exists(item_name, local);
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::vector<std::string> RegistryFactory::names() const {
|
2015-02-25 04:29:57 +00:00
|
|
|
std::vector<std::string> names;
|
|
|
|
for (const auto& registry : all()) {
|
|
|
|
names.push_back(registry.second->getName());
|
|
|
|
}
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2015-02-04 03:55:16 +00:00
|
|
|
std::vector<std::string> RegistryFactory::names(
|
2017-01-07 20:21:35 +00:00
|
|
|
const std::string& registry_name) const {
|
|
|
|
if (registries_.at(registry_name) == 0) {
|
2015-02-04 03:55:16 +00:00
|
|
|
std::vector<std::string> names;
|
|
|
|
return names;
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
return registry(registry_name)->names();
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
std::vector<RouteUUID> RegistryFactory::routeUUIDs() const {
|
|
|
|
WriteLock lock(mutex_);
|
2015-02-19 01:19:45 +00:00
|
|
|
std::vector<RouteUUID> uuids;
|
2017-01-07 20:21:35 +00:00
|
|
|
for (const auto& extension : extensions_) {
|
2015-02-23 05:56:52 +00:00
|
|
|
uuids.push_back(extension);
|
2015-02-19 01:19:45 +00:00
|
|
|
}
|
|
|
|
return uuids;
|
|
|
|
}
|
|
|
|
|
2017-01-07 20:21:35 +00:00
|
|
|
size_t RegistryFactory::count(const std::string& registry_name) const {
|
|
|
|
if (!exists(registry_name)) {
|
2015-02-04 03:55:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-01-07 20:21:35 +00:00
|
|
|
return registry(registry_name)->count();
|
2015-02-04 03:55:16 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 05:03:09 +00:00
|
|
|
void Plugin::setName(const std::string& name) {
|
|
|
|
if (!name_.empty() && name != name_) {
|
|
|
|
std::string error = "Cannot rename plugin " + name_ + " to " + name;
|
|
|
|
throw std::runtime_error(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
name_ = name;
|
|
|
|
}
|
|
|
|
|
2015-01-30 18:44:25 +00:00
|
|
|
void Plugin::getResponse(const std::string& key,
|
|
|
|
const PluginResponse& response,
|
|
|
|
boost::property_tree::ptree& tree) {
|
|
|
|
for (const auto& item : response) {
|
|
|
|
boost::property_tree::ptree child;
|
|
|
|
for (const auto& item_detail : item) {
|
|
|
|
child.put(item_detail.first, item_detail.second);
|
|
|
|
}
|
|
|
|
tree.add_child(key, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Plugin::setResponse(const std::string& key,
|
|
|
|
const boost::property_tree::ptree& tree,
|
|
|
|
PluginResponse& response) {
|
|
|
|
std::ostringstream output;
|
2015-07-15 02:09:55 +00:00
|
|
|
try {
|
|
|
|
boost::property_tree::write_json(output, tree, false);
|
2016-09-02 22:04:03 +00:00
|
|
|
} catch (const pt::json_parser::json_parser_error& /* e */) {
|
2015-07-15 02:09:55 +00:00
|
|
|
// The plugin response could not be serialized.
|
|
|
|
}
|
2015-01-30 18:44:25 +00:00
|
|
|
response.push_back({{key, output.str()}});
|
|
|
|
}
|
|
|
|
}
|