in extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp [318:525]
bool SourceInitiatedSubscriptionListener::Handler::handleSubscriptionManager(struct mg_connection* conn, const std::string& endpoint, WsXmlDocH request) {
const auto request_guard = gsl::finally([&]() {
ws_xml_destroy_doc(request);
});
auto action = getSoapAction(request);
auto machine_id = getMachineId(request);
const struct mg_request_info* req_info = mg_get_request_info(conn);
std::string remote_ip = req_info->remote_addr;
if (action != ENUM_ACTION_ENUMERATE) {
processor_.logger_->log_error("%s called by %s (%s) with unknown Action \"%s\"", endpoint.c_str(), machine_id.c_str(), remote_ip.c_str(), action.c_str());
return false; // TODO(bakaid): generate fault if possible
}
// Create reponse envelope from request
WsXmlDocH response = wsman_create_response_envelope(request, nullptr);
const auto response_guard = gsl::finally([&]() {
ws_xml_destroy_doc(response);
});
// Header
WsXmlNodeH response_header = ws_xml_get_soap_header(response);
// Header/MessageID
utils::Identifier msg_id = utils::IdGenerator::getIdGenerator()->generate();
ws_xml_add_child_format(response_header, XML_NS_ADDRESSING, WSA_MESSAGE_ID, "uuid:%s", msg_id.to_string().c_str());
// Body
WsXmlNodeH response_body = ws_xml_get_soap_body(response);
// Body/EnumerationResponse
WsXmlNodeH enumeration_response = ws_xml_add_child(response_body, XML_NS_ENUMERATION, WSENUM_ENUMERATE_RESP, nullptr);
// Body/EnumerationResponse/EnumerationContext
ws_xml_add_child(enumeration_response, XML_NS_ENUMERATION, WSENUM_ENUMERATION_CONTEXT, nullptr);
// Body/EnumerationResponse/Items
WsXmlNodeH enumeration_items = ws_xml_add_child(enumeration_response, XML_NS_WS_MAN, WSENUM_ITEMS, nullptr);
// Body/EnumerationResponse/EndOfSequence
ws_xml_add_child(enumeration_response, XML_NS_WS_MAN, WSENUM_END_OF_SEQUENCE, nullptr);
// Body/EnumerationResponse/Items/Subscription
WsXmlNodeH subscription = ws_xml_add_child(enumeration_items, nullptr, "Subscription", nullptr);
ws_xml_set_ns(subscription, XML_NS_CUSTOM_SUBSCRIPTION, "m");
// Body/EnumerationResponse/Items/Subscription/Version
std::lock_guard<std::mutex> lock(processor_.mutex_);
auto it = processor_.subscribers_.find(machine_id);
std::string subscription_version;
if (it != processor_.subscribers_.end() && it->second.subscription_ != nullptr) {
subscription_version = it->second.subscription_version_;
} else {
utils::Identifier id = utils::IdGenerator::getIdGenerator()->generate();
subscription_version = id.to_string();
}
ws_xml_add_child_format(subscription, XML_NS_CUSTOM_SUBSCRIPTION, "Version", "uuid:%s", subscription_version.c_str());
// Body/EnumerationResponse/Items/Subscription/Envelope
std::string subscription_identifier;
std::string subscription_endpoint;
if (it != processor_.subscribers_.end() && it->second.subscription_ != nullptr) {
WsXmlNodeH subscription_node = ws_xml_get_doc_root(it->second.subscription_);
ws_xml_copy_node(subscription_node, subscription);
} else {
WsXmlDocH subscription_doc = ws_xml_create_envelope();
// Header
WsXmlNodeH header = ws_xml_get_soap_header(subscription_doc);
WsXmlNodeH node;
// Header/Action
node = ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_ACTION, EVT_ACTION_SUBSCRIBE);
ws_xml_add_node_attr(node, XML_NS_SOAP_1_2, SOAP_MUST_UNDERSTAND, "true");
// Header/MessageID
utils::Identifier msg_id = utils::IdGenerator::getIdGenerator()->generate();
ws_xml_add_child_format(header, XML_NS_ADDRESSING, WSA_MESSAGE_ID, "uuid:%s", msg_id.to_string().c_str());
// Header/To
node = ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_TO, WSA_TO_ANONYMOUS);
ws_xml_add_node_attr(node, XML_NS_SOAP_1_2, SOAP_MUST_UNDERSTAND, "true");
// Header/ResourceURI
node = ws_xml_add_child(header, XML_NS_WS_MAN, WSM_RESOURCE_URI, "http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog");
ws_xml_add_node_attr(node, XML_NS_SOAP_1_2, SOAP_MUST_UNDERSTAND, "true");
// Header/ReplyTo
node = ws_xml_add_child(header, XML_NS_ADDRESSING, WSA_REPLY_TO, nullptr);
node = ws_xml_add_child(node, XML_NS_ADDRESSING, WSA_ADDRESS, WSA_TO_ANONYMOUS);
ws_xml_add_node_attr(node, XML_NS_SOAP_1_2, SOAP_MUST_UNDERSTAND, "true");
// Header/OptionSet
WsXmlNodeH option_set = ws_xml_add_child(header, XML_NS_WS_MAN, WSM_OPTION_SET, nullptr);
ws_xml_ns_add(option_set, XML_NS_SCHEMA_INSTANCE, XML_NS_SCHEMA_INSTANCE_PREFIX);
// Header/OptionSet/Option (CDATA)
node = ws_xml_add_child(option_set, XML_NS_WS_MAN, WSM_OPTION, nullptr);
ws_xml_add_node_attr(node, nullptr, WSM_NAME, "CDATA");
ws_xml_add_node_attr(node, XML_NS_SCHEMA_INSTANCE, XML_SCHEMA_NIL, "true");
// Header/OptionSet/Option (IgnoreChannelError)
node = ws_xml_add_child(option_set, XML_NS_WS_MAN, WSM_OPTION, nullptr);
ws_xml_add_node_attr(node, nullptr, WSM_NAME, "IgnoreChannelError");
ws_xml_add_node_attr(node, XML_NS_SCHEMA_INSTANCE, XML_SCHEMA_NIL, "true");
// Body
WsXmlNodeH body = ws_xml_get_soap_body(subscription_doc);
WsXmlNodeH subscribe_node = ws_xml_add_child(body, XML_NS_EVENTING, WSEVENT_SUBSCRIBE, nullptr);
// Body/Delivery
{
utils::Identifier id = utils::IdGenerator::getIdGenerator()->generate();
subscription_identifier = id.to_string();
}
{
utils::Identifier id = utils::IdGenerator::getIdGenerator()->generate();
subscription_endpoint = processor_.subscriptions_base_path_ + "/" + id.to_string();
}
WsXmlNodeH delivery_node = ws_xml_add_child(subscribe_node, XML_NS_EVENTING, WSEVENT_DELIVERY, nullptr);
ws_xml_add_node_attr(delivery_node, nullptr, WSEVENT_DELIVERY_MODE, WSEVENT_DELIVERY_MODE_EVENTS);
// Body/Delivery/Heartbeats
ws_xml_add_child(delivery_node, XML_NS_WS_MAN, WSM_HEARTBEATS, millisecondsToXsdDuration(processor_.heartbeat_interval_).c_str());
// Body/Delivery/ConnectionRetry
auto connection_retry_node = ws_xml_add_child(delivery_node, XML_NS_WS_MAN, WSM_CONNECTIONRETRY, millisecondsToXsdDuration(processor_.connection_retry_interval_).c_str());
ws_xml_add_node_attr(connection_retry_node, nullptr, "Total", std::to_string(processor_.connection_retry_count_).c_str());
// Body/Delivery/NotifyTo and Body/EndTo are the same, so we will use this lambda to recreate the same tree
auto apply_endpoint_nodes = [&](WsXmlNodeH target_node) {
// ${target_node}/NotifyTo/Address
ws_xml_add_child_format(target_node, XML_NS_ADDRESSING, WSA_ADDRESS, "https://%s:%hu%s",
processor_.listen_hostname_.c_str(),
processor_.listen_port_,
subscription_endpoint.c_str());
// ${target_node}/ReferenceProperties
node = ws_xml_add_child(target_node, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES, nullptr);
// ${target_node}/ReferenceProperties/Identifier
ws_xml_add_child_format(node, XML_NS_EVENTING, WSEVENT_IDENTIFIER, "%s", subscription_identifier.c_str());
// ${target_node}/Policy
WsXmlNodeH policy = ws_xml_add_child(target_node, nullptr, "Policy", nullptr);
ws_xml_set_ns(policy, XML_NS_CUSTOM_POLICY, "c");
ws_xml_ns_add(policy, XML_NS_CUSTOM_AUTHENTICATION, "auth");
// ${target_node}/Policy/ExactlyOne
WsXmlNodeH exactly_one = ws_xml_add_child(policy, XML_NS_CUSTOM_POLICY, "ExactlyOne", nullptr);
// ${target_node}/Policy/ExactlyOne/All
WsXmlNodeH all = ws_xml_add_child(exactly_one, XML_NS_CUSTOM_POLICY, "All", nullptr);
// ${target_node}/Policy/ExactlyOne/All/Authentication
WsXmlNodeH authentication = ws_xml_add_child(all, XML_NS_CUSTOM_AUTHENTICATION, "Authentication", nullptr);
ws_xml_add_node_attr(authentication, nullptr, "Profile", WSMAN_SECURITY_PROFILE_HTTPS_MUTUAL);
// ${target_node}/Policy/ExactlyOne/All/Authentication/ClientCertificate
WsXmlNodeH client_certificate = ws_xml_add_child(authentication, XML_NS_CUSTOM_AUTHENTICATION, "ClientCertificate", nullptr);
// ${target_node}/Policy/ExactlyOne/All/Authentication/ClientCertificate/Thumbprint
WsXmlNodeH thumbprint = ws_xml_add_child_format(client_certificate, XML_NS_CUSTOM_AUTHENTICATION, "Thumbprint", "%s", processor_.ssl_ca_cert_thumbprint_.c_str());
ws_xml_add_node_attr(thumbprint, nullptr, "Role", "issuer");
};
// Body/Delivery/NotifyTo
WsXmlNodeH notifyto_node = ws_xml_add_child(delivery_node, XML_NS_EVENTING, WSEVENT_NOTIFY_TO, nullptr);
apply_endpoint_nodes(notifyto_node);
// Body/EndTo
WsXmlNodeH endto_node = ws_xml_add_child(subscribe_node, XML_NS_EVENTING, WSEVENT_ENDTO, nullptr);
apply_endpoint_nodes(endto_node);
// Body/MaxElements
ws_xml_add_child(delivery_node, XML_NS_WS_MAN, WSM_MAX_ELEMENTS, std::to_string(processor_.max_elements_).c_str());
// Body/MaxTime
ws_xml_add_child(delivery_node, XML_NS_WS_MAN, WSENUM_MAX_TIME, millisecondsToXsdDuration(processor_.max_latency_).c_str());
// Body/Expires
ws_xml_add_child(subscribe_node, XML_NS_EVENTING, WSEVENT_EXPIRES, millisecondsToXsdDuration(processor_.subscription_expiration_interval_).c_str());
// Body/Filter
ws_xml_add_child(subscribe_node, XML_NS_WS_MAN, WSM_FILTER, processor_.xpath_xml_query_.c_str());
// ws_xml_add_node_attr(filter_node, nullptr, "Dialect", "http://schemas.microsoft.com/win/2004/08/events/eventquery");
// Body/Bookmark
if (it != processor_.subscribers_.end() && it->second.bookmark_ != nullptr) {
WsXmlNodeH bookmark_node = ws_xml_get_doc_root(it->second.bookmark_);
ws_xml_copy_node(bookmark_node, subscribe_node);
} else if (processor_.initial_existing_events_strategy_ == INITIAL_EXISTING_EVENTS_STRATEGY_ALL) {
ws_xml_add_child(subscribe_node, XML_NS_WS_MAN, WSM_BOOKMARK, "http://schemas.dmtf.org/wbem/wsman/1/wsman/bookmark/earliest");
}
// Body/SendBookmarks
ws_xml_add_child(subscribe_node, XML_NS_WS_MAN, WSM_SENDBOOKMARKS, nullptr);
// Copy the whole Subscription
WsXmlNodeH subscription_node = ws_xml_get_doc_root(subscription_doc);
ws_xml_copy_node(subscription_node, subscription);
// Save subscription
if (it == processor_.subscribers_.end()) {
it = processor_.subscribers_.emplace(machine_id, SubscriberData()).first;
}
it->second.setSubscription(subscription_version, subscription_doc, subscription_endpoint, subscription_identifier);
}
// Send response
char* xml_buf = nullptr;
int xml_buf_size = 0;
ws_xml_dump_memory_enc(response, &xml_buf, &xml_buf_size, "UTF-8");
sendResponse(conn, machine_id, req_info->remote_addr, xml_buf, xml_buf_size);
ws_xml_free_memory(xml_buf);
return true;
}