| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <windows.h> |
| #include "MetadataWalker.h" |
| #include "XMLString.h" |
| #include <strsafe.h> |
| |
| namespace org { |
| namespace apache { |
| namespace nifi { |
| namespace minifi { |
| namespace wel { |
| |
| bool MetadataWalker::for_each(pugi::xml_node &node) { |
| // don't shortcut resolution here so that we can log attributes. |
| const std::string node_name = node.name(); |
| if (node_name == "Data") { |
| for (pugi::xml_attribute attr : node.attributes()) { |
| const auto idUpdate = [&](const std::string &input) { |
| if (resolve_) { |
| const auto resolved = utils::OsUtils::userIdToUsername(input); |
| replaced_identifiers_[input] = resolved; |
| return resolved; |
| } |
| |
| replaced_identifiers_[input] = input; |
| return input; |
| }; |
| |
| if (std::regex_match(attr.name(), regex_)) { |
| updateText(node, attr.name(), idUpdate); |
| } |
| |
| if (std::regex_match(attr.value(), regex_)) { |
| updateText(node, attr.value(), idUpdate); |
| } |
| } |
| |
| if (resolve_) { |
| std::string nodeText = node.text().get(); |
| std::vector<std::string> ids = getIdentifiers(nodeText); |
| for (const auto &id : ids) { |
| auto resolved = utils::OsUtils::userIdToUsername(id); |
| std::string replacement = "%{" + id + "}"; |
| replaced_identifiers_[id] = resolved; |
| replaced_identifiers_[replacement] = resolved; |
| nodeText = utils::StringUtils::replaceAll(nodeText, replacement, resolved); |
| } |
| node.text().set(nodeText.c_str()); |
| } |
| |
| } |
| else if (node_name == "TimeCreated") { |
| metadata_["TimeCreated"] = node.attribute("SystemTime").value(); |
| } |
| else if (node_name == "EventRecordID") { |
| metadata_["EventRecordID"] = node.text().get(); |
| } |
| else if (node_name == "Provider") { |
| metadata_["Provider"] = node.attribute("Name").value(); |
| } |
| else if (node_name == "EventID") { |
| metadata_["EventID"] = node.text().get(); |
| } |
| else { |
| static std::map<std::string, EVT_FORMAT_MESSAGE_FLAGS> formatFlagMap = { {"Channel", EvtFormatMessageChannel}, {"Keywords", EvtFormatMessageKeyword}, {"Level", EvtFormatMessageLevel}, {"Opcode", EvtFormatMessageOpcode}, {"Task",EvtFormatMessageTask} }; |
| auto it = formatFlagMap.find(node_name); |
| if (it != formatFlagMap.end()) { |
| std::function<std::string(const std::string &)> updateFunc = [&](const std::string &input) -> std::string { |
| if (resolve_) { |
| auto resolved = windows_event_log_metadata_.getEventData(it->second); |
| if (!resolved.empty()) { |
| return resolved; |
| } |
| } |
| return input; |
| }; |
| updateText(node, node.name(), std::move(updateFunc)); |
| } |
| else { |
| // no conversion is required here, so let the node fall through |
| } |
| } |
| |
| return true; |
| } |
| |
| std::vector<std::string> MetadataWalker::getIdentifiers(const std::string &text) const { |
| auto pos = text.find("%{"); |
| std::vector<std::string> found_strings; |
| while (pos != std::string::npos) { |
| auto next_pos = text.find("}", pos); |
| if (next_pos != std::string::npos) { |
| auto potential_identifier = text.substr(pos + 2, next_pos - (pos + 2)); |
| std::smatch match; |
| if (potential_identifier.find("S-") != std::string::npos){ |
| found_strings.push_back(potential_identifier); |
| } |
| } |
| pos = text.find("%{", pos + 2); |
| } |
| return found_strings; |
| } |
| |
| std::string MetadataWalker::getMetadata(METADATA metadata) const { |
| switch (metadata) { |
| case LOG_NAME: |
| return log_name_; |
| case SOURCE: |
| return getString(metadata_,"Provider"); |
| case TIME_CREATED: |
| return windows_event_log_metadata_.getEventTimestamp(); |
| case EVENTID: |
| return getString(metadata_,"EventID"); |
| case EVENT_RECORDID: |
| return getString(metadata_, "EventRecordID"); |
| case OPCODE: |
| return getString(metadata_, "Opcode"); |
| case TASK_CATEGORY: |
| return getString(metadata_,"Task"); |
| case LEVEL: |
| return getString(metadata_,"Level"); |
| case KEYWORDS: |
| return getString(metadata_,"Keywords"); |
| case EVENT_TYPE: |
| return std::to_string(windows_event_log_metadata_.getEventTypeIndex()); |
| case COMPUTER: |
| return windows_event_log_metadata_.getComputerName(); |
| }; |
| return "N/A"; |
| } |
| |
| std::map<std::string, std::string> MetadataWalker::getFieldValues() const { |
| return fields_values_; |
| } |
| |
| std::map<std::string, std::string> MetadataWalker::getIdentifiers() const { |
| return replaced_identifiers_; |
| } |
| |
| std::string MetadataWalker::updateXmlMetadata(const std::string &xml, EVT_HANDLE metadata_ptr, EVT_HANDLE event_ptr, bool update_xml, bool resolve, const std::string ®ex) { |
| WindowsEventLogMetadataImpl metadata{metadata_ptr, event_ptr}; |
| MetadataWalker walker(metadata, "", update_xml, resolve, regex); |
| |
| pugi::xml_document doc; |
| pugi::xml_parse_result result = doc.load_string(xml.c_str()); |
| |
| if (result) { |
| doc.traverse(walker); |
| wel::XmlString writer; |
| doc.print(writer, "", pugi::format_raw); // no indentation or formatting |
| return writer.xml_; |
| } |
| else { |
| throw std::runtime_error("Could not parse XML document"); |
| } |
| } |
| |
| std::string MetadataWalker::to_string(const wchar_t* pChar) { |
| return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(pChar); |
| } |
| |
| void MetadataWalker::updateText(pugi::xml_node &node, const std::string &field_name, std::function<std::string(const std::string &)> &&fn) { |
| std::string previous_value = node.text().get(); |
| auto new_field_value = fn(previous_value); |
| if (new_field_value != previous_value) { |
| metadata_[field_name] = new_field_value; |
| if (update_xml_) { |
| node.text().set(new_field_value.c_str()); |
| } else { |
| fields_values_[field_name] = new_field_value; |
| } |
| } |
| } |
| |
| } /* namespace wel */ |
| } /* namespace minifi */ |
| } /* namespace nifi */ |
| } /* namespace apache */ |
| } /* namespace org */ |