| //---------------------------------------------------------------------------- |
| // |
| // Copyright (C) Intel Corporation, 2007. |
| // (C) Red Hat, Inc, 2015. |
| // |
| // File: OpenWsmanClient.cpp |
| // |
| // Contents: An implementation of the WsmanClient interface using openwsman |
| // |
| //---------------------------------------------------------------------------- |
| |
| #include "OpenWsmanClient.h" |
| |
| |
| extern "C" { |
| #include "u/libu.h" |
| #include "wsman-api.h" |
| } |
| |
| #include "wsman-client-transport.h" |
| |
| #define WSMAN_ENCODING "UTF-8" |
| |
| using namespace WsmanClientNamespace; |
| |
| static bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc); |
| static bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes); |
| static string XmlDocToString(WsXmlDocH& doc); |
| static client_opt_t *SetOptions(WsManClient* cl); |
| static string GetSubscribeContext(WsXmlDocH& doc); |
| static string ExtractPayload(WsXmlDocH& doc); |
| static string ExtractItems(WsXmlDocH& doc); |
| |
| // Construct from params. |
| |
| OpenWsmanClient::OpenWsmanClient( |
| const string &host, |
| const int port, |
| const string &path, |
| const string &scheme, |
| const string &auth_method, |
| const string &username, |
| const string &password, |
| // proxy address include proxy port |
| const string &proxy, |
| //proxy user name |
| const string &proxy_username, |
| //proxy password |
| const string &proxy_password |
| #ifdef _WIN32 |
| // determines which cert store to search |
| ,const bool local, |
| // search for a client cert with this name |
| const string &cert, |
| // search for a cient cert with this oid |
| const string &oid |
| #endif |
| ) |
| { |
| cl = wsmc_create( |
| host.c_str(), |
| port, |
| path.c_str(), |
| scheme.c_str(), |
| username.c_str(), |
| password.c_str()); |
| SetAuth(auth_method); |
| #ifdef _WIN32 |
| SetClientCert(oid, cert, local); |
| #endif |
| SetProxy(proxy.c_str(), proxy_username, proxy_password); |
| wsmc_transport_init(cl, (void*)NULL); |
| } |
| |
| // Destructor. |
| OpenWsmanClient::~OpenWsmanClient() |
| { |
| wsmc_transport_fini(cl); |
| wsmc_release(cl); |
| } |
| |
| string OpenWsmanClient::Identify() const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| |
| WsXmlDocH identifyResponse = wsmc_action_identify(cl, options); |
| CheckWsmanResponse(cl, identifyResponse); |
| string xml = ExtractPayload(identifyResponse); |
| ws_xml_destroy_doc(identifyResponse); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Create(const string &resourceUri, const string &data) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| |
| WsXmlDocH createResponse = wsmc_action_create_fromtext(cl, |
| resourceUri.c_str(), |
| options, |
| data.c_str(), data.length(), WSMAN_ENCODING); |
| CheckWsmanResponse(cl, createResponse); |
| string xml = ExtractPayload(createResponse); |
| ws_xml_destroy_doc(createResponse); |
| return xml; |
| } |
| |
| void OpenWsmanClient::Delete(const string &resourceUri, const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| WsXmlDocH deleteResponse = wsmc_action_delete(cl, |
| resourceUri.c_str(), |
| options); |
| CheckWsmanResponse(cl, deleteResponse); |
| ws_xml_destroy_doc(deleteResponse); |
| } |
| |
| void OpenWsmanClient::Enumerate( |
| const string &resourceUri, |
| vector<string> &enumRes, |
| const WsmanOptions &options, |
| const WsmanFilter &filter) const |
| { |
| WsXmlDocH doc; |
| char *enumContext; |
| WsXmlDocH enum_response = wsmc_action_enumerate(cl, (char *)resourceUri.c_str(), options, filter); |
| |
| if(ResourceNotFound(cl, enum_response)) |
| throw WsmanResourceNotFound(resourceUri.c_str()); |
| |
| enumContext = wsmc_get_enum_context(enum_response); |
| ws_xml_destroy_doc(enum_response); |
| |
| while (enumContext != NULL && enumContext[0] != 0 ) { |
| doc = wsmc_action_pull(cl, resourceUri.c_str(), options, NULL, enumContext); |
| CheckWsmanResponse(cl, doc); |
| string payload = ExtractItems(doc); |
| |
| if (payload.length() > 0) |
| enumRes.push_back(payload); |
| |
| wsmc_free_enum_context(enumContext); |
| enumContext = wsmc_get_enum_context(doc); |
| ws_xml_destroy_doc(doc); |
| } |
| |
| wsmc_free_enum_context(enumContext); |
| } |
| |
| void OpenWsmanClient::Enumerate( |
| const string &resourceUri, |
| vector<string> &enumRes, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| Enumerate(resourceUri, enumRes, options, WsmanFilter()); |
| } |
| |
| void OpenWsmanClient::Enumerate( |
| const string &resourceUri, |
| WsmanFilter &filter, |
| vector<string> &enumRes) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| |
| Enumerate(resourceUri, enumRes, options, filter); |
| } |
| |
| string OpenWsmanClient::Get( |
| const string &resourceUri, |
| const WsmanOptions &options) const |
| { |
| WsXmlDocH doc = wsmc_action_get(cl, (char *)resourceUri.c_str(), options); |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Get( |
| const string &resourceUri, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| return Get(resourceUri, options); |
| } |
| |
| string OpenWsmanClient::Put( |
| const string &resourceUri, |
| const string &content, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| WsXmlDocH doc = wsmc_action_put_fromtext( |
| cl, |
| resourceUri.c_str(), |
| options, |
| content.c_str(), |
| content.length(), |
| WSMAN_ENCODING); |
| |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Invoke( |
| const string &resourceUri, |
| const string &methodName, |
| const WsmanOptions &options) const |
| { |
| WsXmlDocH doc = wsmc_action_invoke( |
| cl, |
| resourceUri.c_str(), |
| options, |
| methodName.c_str(), |
| NULL); |
| |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Invoke( |
| const string &resourceUri, |
| const string &methodName, |
| const string &content, |
| const WsmanOptions &options) const |
| { |
| WsXmlDocH doc = wsmc_action_invoke_fromtext( |
| cl, |
| resourceUri.c_str(), |
| options, |
| const_cast<char*>(methodName.c_str()), |
| content.c_str(), |
| content.length(), |
| WSMAN_ENCODING); |
| |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Invoke( |
| const string &resourceUri, |
| const string &methodName, |
| const string &content, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| return Invoke(resourceUri, methodName, content, options); |
| } |
| |
| string OpenWsmanClient::Subscribe( |
| const string &resourceUri, |
| const SubscribeInfo &info, |
| string &subsContext) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.setDeliveryMode(static_cast<WsmanDeliveryMode>(info.delivery_mode)); |
| options.setDeliveryURI(info.delivery_uri); |
| |
| if (!info.refenceParam.empty()) |
| options.setReference(info.refenceParam); |
| |
| // Add selectors. |
| options.addSelectors(info.selectorset); |
| |
| options.setExpires(info.expires); |
| options.setHeartbeatInterval(info.heartbeat_interval); |
| |
| WsXmlDocH doc = wsmc_action_subscribe(cl, (char *)resourceUri.c_str(), options, NULL); |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| subsContext = GetSubscribeContext(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| string OpenWsmanClient::Renew( |
| const string &resourceUri, |
| const string &subsContext, |
| float expire, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.setExpires(expire); |
| options.addSelectors(s); |
| |
| WsXmlDocH doc = wsmc_action_renew( |
| cl, |
| resourceUri.c_str(), |
| options, |
| subsContext.c_str()); |
| |
| CheckWsmanResponse(cl, doc); |
| string xml = ExtractPayload(doc); |
| ws_xml_destroy_doc(doc); |
| return xml; |
| } |
| |
| void OpenWsmanClient::Unsubscribe( |
| const string &resourceUri, |
| const string &subsContext, |
| const NameValuePairs *s) const |
| { |
| WsmanOptions options; |
| options.setNamespace(GetNamespace()); |
| options.addSelectors(s); |
| |
| WsXmlDocH doc = wsmc_action_unsubscribe( |
| cl, |
| resourceUri.c_str(), |
| options, |
| subsContext.c_str()); |
| |
| CheckWsmanResponse(cl, doc); |
| ws_xml_destroy_doc(doc); |
| return; |
| } |
| |
| |
| string GetSubscribeContext(WsXmlDocH& doc) |
| { |
| string str; |
| char *buf = NULL; |
| WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); |
| WsXmlNodeH tmp = NULL; |
| if(bodyNode == NULL) return str; |
| bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE_RESP); |
| if(bodyNode == NULL) return str; |
| bodyNode = ws_xml_get_child(bodyNode, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIPTION_MANAGER); |
| if(bodyNode == NULL) return str; |
| tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS); |
| if(tmp == NULL) { |
| tmp = ws_xml_get_child(bodyNode, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PROPERTIES); |
| if(tmp == NULL) return str; |
| } |
| wsmc_node_to_buf(tmp, &buf); |
| str = string(buf); |
| u_free(buf); |
| return str; |
| } |
| |
| string ExtractPayload(WsXmlDocH& doc) |
| { |
| WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); |
| WsXmlNodeH payloadNode = ws_xml_get_child(bodyNode, 0, NULL, NULL); |
| char *buf = NULL; |
| wsmc_node_to_buf( payloadNode, &buf); |
| string payload = string(buf); |
| u_free(buf); |
| return payload; |
| } |
| |
| string ExtractItems(WsXmlDocH& doc) |
| { |
| string payload; |
| WsXmlNodeH bodyNode = ws_xml_get_soap_body(doc); |
| WsXmlNodeH pullResponse = ws_xml_get_child(bodyNode, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP); |
| WsXmlNodeH itemsNode = ws_xml_get_child(pullResponse, 0, XML_NS_ENUMERATION, WSENUM_ITEMS); |
| WsXmlNodeH n = ws_xml_get_child(itemsNode, 0 , NULL, NULL ); |
| if (n) { |
| char *buf = NULL; |
| wsmc_node_to_buf( n, &buf); |
| payload = string(buf); |
| u_free(buf); |
| } |
| return payload; |
| } |
| |
| string XmlDocToString(WsXmlDocH& doc) { |
| char *buf; |
| int len; |
| ws_xml_dump_memory_enc(doc, &buf, &len, WSMAN_ENCODING); |
| string str = string(buf); // This constructor copies the data. |
| if (buf) |
| #ifdef _WIN32 |
| ws_xml_free_memory(buf); |
| #else |
| u_free(buf); |
| #endif |
| return str; |
| } |
| |
| bool CheckWsmanResponse(WsManClient* cl, WsXmlDocH& doc) |
| { |
| long lastError = wsmc_get_last_error(cl); |
| string error; |
| |
| if(lastError) { |
| char tmp[10]; |
| error = "Failed to establish a connection with the server.\n"; |
| sprintf(tmp, "%ld", lastError); |
| error.append("Openwsman last error = ").append(tmp); |
| ws_xml_destroy_doc(doc); |
| throw WsmanClientException(error.c_str(), WSMAN_CONNECT_ERROR); |
| } |
| |
| long responseCode = wsmc_get_response_code(cl); |
| if (responseCode != 200 && |
| responseCode != 400 && |
| responseCode != 500) |
| { |
| char tmp[10]; |
| error = "An HTTP error occurred.\n"; |
| sprintf(tmp, "%ld", responseCode); |
| error.append("HTTP Error = ").append(tmp); |
| ws_xml_destroy_doc(doc); |
| throw WsmanClientException(error.c_str(), WSMAN_HTTP_ERROR); |
| } |
| |
| if(!doc) |
| throw WsmanClientException("The Wsman response was NULL."); |
| |
| if (wsmc_check_for_fault(doc)) { |
| char tmp[10]; |
| WsManFault *fault = wsmc_fault_new(); |
| wsmc_get_fault_data(doc, fault); |
| string subcode_s = fault->subcode ? string(fault->subcode) : ""; |
| string code_s = fault->code ? string(fault->code) : ""; |
| string reason_s = fault->reason ? string(fault->reason) : ""; |
| string detail_s = fault->fault_detail ? string(fault->fault_detail) : ""; |
| ws_xml_destroy_doc(doc); |
| wsmc_fault_destroy(fault); |
| error = "A Soap Fault was received:"; |
| error.append("\nFaultCode: " + code_s); |
| error.append("\nFaultSubCode: " + subcode_s); |
| error.append("\nFaultReason: " + reason_s); |
| error.append("\nFaultDetail: " + detail_s); |
| sprintf(tmp, "%ld", responseCode); |
| error.append("\nHttpCode: = ").append(tmp); |
| throw WsmanSoapFault(error.c_str(), code_s, subcode_s, reason_s, detail_s); |
| } |
| |
| return true; |
| } |
| |
| bool ResourceNotFound(WsManClient* cl, WsXmlDocH& enumerationRes) |
| { |
| long responseCode = wsmc_get_response_code(cl); |
| if(wsmc_get_last_error(cl) || |
| (responseCode != 200 && responseCode != 400 && responseCode != 500) || |
| !enumerationRes) |
| { |
| CheckWsmanResponse(cl, enumerationRes); |
| } |
| |
| if (!wsmc_check_for_fault(enumerationRes)) |
| return false; |
| |
| WsManFault *fault = wsmc_fault_new(); |
| bool ret = false; |
| wsmc_get_fault_data(enumerationRes, fault); |
| string subcode_s = fault->subcode ? string(fault->subcode) : ""; |
| if(subcode_s.find("DestinationUnreachable") != string::npos) { |
| wsmc_fault_destroy(fault); |
| return true; |
| } |
| |
| wsmc_fault_destroy(fault); |
| if(!ret) |
| CheckWsmanResponse(cl, enumerationRes); |
| |
| return ret; |
| } |
| |
| void OpenWsmanClient::SetAuth(const string &auth_method) |
| { |
| if (auth_method.empty()) |
| return; |
| |
| wsman_transport_set_auth_method(cl, auth_method.c_str()); |
| if (wsmc_transport_get_auth_value(cl) == WS_MAX_AUTH ) { |
| // Authentication method not supported, reverting to digest |
| wsman_transport_set_auth_method(cl, "digest"); |
| } |
| } |
| void OpenWsmanClient::SetTimeout(unsigned long mtime) |
| { |
| wsman_transport_set_timeout(cl,mtime); |
| } |
| |
| void OpenWsmanClient::SetUserName(const string &user_name) |
| { |
| if (user_name.empty()) |
| return; |
| |
| wsman_transport_set_userName(cl, user_name.c_str()); |
| } |
| |
| void OpenWsmanClient::SetPassword(const string &password) |
| { |
| if (password.empty()) |
| return; |
| |
| wsman_transport_set_password(cl, password.c_str()); |
| } |
| |
| void OpenWsmanClient::SetEncoding(const string &encoding) |
| { |
| if (encoding.empty()) |
| return; |
| |
| wsmc_set_encoding(cl, encoding.c_str()); |
| } |
| |
| void OpenWsmanClient::SetNamespace(const string &ns) |
| { |
| if (ns.empty()) |
| return; |
| |
| wsmc_set_namespace(cl, ns.c_str()); |
| } |
| |
| void OpenWsmanClient::SetProxy( |
| const string &proxy, |
| const string &proxy_username, |
| const string &proxy_password) |
| { |
| if (!proxy.empty()) |
| wsman_transport_set_proxy(cl, proxy.c_str()); |
| |
| if (!proxy_username.empty()) |
| wsman_transport_set_proxy_username(cl, proxy_username.c_str()); |
| |
| if (!proxy_password.empty()) |
| wsman_transport_set_proxy_password(cl, proxy_password.c_str()); |
| } |
| |
| #ifdef _WIN32 |
| void OpenWsmanClient::SetClientCert( |
| const string &caOid, |
| const string &caName, |
| const bool localCert) |
| { |
| if (!caOid.empty()) |
| wsman_transport_set_caoid(cl, caOid.c_str()); |
| |
| if (!caName.empty()) |
| wsman_transport_set_cainfo(cl, caName.c_str()); |
| |
| wsman_transport_set_calocal(cl, localCert); |
| } |
| |
| |
| #else |
| // Set server certificate params |
| // params: cainfo - string naming a file holding one or more certificates to verify the peer with. |
| // capath - string naming a dierctory holding multiple CA certificates to verify the peer with. |
| // Give empty strings if you want curl to search for certificates inthe default path |
| void OpenWsmanClient::SetServerCert( |
| const string &cainfo, |
| const string &capath) |
| { |
| // This means curl verifies the server certificate |
| wsman_transport_set_verify_peer(cl, 1); |
| |
| // This means the certificate must indicate that the server is the server to which you meant to connect. |
| wsman_transport_set_verify_host(cl, 2); |
| |
| if (!cainfo.empty()) |
| wsman_transport_set_cainfo(cl, cainfo.c_str()); |
| |
| if (!capath.empty()) |
| wsman_transport_set_capath(cl, capath.c_str()); |
| } |
| |
| // Set client certificates params |
| // params: cert - file name of your certificate. |
| // key - file name of your private key. |
| void OpenWsmanClient::SetClientCert( |
| const string &cert, |
| const string &key) |
| { |
| if (!cert.empty()) |
| wsman_transport_set_cert(cl, cert.c_str()); |
| |
| if (!key.empty()) |
| wsman_transport_set_key(cl, key.c_str()); |
| } |
| #endif |
| |
| string OpenWsmanClient::GetNamespace() const |
| { |
| char *ns = wsmc_get_namespace(cl); |
| return ns ? string(ns) : string(); |
| } |