Status OptionsConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { if (config.count("options") > 0) { data_ = pt::ptree(); data_.put_child("options", config.at("options")); } const auto& options = data_.get_child("options"); for (const auto& option : options) { std::string value = options.get<std::string>(option.first, ""); if (value.empty()) { continue; } Flag::updateValue(option.first, value); // There is a special case for supported Gflags-reserved switches. if (option.first == "verbose" || option.first == "verbose_debug" || option.first == "debug") { setVerboseLevel(); if (Flag::getValue("verbose") == "true") { VLOG(1) << "Verbose logging enabled by config option"; } } } return Status(0, "OK"); }
Status ViewsConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { auto cv = config.find("views"); if (cv == config.end()) { return Status(1); } auto obj = data_.getObject(); data_.copyFrom(cv->second.doc(), obj); data_.add("views", obj); const auto& views = data_.doc()["views"]; // We use a restricted scope below to change the data structure from // an array to a set. This lets us do deletes much more efficiently std::vector<std::string> created_views; std::set<std::string> erase_views; { std::vector<std::string> old_views_vec; scanDatabaseKeys(kQueries, old_views_vec, kConfigViews); for (const auto& view : old_views_vec) { erase_views.insert(view.substr(kConfigViews.size())); } } QueryData r; for (const auto& view : views.GetObject()) { std::string name = view.name.GetString(); std::string query = view.value.GetString(); if (query.empty()) { continue; } std::string old_query = ""; getDatabaseValue(kQueries, kConfigViews + name, old_query); erase_views.erase(name); if (old_query == query) { continue; } // View has been updated osquery::query("DROP VIEW " + name, r); auto s = osquery::query("CREATE VIEW " + name + " AS " + query, r); if (s.ok()) { setDatabaseValue(kQueries, kConfigViews + name, query); } else { LOG(INFO) << "Error creating view (" << name << "): " << s.getMessage(); } } // Any views left are views that don't exist in the new configuration file // so we tear them down and remove them from the database. for (const auto& old_view : erase_views) { osquery::query("DROP VIEW " + old_view, r); deleteDatabaseValue(kQueries, kConfigViews + old_view); } return Status(0, "OK"); }
Status PrometheusMetricsConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { if (config.count(kConfigParserRootKey) > 0) { data_ = boost::property_tree::ptree(); data_.put_child(kConfigParserRootKey, config.at(kConfigParserRootKey)); } return Status(0, "OK"); }
Status FeatureVectorsConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { auto fv = config.find(kFeatureVectorsRootKey); if (fv == config.end()) { return Status(); } auto obj = data_.getObject(); data_.copyFrom(fv->second.doc(), obj); data_.add(kFeatureVectorsRootKey, obj); return Status(); }
Status LoggerConfigParserPlugin::update(const std::string& /* source */, const ParserConfig& config) { rj::Document& doc = data_.doc(); auto it = doc.FindMember(kLoggerKey); if (it != doc.MemberEnd()) { doc.EraseMember(it); } auto cv = config.find(kLoggerKey); if (cv != config.end()) { auto obj = data_.getObject(); data_.copyFrom(cv->second.doc(), obj); data_.add(kLoggerKey, obj); } return Status(); }
Status FilePathsConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { if (config.count("file_paths") > 0) { data_.put_child("file_paths", config.at("file_paths")); } auto& accesses = data_.get_child("file_accesses"); if (config.count("file_accesses") > 0) { if (access_map_.count(source) > 0) { access_map_.erase(source); } for (const auto& category : config.at("file_accesses")) { auto path = category.second.get_value<std::string>(""); access_map_[source].push_back(path); } // Regenerate the access: for (const auto& access_source : access_map_) { for (const auto& category : access_source.second) { accesses.put(category, access_source.first); } } } Config::getInstance().removeFiles(source); for (const auto& category : data_.get_child("file_paths")) { for (const auto& path : category.second) { auto pattern = path.second.get_value<std::string>(""); if (pattern.empty()) { continue; } replaceGlobWildcards(pattern); Config::getInstance().addFile(source, category.first, pattern); } } return Status(0, "OK"); }
Status ATCConfigParserPlugin::update(const std::string& source, const ParserConfig& config) { auto cv = config.find(kParserKey); if (cv == config.end()) { return Status(1, "No configuration for ATC (Auto Table Construction)"); } auto obj = data_.getObject(); data_.copyFrom(cv->second.doc(), obj); data_.add(kParserKey, obj); const auto& ac_tables = data_.doc()[kParserKey]; auto tables = RegistryFactory::get().registry("table"); auto registered = registeredATCTables(); for (const auto& ac_table : ac_tables.GetObject()) { std::string table_name{ac_table.name.GetString()}; auto params = ac_table.value.GetObject(); std::string query{params.HasMember("query") && params["query"].IsString() ? params["query"].GetString() : ""}; std::string path{params.HasMember("path") && params["path"].IsString() ? params["path"].GetString() : ""}; std::string platform{params.HasMember("platform") && params["platform"].IsString() ? params["platform"].GetString() : ""}; if (query.empty() || path.empty()) { LOG(WARNING) << "ATC Table: " << table_name << " is misconfigured"; continue; } if (!checkPlatform(platform)) { VLOG(1) << "Skipping ATC table: " << table_name << " because platform doesn't match"; continue; } TableColumns columns; std::string columns_value; columns_value.reserve(256); for (const auto& column : params["columns"].GetArray()) { columns.push_back(make_tuple( std::string(column.GetString()), TEXT_TYPE, ColumnOptions::DEFAULT)); columns_value += std::string(column.GetString()) + ","; } registered.erase(table_name); std::string table_settings{table_name + query + columns_value + path}; std::string old_setting; auto s = getDatabaseValue( kPersistentSettings, kDatabaseKeyPrefix + table_name, old_setting); // The ATC table hasn't changed so we skip ahead if (table_settings == old_setting) { continue; } // Remove the old table to replace with the new one s = removeATCTables({table_name}); if (!s.ok()) { LOG(WARNING) << "ATC table overrides core table; Refusing registration"; continue; } s = setDatabaseValue( kPersistentSettings, kDatabaseKeyPrefix + table_name, table_settings); if (!s.ok()) { LOG(WARNING) << "Could not write to database"; continue; } s = tables->add( table_name, std::make_shared<ATCPlugin>(path, columns, query), true); if (!s.ok()) { LOG(WARNING) << s.getMessage(); deleteDatabaseValue(kPersistentSettings, kDatabaseKeyPrefix + table_name); continue; } PluginResponse resp; Registry::call( "sql", "sql", {{"action", "attach"}, {"table", table_name}}, resp); LOG(INFO) << "Registered ATC table: " << table_name; } if (registered.size() > 0) { VLOG(1) << "Removing any ATC tables that were removed in this configuration " "change"; removeATCTables(registered); } return Status(); }